プラグインなし!目次を実装する方法。|WordPress

WordPressで、プラグインを使わずに目次を実装する方法をご紹介します。

JQueryを使わない方法で、本サイトでも導入している実装方法になります。

時間もかからず工数も少ないので、宜しければご参考にされてください。

次の手順で実装していきます。

  1. functions.phpの編集
  2. CSSの編集
  3. 外観→カスタマイズ画面で表示条件の設定
  4. 個別記事内で表示・非表示の調整

functions.phpの編集

functions.phpの編集を行います。

子テーマが利用できる環境であれば子テーマのfunctions.phpを利用してください。

各コードの説明書きはそれぞれコード上部に記載していますので、参考にされてください。

※必ずバックアップをとってから編集してください。

//////////////////////////////////////////////////
//Original sanitize_callback
//////////////////////////////////////////////////
// CheckBox
function fit_sanitize_checkbox( $checked ) {
    return ( ( isset( $checked ) && true == $checked ) ? true : false );
}
// radio/select
function fit_sanitize_select( $input, $setting ) {
	$input = sanitize_key( $input );
    $choices = $setting->manager->get_control($setting->id)->choices;
    return ( array_key_exists( $input, $choices ) ? $input : $setting->default );
}
// number limit
function fit_sanitize_number_range( $number, $setting ) {
    $number = absint( $number );
    $atts = $setting->manager->get_control( $setting->id )->input_attrs;
    $min = ( isset( $atts['min'] ) ? $atts['min'] : $number );
    $max = ( isset( $atts['max'] ) ? $atts['max'] : $number );
    $step = ( isset( $atts['step'] ) ? $atts['step'] : 1 );
    return ( $min <= $number && $number <= $max && is_int( $number / $step ) ? $number : $setting->default );
}


  
//////////////////////////////////////////////////
//投稿ページ各種設定画面
//////////////////////////////////////////////////
function fit_post_cutomizer( $wp_customize ) {
// セクション
	$wp_customize->add_section( 'fit_post_section', array(
		'title'     => '投稿ページ設定',
		'priority'  => 1,
	));
  
	
	
	
	// 目次の表示/非表示 セッティング
	$wp_customize->add_setting( 'fit_post_outline', array(
		'default'   => 'value1',
		'type' => 'option',
		'sanitize_callback' => 'fit_sanitize_select',
	));
	// 目次の表示/非表示 コントロール
	$wp_customize->add_control( 'fit_post_outline', array(
		'section'   => 'fit_post_section',
		'settings'  => 'fit_post_outline',
		'label'     => '■目次の表示/非表示',
		'description' => '投稿ページに目次を表示するか選択<br>
		(記事内の最初のhタグの手前に自動で挿入されます。※
		ショートコードで好きな位置に表示可能)',
		'type'      => 'select',
		'choices'   => array(
			'value1' => '表示する(default)',
			'value2' => '表示しない',
		),
	));
	
	// 目次を表示するための最小見出し数 セッティング
	$wp_customize->add_setting( 'fit_post_outline_number', array(
		'default'   => '1',
		'type' => 'option',
		'sanitize_callback' => 'fit_sanitize_number_range',
	));
	// 目次を表示するための最小見出し数 コントロール
	$wp_customize->add_control( 'fit_post_outline_number', array(
		'section'   => 'fit_post_section',
		'settings'  => 'fit_post_outline_number',
		'description' => '目次を表示するための最小見出し数を指定',
		'type'      => 'number',
		'input_attrs' => array(
        	'step'     => '1',
        	'min'      => '1',
        	'max'      => '50',
    	),
	));

	// 目次パネルデフォルト設定 セッティング
	$wp_customize->add_setting('fit_post_outline_close', array( 
		'type' => 'option',
		'sanitize_callback' => 'fit_sanitize_checkbox',
    ));
	// 目次パネルデフォルト設定 コントロール
	$wp_customize->add_control('fit_post_outline_close', array( 
        'section' => 'fit_post_section', 
        'settings' => 'fit_post_outline_close', 
        'label'     => '目次パネルをデフォルトで閉じておく',
        'type'      => 'checkbox',
    ));
	
	
	

}
add_action( 'customize_register', 'fit_post_cutomizer' );


