wordpressで目次の出し分けを設定する方法

この記事を読むのにかかる時間 1未満

Cocoonには目次の自動生成機能があるが、記事構造によっては不要なケースもある。
投稿ごとに目次の表示有無を制御するには、表示ロジックに条件分岐を加える必要があるため、テーマの挙動を安全かつ再利用可能な形で拡張できるfunction.php に記述するのが適切である。

コード

必要な構成は4つ
・add_toc_meta_box():目次制御用の機能の概要
・toc_meta_box_callback:制御画面の見え方
・save_toc_meta_box:設定の保存制御
・control_toc_display():チェックボックスをチェックした時のページの見え方の制御

// 目次表示を投稿ごとに選択式にする機能
function add_toc_meta_box()
{
  add_meta_box(
    'toc_settings',        // メタボックスID
    '目次設定',            // メタボックスのタイトル
    'toc_meta_box_callback', // コールバック関数
    'post',                // 投稿タイプ
    'side',                // 表示位置(サイドバー)
    'default'              // 優先度
  );
}
// 管理画面でメタボックスを追加するタイミング
add_action('add_meta_boxes', 'add_toc_meta_box');

// 目次設定のメタボックス表示
function toc_meta_box_callback($post)
{
  // セキュリティ用のnonceフィールドを生成(CSRF攻撃防止)
  // 第一パラメータ;アクション名(機能名)、第二パラメータ:フィールド名(nameに当たる部分)
  wp_nonce_field('toc_meta_box_nonce', 'toc_meta_box_nonce');

  // 現在の投稿から目次表示設定の値を取得。falseだと配列が返ってくるのでtrueにする
  $value = get_post_meta($post->ID, '_show_toc', true);

  // 値が'no'の場合はチェックボックスを未チェック、それ以外はチェック状態にする
  $checked = ($value === 'no') ? '' : 'checked';

  // 目次表示設定のチェックボックスを出力
  echo '<label><input type="checkbox" name="show_toc" value="yes" ' . $checked . '> 目次を表示する</label>';

  // ユーザーへの説明文を表示
  echo '<p>チェックを外すとこの投稿で目次が非表示になります。</p>';
}

// 目次設定の保存
function save_toc_meta_box($post_id)
{
  // セキュリティチェック:nonceトークンが正しく送信されているか確認
  // 偽のフォーム送信やCSRF攻撃を防ぐため
  // wp_verify_nonce(送信されたトークン, アクション名)
  if (!isset($_POST['toc_meta_box_nonce']) || !wp_verify_nonce($_POST['toc_meta_box_nonce'], 'toc_meta_box_nonce')) {
    return; // セキュリティチェック失敗時は処理を中断
  }

  // 自動保存時は処理をスキップ(ユーザーの明示的な保存操作のみ対象)
  if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
    return; // 自動保存中は処理しない
  }

  // ユーザーに投稿編集権限があるかチェック
  if (!current_user_can('edit_post', $post_id)) {
    return; // 権限がない場合は処理を中断
  }

  // チェックボックスの状態を判定:チェックされていれば'yes'、外れていれば'no'
  $show_toc = isset($_POST['show_toc']) ? 'yes' : 'no';

  // 投稿のメタデータとして目次表示設定を保存
  update_post_meta($post_id, '_show_toc', $show_toc);
}

// 目次の表示/非表示を制御(フロントエンドで実際に動作する関数)
function control_toc_display()
{
  // 個別投稿ページ(記事の詳細ページ)でのみ動作
  if (is_single()) {
    // WordPressのグローバル変数から現在の投稿情報を取得
    global $post;

    // この投稿の目次表示設定を読み込み(管理画面で設定した値)
    $show_toc = get_post_meta($post->ID, '_show_toc', true);

    // デフォルトは表示('no'が設定されている場合のみ非表示)
    if ($show_toc === 'no') {
      // 方法1: Cocoonテーマの目次機能を無効化(テーマレベルでの制御)
      add_filter('is_toc_visible', '__return_false');

      // 方法2: CSSで目次を強制非表示(見た目レベルでの制御)
      // 複数の目次要素を対象にして確実に非表示にする
      add_action('wp_head', function () {
        echo '<style>.toc, .toc-widget, .toc-wrap, [class*="toc"] { display: none !important; }</style>';
      });
    }
  }
}

// WordPressの初期化時にこの関数を実行するよう登録
// 'wp'フックは、WordPressが投稿情報を読み込んだ後に実行される
add_action('wp', 'control_toc_display');

CSRF攻撃

wp_nonce_field(‘toc_meta_box_nonce’, ‘toc_meta_box_nonce’);など、設定がない場合に致命的になるため注意する。

  • ・他のサイトから勝手に設定を変更される
  • ・悪意のあるスクリプトで無断操作される
  • ・ユーザーが意図しない設定変更が行われる