本文内の見出し(H1~H6)を階層配列として保存する方法【WordPress】

作成日:

WordPressで本文に表示する目次用にH1~H6の見出しを一旦階層を持つ配列にして保存しておく方法を熟考しました。

まずは本文中から見出しを取得して、一時的に配列に保存しておきます。

PHP
$content     = get_the_content();
$heading_ary = array();
$paged_ary   = explode( '<!--nextpage-->', $post->post_content );
$i           = 1;
foreach ( $paged_ary as $page_content ) {
	if ( preg_match_all( '/^<h([1-6])(.*?)>(.*?)<\/h([1-6])>/im', $page_content, $search, PREG_SET_ORDER ) ) {
		if ( $search ) {
			foreach ( $search as $val ) {
				$label               = wp_strip_all_tags( $val[3], true );
				$element             = (int)$val[1];
				$ary                 = array(
					'element' => $element,
					'label'   => $label,
				);
				$heading_ary[ $i ][] = $ary;
				$content             = str_replace( $val[0], '<h' . $element . $val[2] . ' id="' . $label . '">' . $val[3] . '</h' . $element . '>', $content );
			}
		}
		$i++;
	}
}
global $g_heading_list;
$g_heading_list = $heading_ary;

コード解説

  1. まずは本文を取得しておきます。
    PHP [1]
    $content     = get_the_content();
    
  2. 次にページ分割毎に未処理(生データ?)の本文情報を配列として取得します。
    PHP [3]
    $paged_ary   = explode( '<!--nextpage-->', $post->post_content );
    
  3. 各ページごとにH1~H6までの見出しを取得して、$label(HTMLタグを除いた見出しテキスト)と$element(見出し級数)を配列にして保存します。
    PHP [8-14]
    			foreach ( $search as $val ) {
    				$label               = wp_strip_all_tags( $val[3], true );
    				$element             = (int)$val[1];
    				$ary                 = array(
    					'element' => $element,
    					'label'   => $label,
    				);
    
  4. $contentの方も各見出しにアンカーリンク用のIDプロパティ$labelを追加しておきます。
    PHP [16]
    				$content             = str_replace( $val[0], '<h' . $element . $val[2] . ' id="' . $label . '">' . $val[3] . '</h' . $element . '>', $content );
    
  5. ショートコードで使うことを想定して、一旦グローバル変数に格納しておきます。
    PHP [22-23]
    global $g_heading_list;
    $g_heading_list = $heading_ary;
    

この状態で仮に以下のような本文であれば、

HTML
<h2>はじめに</h2>
...
<h2>目的</h2>
...
<h2>内容</h2>
...
<h3>環境調査</h3>
...
<h3>屋内実験</h3>
...
<!--nextpage-->
<h2>結果</h2>
...
<!--nextpage-->
<h2>参考文献</h2>
...

見出し配列は、

PHP
Array
(
    [1] => Array
        (
            [0] => Array
                (
                    [element] => 2
                    [label] => はじめに
                )
            [1] => Array
                (
                    [element] => 2
                    [label] => 目的
                )
            [2] => Array
                (
                    [element] => 2
                    [label] => 内容
                )
            [3] => Array
                (
                    [element] => 3
                    [label] => 環境調査
                )
            [4] => Array
                (
                    [element] => 3
                    [label] => 屋内実験
                )
        )
    [2] => Array
        (
            [0] => Array
                (
                    [element] => 2
                    [label] => 結果
                )

        )

    [3] => Array
        (
            [0] => Array
                (
                    [element] => 2
                    [label] => 参考文献
                )
        )
)

のように取得出来ます。
この時点ではまだ各見出し要素同士が階層に別れていないので、もう一つ作業を追加します。

PHP
global $g_heading_list;
$i           = 1;
$top_element = $g_heading_list[1][0]['element'];
foreach ( $g_heading_list as $index ) {
	$page_list   = array();
	$index       = array_reverse( $index, true );
	$pre_ary     = array();
	$pre_element = '' ;
	foreach ( $index as $val ) {
		$element = $val['element'];
		$label   = $val['label'];
		$key     = array(
			'label' => $label,
			'child' => array(),
		);
		if ( $top_element === $element ) {
			if ( $pre_ary ) {
				$key['child'] = $pre_ary;
				$pre_ary      = array();
			}
			array_unshift( $page_list, $key );
		} else {
			if ( ! $pre_element || $pre_element === $element ) {
				array_unshift( $pre_ary, $key );
			} elseif ( $pre_element > $element ) {
				$key['child'] = $pre_ary;
				$pre_ary      = array();
				array_unshift( $pre_ary, $key );
			}
		}
		$pre_element = $element;
	}
	$list[ $i ] = $page_list;
	$i++;
}

コード解説解説

  1. まず目次配列を保存しているグローバル変数を呼び出します。
    PHP [1]
    global $g_heading_list;
    
  2. 目次配列の一番上の見出し要素の級数を取得して、これを基準とします。
    PHP [3]
    $top_element = $g_heading_list[1][0]['element'];
    
  3. ページ毎に配列を回します。
    PHP [4]
    foreach ( $g_heading_list as $index ) {
    
  4. 一番最後から順に階層に分けるために、配列を逆にします。
    PHP [6]
    	$index       = array_reverse( $index, true );
    
  5. 見出し要素から見出しテキストを取り出して読み込む用の配列にします。
    PHP [12-15]
    		$key     = array(
    			'label' => $label,
    			'child' => array(),
    		);
    
  6. 最上位級数と同階層であるか、前の処理時の階層かに応じて、子階層に相当するならば$key'child'に格納します。
    PHP [17-20]
    			if ( $pre_ary ) {
    				$key['child'] = $pre_ary;
    				$pre_ary      = array();
    			}
    
  7. 最終的に$list配列に格納します。
    PHP [33]
    	$list[ $i ] = $page_list;
    

これで以下のような階層付きの配列を取得することが出来ました。

PHP
Array
(
    [1] => Array
        (
            [0] => Array
                (
                    [label] => はじめに
                    [child] => Array
                        (
                        )
                )
            [1] => Array
                (
                    [label] => 目的
                    [child] => Array
                        (
                        )
                )
            [2] => Array
                (
                    [label] => 内容
                    [child] => Array
                        (
                            [0] => Array
                                (
                                    [label] => 環境調査
                                    [child] => Array
                                        (
                                        )
                                )
                            [1] => Array
                                (
                                    [label] => 屋内実験
                                    [child] => Array
                                        (
                                        )
                                )
                        )
                )
        )
    [2] => Array
        (
            [0] => Array
                (
                    [label] => 結果
                    [child] => Array
                        (
                        )
                )
        )
    [3] => Array
        (
            [0] => Array
                (
                    [label] => 参考文献
                    [child] => Array
                        (
                        )
                )
        )
)

解説はかなり適当に端折ってます。

物草 灸太郎
物草 灸太郎

WordPressでホームページを制作しつつ、休日は畑を耕したりDIYを楽しんでいます。

Loading...

コメントをどうぞ

  • メールアドレスが公開されることはありません。
  • コメント欄にURLは入力できません。
  • このサイトはreCAPTCHAによって保護されており、Googleのプライバシーポリシー利用規約が適用されます。