//////////////////////////////////////////////////
//目次の表示/非表示、個別選択設定
//////////////////////////////////////////////////
if ( get_option('fit_post_outline') != 'value2') {
	function add_outline_fields() {
		//add_meta_box(表示される入力ボックスのHTMLのID, ラベル, 表示する内容を作成する関数名, 投稿タイプ, 表示方法)
		add_meta_box( 'outline_setting', '目次の個別非表示設定', 'insert_outline_fields', 'post', 'normal');
	}
	add_action('admin_menu', 'add_outline_fields');
 
 
	// カスタムフィールドの入力エリア
	function insert_outline_fields() {
		global $post;
	
		if( get_post_meta($post->ID,'outline_none',true) == "1" ) {
			$outline_none_check = "checked";
		}else {
			$outline_none_check = "";
		}
	
		echo '
			<div style="margin:20px 0; overflow: hidden; line-height:2;">
		  	<div style="float:left;width:120px;">目次の表示設定</div>
		  	<div style="float:right;width:calc(100% - 140px);">
		    	<input type="checkbox" name="outline_none" value="1" '.$outline_none_check.' >:この投稿では目次を非表示にしますか?
		  	</div>
		  	<div style="clear:both;"></div>
			</div>
		';
	
	}

	// カスタムフィールドの値を保存
	function save_outline_fields( $post_id ) {
		if(!empty($_POST['outline_none'])){
			update_post_meta($post_id, 'outline_none', $_POST['outline_none'] );
		}else{
			delete_post_meta($post_id, 'outline_none');
		}

	}
	add_action('save_post', 'save_outline_fields');
}


//////////////////////////////////////////////////
//オリジナル目次を作成
//////////////////////////////////////////////////
function get_outline_info($content) {
	// 目次のHTMLを入れる変数を定義します。
	$outline = '';
	// h1?h6タグの個数を入れる変数を定義します。
	$counter = 0;
    // 記事内のh1?h6タグを検索します。(idやclass属性も含むように改良)
    if (preg_match_all('/<h([1-4])[^>]*>(.*?)<\/h\1>/', $content, $matches,  PREG_SET_ORDER)) {
    	   // 記事内で使われているh1?h6タグの中の、1?6の中の一番小さな数字を取得します。
    	   // ※以降ソースの中にある、levelという単語は1?6のことを表します。
        $min_level = min(array_map(function($m) { return $m[1]; }, $matches));
        // スタート時のlevelを決定します。
        // ※このレベルが上がる毎に、<ul></li>タグが追加されていきます。
        $current_level = $min_level - 1;
        // 各レベルの出現数を格納する配列を定義します。
        $sub_levels = array('1' => 0, '2' => 0, '3' => 0, '4' => 0);
        // 記事内で見つかった、hタグの数だけループします。
        foreach ($matches as $m) {
            $level = $m[1];  // 見つかったhタグのlevelを取得します。
            $text = $m[2];  // 見つかったhタグの、タグの中身を取得します。
            // li, ulタグを閉じる処理です。2ループ目以降に中に入る可能性があります。
            // 例えば、前回処理したのがh3タグで、今回出現したのがh2タグの場合、
            // h3タグ用のulを閉じて、h2タグに備えます。
            while ($current_level > $level) {
                $current_level--;
                $outline .= '</li></ul>';
            }
            // 同じlevelの場合、liタグを閉じ、新しく開きます。
            if ($current_level == $level) {
                $outline .= '</li><li class="outline__item">';
            } else {
                // 同じlevelでない場合は、ul, liタグを追加していきます。
                // 例えば、前回処理したのがh2タグで、今回出現したのがh3タグの場合、
                // h3タグのためにulを追加します。
                while ($current_level < $level) {
                    $current_level++;
                    $outline .= sprintf('<ul class="outline__list outline__list-%s"><li class="outline__item">', $current_level);
                }
                // 見出しのレベルが変わった場合は、現在のレベル以下の出現回数をリセットします。
                for ($idx = $current_level + 0; $idx < count($sub_levels); $idx++) {
                    $sub_levels[$idx] = 0;
                }
            }
            // 各レベルの出現数を格納する配列を更新します。
            $sub_levels[$current_level]++;
            // 現在処理中のhタグの、パスを入れる配列を定義します。
            // 例えば、h2 -> h3 -> h3タグと進んでいる場合は、
            // level_fullpathはarray(1, 2)のようになります。
            // ※level_fullpath[0]の1は、1番目のh2タグの直下に入っていることを表します。
            // ※level_fullpath[1]の2は、2番目のh3を表します。
            $level_fullpath = array();
            for ($idx = $min_level; $idx <= $level; $idx++) {
                $level_fullpath[] = $sub_levels[$idx];
            }
            $target_anchor = 'outline__' . implode('_', $level_fullpath);

            // 目次に、<a href="#outline_1_2">1.2 見出し</a>のような形式で見出しを追加します。
            $outline .= sprintf('<a class="outline__link" href="#%s"><span class="outline__number" style="display:none;">%s.</span> %s</a>', $target_anchor, implode('.', $level_fullpath), strip_tags($text));
            // 本文中の見出し本体を、<h3>見出し</h3>を<h3 id="outline_1_2">見出し</h3>
            // のような形式で置き換えます。
            $hid = preg_replace('/<h([1-6])/', '<h\1 id="' .$target_anchor . '"', $m[0]);
            $content = str_replace($m[0], $hid, $content);
			
        }
        // hタグのループが終了後、閉じられていないulタグを閉じていきます。
        while ($current_level >= $min_level) {
            $outline .= '</li></ul>';
            $current_level--;
        }
        // h1?h6タグの個数
        $counter = count($matches);
    }
    return array('content' => $content, 'outline' => $outline, 'count' => $counter);
}

