パンくずリストは、訪問者に現在地を示しサイト構造を伝えるナビゲーションです。この記事では、プラグインを使わずに functions.php の関数だけでパンくずリストを実装する方法を解説します。
自作の前に:テーマ内蔵の確認を
Cocoon をはじめ多くのテーマにはパンくずリスト機能が内蔵されています(Cocoonは設定から表示位置を選ぶだけ・構造化データも自動出力)。Yoast SEO などのプラグインにも同機能があります。テーマ内蔵 → プラグイン → 自作の順で検討し、細かい制御が必要な場合に自作を選ぶのがおすすめです。
Cocoon をはじめ多くのテーマにはパンくずリスト機能が内蔵されています(Cocoonは設定から表示位置を選ぶだけ・構造化データも自動出力)。Yoast SEO などのプラグインにも同機能があります。テーマ内蔵 → プラグイン → 自作の順で検討し、細かい制御が必要な場合に自作を選ぶのがおすすめです。
この記事でわかること
- ページ種別ごとに出し分けるパンくず関数の作成(カテゴリー・固定ページ階層・タグ・検索)
- テーマへの組み込みとCSS
- リッチリザルトに必要な構造化データ(BreadcrumbList)の注意
パンくずリストの関数を作成する
functions.php に次の関数を追加します。区切り文字は $sep にまとめ、URLは esc_url()・テキストは esc_html() でエスケープして出力します。固定ページは get_post_ancestors() で親ページの階層も辿ります。
functions.php:パンくずリスト生成関数
function custom_breadcrumbs() {
$sep = ' » '; // 区切り文字(ここを変えれば一括変更)
echo '<a href="' . esc_url(home_url('/')) . '">ホーム</a>';
if (is_single()) {
// 投稿:先頭のカテゴリー → 記事タイトル
$cats = get_the_category();
if (!empty($cats)) {
echo $sep . '<a href="' . esc_url(get_category_link($cats[0]->term_id)) . '">'
. esc_html($cats[0]->name) . '</a>';
}
echo $sep . esc_html(get_the_title());
} elseif (is_page()) {
// 固定ページ:親ページの階層を上から辿る
$ancestors = array_reverse(get_post_ancestors(get_the_ID()));
foreach ($ancestors as $ancestor_id) {
echo $sep . '<a href="' . esc_url(get_permalink($ancestor_id)) . '">'
. esc_html(get_the_title($ancestor_id)) . '</a>';
}
echo $sep . esc_html(get_the_title());
} elseif (is_category()) {
echo $sep . esc_html(single_cat_title('', false));
} elseif (is_tag()) {
echo $sep . esc_html(single_tag_title('', false));
} elseif (is_search()) {
echo $sep . '検索結果:' . esc_html(get_search_query());
} elseif (is_date()) {
echo $sep . esc_html(get_the_time('Y年n月')) . 'の記事';
}
}
カテゴリーは「1系統」に絞る
投稿に複数カテゴリーがある場合、パンくずでは先頭の1つに絞るのが一般的です(すべて並べると「現在地」の意味が薄れます)。カテゴリー取得の詳細は記事のカテゴリーを取得する方法(完全ガイド)、リンク付き表示の基本は特定のカテゴリー名をリンク付きで表示する方法を参照してください。
投稿に複数カテゴリーがある場合、パンくずでは先頭の1つに絞るのが一般的です(すべて並べると「現在地」の意味が薄れます)。カテゴリー取得の詳細は記事のカテゴリーを取得する方法(完全ガイド)、リンク付き表示の基本は特定のカテゴリー名をリンク付きで表示する方法を参照してください。
テーマに組み込む
表示したいテンプレート(header.php など)で関数を呼び出します。トップページでは非表示にするのが一般的です(is_front_page() と is_home() の違いも参照)。
テンプレート:フロントページ以外で表示
<?php if (!is_front_page()) : ?>
<div class="breadcrumbs">
<?php custom_breadcrumbs(); ?>
</div>
<?php endif; ?>
CSSで見た目を整える
style.css:パンくずのスタイル
.breadcrumbs {
padding: 10px 0;
font-size: 14px;
color: #666;
}
.breadcrumbs a {
color: #0073aa;
text-decoration: none;
}
.breadcrumbs a:hover {
text-decoration: underline;
}
注意:リッチリザルトには構造化データが必要
自作パンくずはそのままでは検索結果に反映されない
Google検索結果のパンくず表示(リッチリザルト)には、schema.org の BreadcrumbList 構造化データが必要です。YoastやCocoon内蔵のパンくずは自動で出力しますが、自作の場合は自分で追加する必要があります。Cocoon利用中なら内蔵パンくず(構造化データ込み)を活かし、見た目だけ自作したい場合も構造化データはテーマ側に任せるのが手軽です。
Google検索結果のパンくず表示(リッチリザルト)には、schema.org の BreadcrumbList 構造化データが必要です。YoastやCocoon内蔵のパンくずは自動で出力しますが、自作の場合は自分で追加する必要があります。Cocoon利用中なら内蔵パンくず(構造化データ込み)を活かし、見た目だけ自作したい場合も構造化データはテーマ側に任せるのが手軽です。
BreadcrumbList は次のようなJSON-LD形式です(例:ホーム → カテゴリー → 記事)。PHPで動的に出力する実装はテーマにJSON-LD形式の構造化データを追加する方法で詳しく解説しています。
JSON-LD:BreadcrumbListの構造(例)
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{ "@type": "ListItem", "position": 1, "name": "ホーム", "item": "https://example.com/" },
{ "@type": "ListItem", "position": 2, "name": "WordPress", "item": "https://example.com/wp/" },
{ "@type": "ListItem", "position": 3, "name": "記事タイトル" }
]
}
よくある質問(FAQ)
Q区切り文字(» や / など)を変更するには?
Aこの記事のコードでは
$sep 変数を書き換えるだけで全箇所に反映されます。HTML側で区切りを持たせている場合は、CSSの疑似要素(.breadcrumbs a + a::before { content: " / "; } など)で変える方法もあります。Q自作パンくずでも検索結果にパンくずが表示されますか?
AHTML のパンくずだけでは表示されません。BreadcrumbList の構造化データ(JSON-LD)を出力する必要があります。テーマやSEOプラグインが出力している場合は不要です。自作する場合はJSON-LDを追加する方法を参照してください。
Qテーマ内蔵・プラグイン・自作、どれを使うべきですか?
Aテーマ内蔵 → プラグイン → 自作の順で検討するのがおすすめです。Cocoonなど内蔵機能があれば構造化データ込みで手間がありません。表示内容や階層を細かく制御したい場合に、この記事の自作方式が向いています。
まとめ
- 関数:ページ種別ごとに分岐し、
esc_url/esc_htmlで安全に出力 - 階層:固定ページは
get_post_ancestors()、投稿はカテゴリー1系統 - 組み込み:
!is_front_page()でトップ以外に表示 - SEO:リッチリザルトには BreadcrumbList 構造化データが別途必要
- 判断順:テーマ内蔵(Cocoon等)→ プラグイン → 自作
自作は自由度が高いぶん、構造化データまで含めて自分で管理することになります。テーマ内蔵機能との使い分けを踏まえて実装しましょう。
