あるサイトで、コラムの記事のパンくずが「HOME」だけになっていました。
コラムは、カスタム投稿で作った投稿タイプです。
コラムの一覧のページも、同じく「HOME」だけでした。
この記事では、原因の見つけ方と、あとで投稿タイプが増えても抜けない書き方をまとめます。
どうなっていたか
| ページ | 画面のパンくず(前) | あるべき形 |
|---|---|---|
| コラムの記事 | HOME | HOME > コラム > 記事のタイトル |
| コラムの一覧 | HOME | HOME > コラム |
| 事例の記事・固定ページ・お知らせ | 正しく出ていた | (そのまま) |
おもしろいのは、SEO のプラグイン(All in One SEO)が出す構造化データのほうは、正しかったことです。
ページの HTML の中の BreadcrumbList(JSON-LD)には、「Home > コラム > タイトル」が入っていました。
抜けていたのは、画面に出るパンくずだけでした。
構造化データはプラグインが作り、画面のパンくずはテーマが作っているので、片方だけが抜けることがあります。
原因:種類ごとに分けて書いていて、コラムの分けがなかった
テーマのパンくずは、template-parts/breadcrumb.php の 1 つのファイルで作っています。
中は、ページの種類ごとに if と elseif で分けて書いてありました。
形だけを抜き出すと、次のようになります。
<?php // HOME はいつも出す ?> <li>…HOME…</li> <?php if ( is_welcart_member_page() ) : // 会員のページ elseif ( strpos( $_SERVER['REQUEST_URI'], '/archives/customer' ) !== false ) : // 事例(customer) elseif ( is_post_type_archive( 'news' ) ) : // お知らせの一覧 elseif ( is_singular( 'news' ) ) : // お知らせの記事 elseif ( is_category() ) : // カテゴリー // …(タグ・検索・日付・ブログのトップ) elseif ( is_page() ) : // 固定ページ elseif ( is_singular( 'post' ) ) : // ふつうの投稿 elseif ( is_404() ) : // 404 endif; // コラム(column)の分けがない → HOME だけで終わる
| 書き方 | 役目 |
|---|---|
is_page() |
固定ページのとき |
is_singular( 'post' ) |
ふつうの投稿の記事のとき。カスタム投稿の記事は入らない |
is_singular( 'news' ) |
お知らせ(テーマが作ったカスタム投稿)の記事のとき |
is_post_type_archive( 'news' ) |
お知らせの一覧のとき |
$_SERVER['REQUEST_URI'] |
事例は、URL に /archives/customer が入っているかで分けていた |
テーマを買ったときからある種類(投稿・固定ページ・お知らせ)と、あとから足した事例は、分けが書いてありました。
コラムは、あとからプラグイン(Custom Post Type UI)の書き出しで足した種類で、パンくずの分けを足していませんでした。
そのため、コラムのページはどの elseif にも当たらず、最初の「HOME」だけで終わっていました。
直し方:分けの最後に「受け皿」を足す
コラムのための elseif ( is_singular( 'column' ) ) を足すこともできます。
ただ、それだと、次に投稿タイプを足したときに、また同じことが起きます。
そこで、上の分けのどれにも当たらなかった投稿タイプを、まとめて受け止める分けを足しました。
置き場所は、分けのいちばん最後(is_404() の前)です。
上の分けはそのまま残すので、今まで正しく出ていたページは変わりません。
<?php // …(上の分けはそのまま) elseif ( is_singular( 'post' ) ) : // ふつうの投稿(そのまま) // ここから足した受け皿:上で分けていない投稿の種類 // 一覧:HOME > 種類の名前 elseif ( is_post_type_archive() ) : $breadcrumb_type = get_queried_object(); ?> <li class="p-breadcrumb__item c-breadcrumb__item"> <span itemprop="name"><?php echo esc_html( $breadcrumb_type && ! empty( $breadcrumb_type->label ) ? $breadcrumb_type->label : post_type_archive_title( '', false ) ); ?></span> </li> <?php // 記事:HOME > 種類の名前(一覧があればリンク)> タイトル elseif ( is_singular() && ( $breadcrumb_type = get_post_type_object( get_post_type() ) ) ) : $breadcrumb_type_link = $breadcrumb_type->has_archive ? get_post_type_archive_link( $breadcrumb_type->name ) : ''; if ( $breadcrumb_type_link ) : ?> <li class="p-breadcrumb__item c-breadcrumb__item" itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"> <a href="<?php echo esc_url( $breadcrumb_type_link ); ?>" itemscope itemtype="http://schema.org/Thing" itemprop="item"> <span itemprop="name"><?php echo esc_html( $breadcrumb_type->label ); ?></span> </a> <meta itemprop="position" content="<?php echo $breadcrumb_position++; ?>" /> </li> <?php endif; ?> <li class="p-breadcrumb__item c-breadcrumb__item"> <span itemprop="name"><?php echo strip_tags( get_the_title( $post->ID ) ); ?></span> </li> <?php // ここまで elseif ( is_404() ) : // 404(そのまま) endif;
| 書き方 | 役目 |
|---|---|
is_post_type_archive() |
種類を指定しないと、どの種類の一覧でも当たる |
get_queried_object() |
一覧のページでは、その投稿タイプの情報(WP_Post_Type)が返る |
->label |
投稿タイプの名前(ここでは「コラム」)。登録のときに付けた名前がそのまま出る |
post_type_archive_title( '', false ) |
名前が取れなかったときの代わり。false で、出さずに文字で返す |
is_singular() |
種類を指定しないと、どの種類の記事でも当たる |
get_post_type_object( get_post_type() ) |
今の記事の投稿タイプの情報。取れないときは受け皿に入らない |
->has_archive |
その種類に一覧のページがあるか |
get_post_type_archive_link() |
一覧のページの URL。一覧があるときだけ、種類の名前をリンクにする |
esc_html()・esc_url() |
画面に出す文字と URL を、安全な形にする |
一覧のない種類は、種類の名前を出さない
投稿タイプには、一覧のページがないもの(has_archive が false)もあります。
たとえば、添付ファイル(メディア)の種類です。
リンク先のない「種類の名前」を出しても、押せないだけなので、その場合は「HOME > タイトル」にしました。
受け皿は最後に置く
is_singular() は、固定ページやふつうの投稿でも当たります。
もし上のほうに置くと、固定ページやお知らせまで受け皿に入ってしまい、今の出し方が変わります。
いちばん最後に置けば、上で分けたページは今まで通りで、分けていないページだけが受け皿に入ります。
テーマの見た目に合わせるため、<li> の class や、構造化データの属性(itemprop など)は、上の分けと同じ書き方にそろえました。
確かめた結果
このサイトの作業環境(WordPress 7.1.3・PHP 8.3.32)で確かめました。
テーマのファイルは変えずに、直す前のファイルを git から取り出して、試しのスクリプトから読ませて比べました。
DB には書いていません。
<?php
// 試しのスクリプト:URL の形でクエリを作り、直す前と後のパンくずを出して比べる
// 直す前のファイルは git show で取り出して、スクリプトの横に置いた(テーマのファイルは変えない)
$_SERVER['REQUEST_URI'] = $argv[1];
$_SERVER['HTTP_HOST'] = '(作業環境のホスト名)';
define( 'WP_USE_THEMES', false );
require '(作業環境の WordPress)/wp-load.php';
wp(); // URL からクエリを作る(is_singular() などが使えるようになる)
function bc_render( $file ) {
global $post, $dp_options;
ob_start();
include $file;
return ob_get_clean();
}
$before = bc_render( __DIR__ . '/breadcrumb-before.php' );
$after = bc_render( get_template_directory() . '/template-parts/breadcrumb.php' );
// それぞれの <li> の文字とリンクを取り出して並べる
| 書き方 | 役目 |
|---|---|
WP_USE_THEMES を false |
WordPress とテーマの関数は読み込むが、ページは出さない |
wp() |
REQUEST_URI の URL から、表示のときと同じクエリを作る |
ob_start()・ob_get_clean() |
パンくずのファイルが出す HTML を、文字として受け取る |
ページごとの前と後
| ページ | 直す前 | 直した後 |
|---|---|---|
| コラムの記事 | HOME | HOME > コラム(一覧へのリンク)> 記事のタイトル |
| コラムの一覧 | HOME | HOME > コラム |
| 事例の記事 | HOME > 事例一覧 > タイトル | 同じ |
| 事例の一覧 | HOME > 事例一覧 | 同じ |
| 固定ページ | HOME > ページのタイトル | 同じ |
| お知らせの記事 | HOME > お知らせ > タイトル | 同じ |
| お知らせの一覧 | HOME > お知らせ | 同じ |
| ふつうの投稿 | HOME > カテゴリー > タイトル | 同じ |
| 404 のページ | HOME > 見つからないという文 | 同じ |
変わったのはコラムの 2 種類だけで、ほかのページは、前と後で文字もリンクも同じでした。
コラムの記事 すべて
公開中のコラムの記事 62 件を、1 件ずつ同じ方法で比べました。
| 直す前 | 直した後 | |
|---|---|---|
| HOME だけ | 62 | 0 |
| HOME > コラム > タイトル | 0 | 62 |
一覧のない種類(添付ファイル)
添付ファイルのページも、試しのスクリプトで比べました。
| 添付ファイルの親 | 直す前 | 直した後 |
|---|---|---|
| コラムの記事 | HOME | HOME > ファイルのタイトル |
| ふつうの投稿 | HOME | HOME > ファイルのタイトル |
| 固定ページ | HOME > ファイルのタイトル | 同じ |
一覧がないので、「添付ファイル」という種類の名前は出ず、「HOME > タイトル」になりました。
固定ページの下の添付ファイルは、is_page() にも当たるため、受け皿の前の固定ページの分けで出ていて、変わりませんでした。
なお、このサイトは添付ファイルのページを開かない設定(wp_attachment_pages_enabled が 0)なので、実際に開くと画像のファイルへ移ります(301)。
そのため、添付ファイルのパンくずは、試しのスクリプトの中だけで確かめました。
画面と構造化データ
直したあとのページを開いて、画面のパンくずと、HTML の中の BreadcrumbList を比べました。
| ページ | 画面のパンくず | BreadcrumbList(JSON-LD) |
|---|---|---|
| コラムの記事(作業環境) | HOME > コラム > タイトル | Home > コラム > タイトル |
| コラムの記事(本番) | HOME > コラム > タイトル | Home > コラム > タイトル |
| コラムの一覧(作業環境) | HOME > コラム | Home > Archives for (名前が空) |
| コラムの一覧(本番) | HOME > コラム | Home > Archives for (名前が空) |
記事のページは、画面と構造化データの並びがそろいました。
一覧のページでは、プラグインの構造化データの 2 つ目の名前が「Archives for 」のあとが空になっていました。
これはプラグインが作る部分で、テーマのパンくずとは別です。
この記事では直していません(原因も調べていません)。
あとで投稿タイプを新しく足したときの動きは、このサイトではまだ種類を足していないので、試していません。
受け皿の書き方は種類の名前を書いていないので、コラムと同じように出るはずです。
気をつけること
- 受け皿は、分けのいちばん最後に置きます。上に置くと、今まで正しく出ていたページの形が変わります
- 種類の名前は、投稿タイプを登録したときの名前(
label)がそのまま出ます。英語の名前で登録していれば、英語で出ます - パンくずのファイルを直す前に、構造化データ(JSON-LD)がどうなっているかも見ておくと、どちらが抜けているかが分かります
- テーマを更新すると、パンくずのファイルが元に戻ることがあります。子テーマや、自分で管理しているテーマで直します
まとめ
- カスタム投稿のパンくずが HOME だけになるのは、テーマが種類ごとに分けて書いていて、その種類の分けがないことが多い
- 種類を 1 つずつ足す代わりに、
is_post_type_archive()とis_singular()を種類なしで使う受け皿を、分けの最後に置く - 種類の名前は
get_post_type_object()のlabel、一覧へのリンクはhas_archiveがあるときだけget_post_type_archive_link()で出す - 直す前のファイルを git から取り出して、試しのスクリプトで前と後を並べると、変わったページと変わらないページがはっきり分かる
- 画面のパンくずと、プラグインの構造化データは別に作られているので、両方を見る


