カスタム投稿のパンくずが HOME だけになる:投稿タイプが増えても抜けない受け皿の書き方

トラブル・エラー対応
広告WordPress・PHP を学べる本

Amazonのアソシエイトとして、WordPress functions.phpは適格販売により収入を得ています。

あるサイトで、コラムの記事のパンくずが「HOME」だけになっていました。

コラムは、カスタム投稿で作った投稿タイプです。

コラムの一覧のページも、同じく「HOME」だけでした。

この記事では、原因の見つけ方と、あとで投稿タイプが増えても抜けない書き方をまとめます。

どうなっていたか

ページ 画面のパンくず(前) / あるべき形
コラムの記事 画面のパンくず(前):HOMEあるべき形:HOME > コラム > 記事のタイトル
コラムの一覧 画面のパンくず(前):HOMEあるべき形:HOME > コラム
事例の記事・固定ページ・お知らせ 画面のパンくず(前):正しく出ていたあるべき形:(そのまま)

おもしろいのは、SEO のプラグイン(All in One SEO)が出す構造化データのほうは、正しかったことです。

ページの HTML の中の BreadcrumbList(JSON-LD)には、「Home > コラム > タイトル」が入っていました。

抜けていたのは、画面に出るパンくずだけでした。

構造化データはプラグインが作り、画面のパンくずはテーマが作っているので、片方だけが抜けることがあります。

原因:種類ごとに分けて書いていて、コラムの分けがなかった

テーマのパンくずは、template-parts/breadcrumb.php の 1 つのファイルで作っています。

中は、ページの種類ごとに if と elseif で分けて書いてありました。

形だけを抜き出すと、次のようになります。

template-parts/breadcrumb.php(直す前の形・内容は省略)
<?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() の前)です。

上の分けはそのまま残すので、今まで正しく出ていたページは変わりません。

template-parts/breadcrumb.php(足したところ)
<?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 > コラム > タイトルBreadcrumbList(JSON-LD):Home > コラム > タイトル
コラムの記事(本番) 画面のパンくず:HOME > コラム > タイトルBreadcrumbList(JSON-LD):Home > コラム > タイトル
コラムの一覧(作業環境) 画面のパンくず:HOME > コラムBreadcrumbList(JSON-LD):Home > Archives for (名前が空)
コラムの一覧(本番) 画面のパンくず:HOME > コラムBreadcrumbList(JSON-LD):Home > Archives for (名前が空)

記事のページは、画面と構造化データの並びがそろいました。

一覧のページでは、プラグインの構造化データの 2 つ目の名前が「Archives for 」のあとが空になっていました。

これはプラグインが作る部分で、テーマのパンくずとは別です。

この記事では直していません(原因も調べていません)。

あとで投稿タイプを新しく足したときの動きは、このサイトではまだ種類を足していないので、試していません。

受け皿の書き方は種類の名前を書いていないので、コラムと同じように出るはずです。

気をつけること

  • 種類の名前は、投稿タイプを登録したときの名前(label)がそのまま出ます。英語の名前で登録していれば、英語で出ます
  • テーマを更新すると、パンくずのファイルが元に戻ることがあります。子テーマや、自分で管理しているテーマで直します

まとめ

次に投稿タイプを足したときは、その種類の記事と一覧のページを開き、画面のパンくずに種類の名前と一覧へのリンクが出るかを見ます。コラムの一覧の構造化データで「Archives for 」のあとが空になっている点は、プラグインの側で原因を調べます。

参考

SiteBeacon(サイトビーコン)

サイトが止まったら、すぐに気づける。

ホームページを 5 分ごとにチェックして、止まったとき・エラーが出たとき・SSL やドメインの期限が近いときに、メールでお知らせします。2 サイトまでは、ずっと無料で使えます。

SiteBeacon を見る サイトを直す相談をする

監視で気づいたあとの直す作業も、同じ担当がお受けします。