【WordPress】固定ページでカテゴリーページを作成する方法

固定ページでカテゴリーページを作成する方法を紹介します。

コピペ利用可能なソースコードを詳しい解説付きでお送りします。SEOの観点から問題となるコンテンツの重複についても、具体的な対策を紹介しています。

解決したいこと: 「固定ページでカテゴリーページを作成する」とは

この記事ではどんな問題を解決できるか?

通常、WordPress のカテゴリーページは、投稿や固定ページのような「個別ページ」とは異なり、管理画面で記事を作成することはできません。あらかじめ、テンプレートを作成しておき、表示する記事はいつもアクセスのたびに決定されます。

例えば、ある日、/category/javascript にアクセスがあり、1ページ目に記事ID 5〜1 が表示されたとしても、1週間後再びアクセスがあったときは、10〜6 というように表示が変わってしまうかもしれません。

この動作を「いつも特定の記事のみ表示する」というように変更したいのなら、テーマの中に category-$slug.php(上記の例の場合、category-javascript.phpを作成します。

この記事で紹介するのは、この工程を固定ページで行う方法です。

実現される動作

前置きを引っ張って申し訳ないのですが、紹介する方法を試すとどういう動作に変わるのかを説明します。

固定ページをカテゴリーページにするのはカテゴリーごとに設定します。設定方法は、カテゴリーのスラッグと同じスラッグで公開状態の固定ページを作成することです。前の例だと、javascript というスラッグの固定ページを公開します。そうしなかったカテゴリーは通常のテンプレート階層のとおりにテンプレートが適用されます。

  • 固定ページを作成・公開した場合: 固定ページが表示される(ただし、category-$slug.php または category-$id.php があった場合は表示されない)
  • そうしなかった場合: 通常のカテゴリーと同じ動作

もし、固定ページにカスタムテンプレートが設定されていれば、それを適用するようにします。

また、固定ページ自体にアクセスがあった場合は、通常どおり固定ページを表示します。そのため、SEOの観点から、重複コンテンツが生まれてしまうという問題が発生します。その対策についても記事の後半で解説します。

ソースコード

お待たせしました。実際のコードの紹介です。すべてのカテゴリーページのアクセスをキャッチするため、category.php に記述を行います。

category.php(コピペでお使いいただけます。)
  1. <?php
  2. /**
  3. * カテゴリースラッグと同じスラッグの固定ページが存在すれば固定ページを表示し、
  4. * なければアーカイブページを表示する。
  5. *
  6. * 1. 公開状態の固定ページあり:
  7. *
  8. * 1-1. カスタムテンプレート
  9. * 1-2. page-$slug.php
  10. * 1-3. page-$id.php
  11. * 1-4. page.php
  12. * 1-5. singular.php
  13. * 1-6. index.php
  14. *
  15. * 2. 公開状態の固定ページなし:
  16. *
  17. * 2-1. archive.php
  18. * 2-2. paged.php (2ページ目以降)
  19. * 2-3. index.php
  20. */
  21. $category_slug = get_query_var('category_name');
  22. $page = get_page_by_path($category_slug);
  23.  
  24. if (isset($page) && $page->post_status === 'publish') { # 1. 公開状態の固定ページあり
  25.  
  26. # メインループの書き換え
  27. $GLOBALS['wp_the_query']->posts = [$page];
  28. $GLOBALS['wp_the_query']->post_count = 1;
  29.  
  30. # カスタムテンプレートのパス
  31. $template_path = get_post_meta($page->ID, '_wp_page_template')[0];
  32.  
  33. if ($template_path) {
  34. if ($template_path !== 'default') {
  35. # 1-1. $custom.php
  36. locate_template([$template_path], true);
  37. }
  38. } else {
  39. locate_template([
  40. "page-{$page->post_name}.php", # 1-2. page-$slug.php
  41. "page-{$page->ID}.php", # 1-3. page-$id.php
  42. "page.php", # 1-4. page.php
  43. 'singular.php', # 1-5. singular.php
  44. 'index.php', # 1-6. index.php
  45. ], true);
  46. }
  47.  
  48. } else { # 2. 公開状態の固定ページなし
  49.  
  50. locate_template([
  51. 'archive.php', # 2-1. archive.php
  52. (get_query_var('paged', 1) >= 2
  53. ? 'paged.php' # 2-2. paged.php (2ページ目以降)
  54. : null),
  55. 'index.php', # 2-3. index.php
  56. ], true);
  57. }

ソースコードの解説

ここからはコードの解説をしていきます。

1. 公開状態の固定ページあり

一番外側の if 文で固定ページの有無を調べて、その結果に応じて擬似的にテンプレート階層を作成しています。既に category.php が適用されているので、擬似的に階層を再現する必要があります。

  1. if (isset($page) && $page->post_status === 'publish') { # 公開状態の固定ページあり

メインループの書き換え:

固定ページを適用する場合は、メインループを書き換えます。理由は簡単で、該当の固定ページのみを表示するためです。書き換えを行わなかった場合は、通常のカテゴリー検索結果が表示されてしまいます。

  1. # メインループの書き換え
  2. $GLOBALS['wp_the_query']->posts = [$page];
  3. $GLOBALS['wp_the_query']->post_count = 1;

設定されているカスタムテンプレートの取得:

固定ページはカスタムテンプレートが最優先で適用されます。固定ページに設定されているカスタムテンプレートは、カスタムフィールドで管理されており、フィールド名は「_wp_page_template」です。

  1. # カスタムテンプレートのパス
  2. $template_path = get_post_meta($page->ID, '_wp_page_template')[0];
1-1. カスタムテンプレートの適用

カスタムテンプレートが設定されていた場合はそれを適用します。ここで使用している locate_template() 関数は、第一引数に適用するテンプレートパスを優先順に並べたもので、第二引数を true にするとテンプレートを読み込みます。

  1. if ($template_path) {
  2. if ($template_path !== 'default') {
  3. # 1-1. $custom.php
  4. locate_template([$template_path], true);
  5. }
1-2 ~ 1-6. 各種テンプレートの適用
  1. } else {
  2. locate_template([
  3. "page-{$page->post_name}.php", # 1-2. page-$slug.php
  4. "page-{$page->ID}.php", # 1-3. page-$id.php
  5. "page.php", # 1-4. page.php
  6. 'singular.php', # 1-5. singular.php
  7. 'index.php', # 1-6. index.php
  8. ], true);
  9. }

2. 公開状態の固定ページなし

公開の固定ページがない場合は通常のカテゴリーと同様です。しかし、このテンプレートが category.php であり、より優先度の高い category-$slug.phpcategory-$id.php は既にスキップされているのでここでは含めません。

  1. } else { # 2. 公開状態の固定ページなし
  2.  
  3. locate_template([
  4. 'archive.php', # 2-1. archive.php
  5. (get_query_var('paged', 1) >= 2
  6. ? 'paged.php' # 2-2. paged.php (2ページ目以降)
  7. : null),
  8. 'index.php', # 2-3. index.php
  9. ], true);
  10. }

SEO対策: 重複コンテンツの対応

ここでは、SEOで問題となる事柄について解説します。

これまでの解説内容を実践すると、カテゴリーページへのアクセスと固定ページへのアクセス両方に同じコンテンツを配信するという性質から、ページへの評価が分散してしまうことになります。

どういうことかというと、カテゴリーページ /category/javascript へアクセスした場合と 固定ページ /javascript にアクセスした場合とでコンテンツ内容は同じですが、クローラーからは別ページとして扱われてしまうということです。幸い、この問題を解決する方法が確立されています。

<link> 要素のリンク種別 canonical 属性値は、「正規」または「推奨」バージョンのウェブページを示すことができます。

  1. <head>
  2. <link rel="canonical" href="https://example.com/category-name">
  3. </head>

この仕組み活用して、例えば、カテゴリーページとして使用する固定ページのカスタムテンプレートを次のようにします。

template-single.php
  1. <?php
  2. /*
  3. Template Name: Post
  4. */
  5. add_action('wp_head', function () {
  6. if (is_category()) { # カテゴリーページでの表示の場合
  7. $category_slug = get_query_var('category_name');
  8. $page = get_page_by_path($category_slug);
  9. $canonical = get_permalink($page->ID);
  10. echo '<link rel="canonical" href="' . $canonical . '">';
  11. }
  12. });
  13. get_template_part('single');

これは、固定ページに投稿のテンプレートを適用するというカスタムテンプレートですが、カテゴリーページとしてアクセスされた場合には canonical をセットしています。