かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

WordPress タクソノミー名によっては予約語でなくてもアーカイブページに投稿が表示されないことがあるっぽい

遥か昔、100億年ほど前に作っていたテーマを使用していたサイトで突然アーカイブページに何も表示されなくなったと連絡がありました。ブラウザの表示でなければ、何もして無ければ変化が起こるはずがないので、何を変更したか訊いたところ「WordPressプラグイン」をアップデートしたという事でした。はい。100%コレが原因で挙動が変わったわけですね。
「突然動かなくなった」じゃなくて、「アップデートしたら」って最初から言ってください...
(´-`).。oO(普段からもっとこまめにアップデートしておいておくれよ...)
よく解ってない運用者に期待するのが間違っているのです。はい。愚痴を言っても始まらないので、調査しましょう。

Note.

  • アップデートされたWordPressのバージョン: 4.6.1

title」というスラッグ名のタクソノミーのアーカイブページで投稿が表示されていない

問題のページを確認したところ、titleという名前のタクソノミーアーカイブページで問題が発生していました。
タクソノミーの登録はこのようになっていました。

<?php // function.php
add_action('init', 'my_custom_init');
function my_custom_init() {
  // 中略 //
  $arg = array(
    'labels'         => $labels,
    'public'         => true,
    'show_ui'        => true,
    'hierarchical'   => true,
    'show_tagcloud'  => true,
  );
  register_taxonomy('title', 'product', $arg);
  // 中略 //
}

product というカスタム投稿タイプのタクソノミーになっています。
他のproductに紐付けられたタクソノミーのアーカイブページは問題なく表示されており、タクソノミーの登録方法にも特に違いはありませんでした。
また、function.php でこのタクソノミーの際に何か処理を行ってるコードも特にありませんでした。

何が原因になっているか探す

問題がよくわからない時は、糸口を掴むために問題が起きているページと正常なページのWordPressグローバル変数 $wp_queryダンプして見比べて違いを探していきます。
問題となっているタクソノミーのアーカイブページのテンプレートはtaxonomy-title.phpです。

<?php var_dump( $wp_query ); ?>

上記コードをテンプレートに記述して見たところ、["posts"]=> &array(0) となっており取得できている投稿が0件となっていました。

どうやら投稿を取得するクエリに問題がありそうです。
このページを表示するのに使われたクエリは$wp_queryオブジェクトから下記で見ることができます。

<?php var_dump( $wp_query->request ); ?>

タクソノミー名が投稿タイトルと一致するものを探していた!

titleタクソノミーがhogeアーカイブページ (url: http://site-name/title/hoge) の時、次のようなクエリが使用されていました。

SELECT SQL_CALC_FOUND_ROWS  wp_posts.ID FROM wp_posts
LEFT JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
WHERE 1=1
  AND wp_posts.post_title = 'hoge'
  AND ( wp_term_relationships.term_taxonomy_id IN (8) )
  AND wp_posts.post_type = 'product'
  AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private')
GROUP BY wp_posts.ID
ORDER BY wp_posts.post_date
DESC LIMIT 0, 20

WHERE句におかしなものがありますね...

_人人人人人人人人人人人人人人人人人人_
> AND wp_posts.post_title = 'hoge' <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

どうみても、投稿タイトルとタクソノミー名が一致しているものを探しています。本当に有難うございます。
当然、他の問題なく表示されているタクソノミーのアーカイブページにはpost_title =という条件はありませんでした。

リファレンスを見るかぎり、titleというタクソノミー名は予約語にはなっていない様なのですが、titleというタクソノミー名でアーカイブなどの絞込の条件がquery_varsの中にあると、投稿のタイトルの検索と誤認してしまってうようです。

<?php var_dump( $wp_query->query_vars ); ?>  
array(66) {
  ["title"]=>
  string(4) "hoge" // ← これが post_title = 'hoge' の条件になってるっぽい
  ["error"]=>
  string(0) ""
  ["m"]=>
  // 以下略

pre_get_posts アクション内でクエリの条件を修正する。

意図しない条件が入ってしまっているので、WordPressのクエリを変更する pre_get_posts アクション内でクエリの条件を変更します。

<?php // function.php
function my_posts_query( $query ) {
  if( !is_admin() && $query->is_main_query() ) {
        if( is_archive() && is_tax('title') ) {
      // query_vars["title"]を削除
      unset($query->query_vars["title"]);
      // query_vars["title"]を削除 するとナゼかタクソノミーの指定も無くなってしまうので、改めて追加する
      $term = $query->query["title"];
      $tax_query = array(
        array(
          'taxonomy' => 'title',
          'field'    => 'slug',
          'terms'    => $term,
        ),
      );
      $query->set('tax_query', $tax_query);
    }
  }
}
add_action('pre_get_posts', 'my_posts_query');

これで、問題なくtitleというタクソノミーのアーカイブページが問題なく表示されるようになりました。
リファレンスの予約語の欄にtitleという単語は無かったのですが、WordPress内で一般的に使われている単語はカスタム投稿やタクソノミー名に使うにはキケンがあると思っておいた方が良いかもしれません。


[参考]