//目次を作成します。
function add_outline($content) {

    // 目次を表示するために必要な見出しの数
	if(get_option('fit_post_outline_number')){
		$number = get_option('fit_post_outline_number');
	}else{
		$number = 1;
	}
    // 目次関連の情報を取得します。
    $outline_info = get_outline_info($content);
    $content = $outline_info['content'];
    $outline = $outline_info['outline'];
    $count = $outline_info['count'];
	if (get_option('fit_post_outline_close') ) {
		$close = "";
	}else{
		$close = "checked";
	}
    if ($outline != '' && $count >= $number) {
        // 目次を装飾します。
        $decorated_outline = sprintf('
		<div class="outline">
		  <span class="outline__title">目次</span>
		  <input class="outline__toggle" id="outline__toggle" type="checkbox" '.$close.'>
		  <label class="outline__switch" for="outline__toggle"></label>
		  %s
		</div>', $outline);
        // カスタマイザーで目次を非表示にする以外が選択された時&個別非表示が1以外の時に目次を追加します。
		if ( get_option('fit_post_outline') != 'value2' && get_post_meta(get_the_ID(), 'outline_none', true) != '1' && is_single() ) {
        	$shortcode_outline = '
		';
        	if (strpos($content, $shortcode_outline) !== false) {
            	// 記事内にショートコードがある場合、ショートコードを目次で置換します。
            	$content = str_replace($shortcode_outline, $decorated_outline, $content);
        	} else if (preg_match('/<h[1-6].*>/', $content, $matches, PREG_OFFSET_CAPTURE)) {
            	// 最初のhタグの前に目次を追加します。
            	$pos = $matches[0][1];
            	$content = substr($content, 0, $pos) . $decorated_outline . substr($content, $pos);
        	}
		}
    }
	return $content;
}
add_filter('the_content', 'add_outline');

function override_mce_options( $init_array ) {
    global $allowedposttags;

    $init_array['valid_elements']          = '*[*]';
    $init_array['extended_valid_elements'] = '*[*]';
    $init_array['valid_children']          = '+a[' . implode( '|', array_keys( $allowedposttags ) ) . ']';
    $init_array['indent']                  = true;
    $init_array['wpautop']                 = false;

    return $init_array;
}

add_filter( 'tiny_mce_before_init', 'override_mce_options' );

CSSコードの編集

CSSの調整を行います。

CSSコードは以下になります。

style.cssなど任意のスタイルシートに丸ごとコピペしてください。

/*目次*/
.outline{
	border:1px dotted #D8D8D8;
	padding:20px;
	margin-top:20px;
	display:inline-block;
	font-size:0.9em;
	line-height:1.5em;
}
.outline__toggle{display: none;}
.outline__switch::before{
	content:"開く";
	cursor:pointer;
	border: solid 1px #D8D8D8;
	padding:5px;
	font-size:0.8rem;
	margin-left:5px;
	border-radius: 5px;
}
.outline__toggle:checked + .outline__switch::before{content:"閉じる"}
.outline__switch + .outline__list{
	overflow:hidden;
	width:0;
	height:0;
	margin-top:0;
	margin-left:-20px;
	transition: 0.2s;
}

.outline__toggle:checked + .outline__switch + .outline__list {
    width: auto;
    height: auto;
    margin-top: 20px;
    transition: 0.2s;
    border-top: dotted 1px #d2d2d2;
    padding-top: 1em;
}
.outline__item:before {content: normal;}
.outline__link{
	display:relative;
	color:#191919 !important;
}
.outline__link:hover{border:none;}
.outline__number{
	display: inline-block;
	color:#7F7F7F;
	background:#F2F2F2;
	padding:3px 6px;
	font-weight:400;
	font-size:1.2rem;
	margin-right: 5px;
}
label.outline__switch {
    position: relative;
    float: right;
}
li .outline__item{
list-style-type:none!important;
}
li .outline__item:before{
content:'- ';
}
ul .outline__item{
	list-style-type:none!important;
}
ul{
		-webkit-padding-start: 1.2em;
}

CSSをカスタマイズすることで任意のデザインに変更可能です。

CSSの編集が完了したら、テーマで使用しているCSSに保存してください。

設定については以上で完了です。

外観→カスタマイズ画面で表示条件の設定

「外観」→「カスタマイズ」→「投稿ページ設定」に進みます。

投稿ページで目次を表示するか選択

標準で目次を表示するかしないかです。

この項目は基本的に「表示」でよいと思います。

たまにしか目次が必要ではないという場合は「非表示」でよいと思います。

目次を表示するための最小見出し数を設定

見出しの数が何個あったら目次を表示するかです。

3~5くらいが標準的な数だと思います。仮に3にした場合は1個か2個しか見出しがないときは目次は生成されません。

当サイトでは2に設定しています。

目次パネルをデフォルトで閉じておく

目次欄をデフォルトで最初から閉じた状態にするかです。

この項目はチェックをしない状態でよいと思います。

個別記事内で表示・非表示の調整

基本的に操作することはほとんどないのですが、見出しの数が多く標準で目次が表示されてしまうものの投稿内のデザイン・見た目の関係上非表示にしたいことがあります。

そういう場合は個別記事内にチェックボックスがありますのでチェックを入れてください。

まとめ

今回はプラグインを使わずにWordPressに「目次を実装する方法」をご紹介しました。

作業自体は時間もかからず、すぐに実装できますので宜しければ参考にされてください。

最後までご覧いただきありがとうございました。

Web Wordpress コード プラグインなし

プラグインなし!内部・外部リンク対応のブログカードを表示する方法。|WordPress

WordPressで、プラグインを使わずにブログカードを表示する方法をご紹介致します。 プラグイン不使用には、サーバー負荷の軽減やサイト表示速度の保持など様々なメリットがあります。 WordPress...

続きを見る

植物

Copiapoa cinerea var. cinerea コピアポア シネレア 黒王丸

黒王丸 コピアポア・シネレア Copiapoa cinerea は、「白サボテン」と呼ばれ日本で最も人気の高いサボテンと言っても過言ではありません。 肌が特に白く、真っ黒のトゲの個体は高値で取引されて...

続きを見る

Web Wordpress コード プラグインなし

プラグインなし!コピペで3分超簡単!ダークモードの実装方法。WordPress

ダークモードをWordPressに実装します。プラグインは必要ありません。 1. 1.JavaScriptの記述2. 2.Cssの記述3. 3.HTMLの記述 1.JavaScriptの記述 ヘッダー...

続きを見る

CDN Web スピード セキュリティ

CloudflareでCDN配信してもAdSense収益が減ることはない?各種設定方法。

1. Adsenseの影響について2. 原因は個々のIPがCloudflareを通すことで区別がつかなくなっていること(Cloudflareを通すと全て同じIPになる)3. Nginxで個別のIPを区...

続きを見る

Web スピード

Webサイトの表示速度を加速させる画像圧縮Webツール。

Webサイトの表示速度を向上させるためには、いくつか方法がありますが、まずは画像のサイズを最適化することが効果的です。 その場合は下記のような画像圧縮Webツールを利用することをおすすめします。 メリ...

続きを見る

Web Woocommerce Wordpress プラグイン

WordPressのユーザー情報をCSVエクスポート、インポートするプラグイン

「Import and export users and customers」というプラグインを利用します。 とにかくシンプルにユーザー情報をCSVでダウンロードできればいい、という方にお勧めです。 ...

続きを見る

Web Wordpress スピード

WordPressでページ速度を最適化する方法。WordPress

Webページが最初の2秒以内に読み込まれないと、モバイルユーザーの55%がそのWebページを離脱してしまいます。 さらに、オンラインストアでは消費者の約70%がページ表示の速度が商品を購入するための意...

続きを見る

Web YouTube コード プラグインなし

CSSでYouTubeの埋め込みを比率維持したままレスポンシブ対応させる方法。

YouTubeの埋め込みを比率維持したままレスポンシブ対応させる方法をご紹介します。 1. 手順1:divタグ追加2. 手順2:css追加3. 完成 手順1:divタグ追加 iframeタグを囲うよう...

続きを見る

コード

サーバー内でzipファイルを解凍する方法

解凍したいファイルを「example.zip」とします。 1. 1:解凍したいzipファイルをアップロード2. 2:unzip.phpの作成・アップロード3. 2:unzip.phpにアクセス4. 3...

続きを見る

植物 育て方

ポイントは「日・風・水・土」!多肉植物の育て方。

多肉植物の育て方は他の植物に比べとても簡単です。 ポイントはシンプルに4つです。 日当たりの良い場所で管理 風通しの良い場所で管理 水は土が乾いたら与える 水はけの良い土に植える 上記4つのポイントさ...

続きを見る

コメントを残す

本サイトは、皆様に快適な閲覧をご提供させていただくためにcookieを使用しています。cookieの使用に同意しますか?