sp_menu

【WordPress】プラグインなしでパンくずリストを実装する方法

【WordPress】パンくずリストをプラグインナシで実装する方法

今回はプラグインを使わずにパンくずリストを作成する方法をご紹介します。この記事は以下のお悩みを解決します。

  • ・パンくずリストをプラグインを使わずに作成したい
  • ・カテゴリーや固定ページの階層化にも対応できるようにしたい
       

1. パンくずリストとは?

パンくずリストは現在表示されているページがWebサイトのどの位置にあるかを示すナビゲーションです。以下はパンくずリストの例です。

これは投稿ページで表示されるパンくずリストで「Home」はトップページ、「WordPress」はカテゴリーページ、「【WordPress】プラグインなしでページネーションを実装する方法」は現在表示されているページのタイトルになります。「Home」と「WordPress」はリンクになっています。

パンくずリストを設置するメリットは以下のとおりです。

  • 【パンくずリストを設置するメリット】
  • ①ユーザビリティ(ユーザーの使いやすさ)の向上
  • ②クローラビリティ(クローラーのサイトの回遊のしやすさ)の向上
  • ③SEO評価の向上

ユーザビリティ(ユーザーの使いやすさ)の向上

パンくずリストを設置することで、ユーザーが現在見ているページがサイト内のどこにいるかを把握しやすくなります。大規模なサイトでは、サイトの構造が複雑になるので特に便利になります。

また、パンくずリストは上位ページのテキストがリンクになっているので上位ページや他のページに簡単に移動できます。

②クローラビリティ(クローラーのサイトの巡回のしやすさ)の向上

検索エンジンがサイト内を巡回して、ページの情報を収集するためのロボットをクローラーといいます。パンくずリストを設置することでクローラーがページが見つけやすくなり、より早くインデックスされる可能性があります。

インデックスとは検索エンジンにページが登録されることです。インデックスされないと検索してもページが表示されません。

SEO評価の向上

パンくずリストは内部リンクとして機能するため、サイトの内部リンク構造が強化されます。ユーザーがパンくずリストから他のページにアクセスすることで滞在時間が伸び、PV数が増える可能性があります。

検索エンジンはユーザーにとって有益なコンテンツを評価します。そのためユーザーの回遊率(1訪問あたりのPV数)が高くなり、滞在時間が長くなればWebサイトのSEO評価は向上する可能性があります。

2. パンくずリストの表示例

今回実装するパンくずリストは投稿ページ、固定ページ、カテゴリーページ、月別アーカイブページ、検索ページ、404ページで表示するようにします。

カテゴリーと固定ページは親子関係を設定することができ、階層構造を持たせることができます。投稿ぺージ、カテゴリーページ、固定ページに祖先のカテゴリーやページがある場合は表示します。

各ページのパンくずリストの表示例は以下のようになります。

  • 【投稿ページ】
  • (祖先カテゴリーなし) ホーム > カテゴリー > ページタイトル
  • (祖先カテゴリーあり) ホーム > 親カテゴリー > 子カテゴリー > ページタイトル

  • 【固定ページ】
  • (祖先ページなし) ホーム > ページタイトル
  • (祖先ページあり) ホーム > 親ページタイトル > 子ページタイトル

  • 【カテゴリーページ】
  • (祖先カテゴリーなし) ホーム > カテゴリー
  • (祖先カテゴリーあり) ホーム > 親カテゴリー > 子カテゴリー

  • 【月別アーカイブページ】
  • ホーム > 〇〇年△△月の記事一覧

  • 【検索ページ】
  • (検索キーワードあり) ホーム > 「〇〇」の検索結果
  • (検索キーワード未入力) ホーム > 検索キーワードが未入力

  • 【404ページ】
  • ホーム > ページが見つかりません
       

3. 実装方法

3-1. functions.phpを編集する

functions.phpに以下の内容を記述します。

functions.phpを編集する際に誤って必要なコードを削除してしまうと、サイトが表示されなくなる可能性があります。編集する前にバックアップを取ることをおすすめします。

バックアップの取り方がわからない方は以下の記事で紹介していますので参考にしてください。

<?php

function custom_breadcrumb() {
  $html = '<div class="breadcrumbs-list">';
  $html .= '<ul>';
  $html .= '<li><a href="'. esc_url(home_url()) .'"><i class="fa-solid fa-house"></i>ホーム</a></li>';
  
  //投稿ページ
  if(is_single()){   
    $cats = get_the_category();
    $target_cat = '';
    $current_cat_ancestors = [];
    $target_cat_ancestors = [];

    //カテゴリーが階層構造の場合、最下層のカテゴリーを取得
    foreach($cats as $cat) {
      $cat_ancestors = get_ancestors($cat->term_id, 'category');
      if($target_cat) {
       $current_cat_ancestors = get_ancestors($target_cat->term_id, 'category'); 
      }

      if(empty($target_cat) || count($cat_ancestors) > count($current_cat_ancestors)) {
        $target_cat = $cat;
      }
    }

    $target_cat_ancestors = array_reverse(get_ancestors($target_cat->term_id, 'category'));
  
    if($target_cat_ancestors) {
      foreach($target_cat_ancestors  as  $target_cat_ancestor) {
        $ancestor_category = get_category($target_cat_ancestor);
        $html .= '<li><a href="'.esc_url(get_category_link($ancestor_category->term_id)).'"><span class="arrow">></span>'.esc_html($ancestor_category->name).'</a></li>';
      }
    }
    if($target_cat) {
      $html .= '<li><span class="arrow">></span><a href="'.esc_url(get_category_link($target_cat->term_id)).'">'.esc_html($target_cat->name).'</a></li>';
    }
    $html .= '<li><span class="arrow">></span>'.esc_html(get_the_title()).'</li>';
  //固定ページ  
  }else if(is_page()) {
    $page = get_queried_object();
    $ancestors = array_reverse(get_ancestors($page->ID, 'page'));

    if($ancestors) {
      foreach($ancestors as $ancestor) {
        $ancestor_page = get_post($ancestor);
        $html .= '<li><a href="'. esc_url(get_page_link($ancestor_page)) .'"><span class="arrow">></span> '. esc_html($ancestor_page->post_title) .'</a></li>';
      }
    }
    $html .= '<li><span class="arrow">></span>'. esc_html(get_the_title()) .'</li>';
  //カテゴリーページ  
  }else if (is_category()) {
    $cat = get_queried_object();

    if ($cat->parent != 0) {
      $ancestors = array_reverse(get_ancestors($cat->term_id, 'category'));

      foreach ($ancestors as $ancestor) {
        $ancestor_category = get_category($ancestor);
        $html .= '<li><a href="'. esc_url(get_category_link($ancestor_category->term_id)) .'"><span class="arrow">></span> '. esc_html($ancestor_category->name) .'</a></li>';
      }
      $html .= '<li><span class="arrow">></span> '. esc_html($cat->name) .'</li>';
    } else {
      $html .= '<li><span class="arrow">></span> '. esc_html($cat->name) .'</li>';
    }
  //月別アーカイブページ
  }else if(is_month()) {
    $html .= ' <li><span class="arrow">></span>'. esc_html(get_the_date('Y年m月')) .'の記事一覧</li>';
  //検索ページ
  }else if(is_search()) {
    //検索キーワードが入力されているかどうかを判定
    if(get_search_query()) {
      $html .= '<li><span class="arrow">></span>「'. esc_html(get_search_query()) .'」の検索結果</li>';
    }else {
      $html .= '<li><span class="arrow">></span>検索キーワードが未入力</li>';
    }
  //404ページ
  }else if(is_404()) {
    $html .= '<li><span class="arrow">></span>ページが見つかりません</li>';
  }
  $html .= '</ul>';
  $html .= '</div>';

  echo $html;
}
 
?>

functions.phpの解説

4行目:$html .= ‘<div class=”breadcrumbs-list”>’;

「.=」は結合代入演算子でhtmlタグ(<div class=”breadcrumbs-list”>)を変数$htmlに追加します。

6行目:$html .= ‘<li><a href=”‘.esc_url(home_url()).'”>ホーム</a></li>’;

トップページへのリンクを表示するhtmlタグを変数$htmlに追加します。

  • home_url() :トップページのURLを取得する。
  • esc_url() :URLに適切でない文字が含まれている場合は除去し、URLを無害化する。これによりクロスサイトスクリプティング(XSS)攻撃や不正なリダイレクトを防ぐことができる。
  //投稿ページ
  if(is_single()){   
    $cats = get_the_category();
    $target_cat = '';
    $current_cat_ancestors = [];
    $target_cat_ancestors = [];

  //カテゴリーが階層構造の場合、最下層のカテゴリーを取得
    foreach($cats as $cat) {
      $cat_ancestors = get_ancestors($cat->term_id, 'category');
      if($target_cat) {
       $current_cat_ancestors = get_ancestors($target_cat->term_id, 'category'); 
      }

      if(empty($target_cat) || count($cat_ancestors) > count($current_cat_ancestors)) {
        $target_cat = $cat;
      }
    }

    $target_cat_ancestors = array_reverse(get_ancestors($target_cat->term_id, 'category'));

    if($target_cat_ancestors) {
      foreach($target_cat_ancestors  as  $target_cat_ancestor) {
        $ancestor_category = get_category($target_cat_ancestor);
        $html .= '<li><a href="'.esc_url(get_category_link($ancestor_category->term_id)).'"><span class="arrow">></span>'.esc_html($ancestor_category->name).'</a></li>';
      }
    }
    if($target_cat) {
      $html .= '<li><span class="arrow">></span><a href="'.esc_url(get_category_link($target_cat->term_id)).'">'.esc_html($target_cat->name).'</a></li>';
    }
    $html .= '<li><span class="arrow">></span>'.esc_html(get_the_title()).'</li>';
  //固定ページ  
  }else if(is_page()) {

9-40行目:if(is_single()){~}

現在表示されているページが投稿ページの場合、処理を実行します。

  • is_single() : 現在表示されているページが投稿ページの場合はtrue,それ以外はfalseを返す。

10行目:$cats = get_the_category();

投稿ページの指定した全てのカテゴリー情報を取得します。

  • get_the_category() : 投稿ページのカテゴリー情報を取得する。

16-25行目:foreach($cats as $cat){~}

$catsには指定した全てのカテゴリー情報が入っているのでforeach()でカテゴリー情報を1個ずつ取り出して処理を実行します。

カテゴリーを複数指定する場合についてもう少し詳しく解説します。

1.祖先があるカテゴリーを指定する場合

祖先があるカテゴリーを指定する場合は最下層のカテゴリー(最も祖先が多いカテゴリー)を取得します。例として投稿記事にCSS、Sass、HTMLの3つのカテゴリーが指定されている場合を考えます。

CSSとSassは階層構造(親子関係)になっており、HTMLは階層構造になっていません。Sassだけ祖先カテゴリー(CSS)があります。

この場合、Sassが最下層のカテゴリー(最も祖先が多いカテゴリー)になるのでSassのカテゴリー情報が23行目の$target_catに代入されます。

2.祖先がないカテゴリーを指定する場合

祖先がないカテゴリーを指定する場合はforeach()で取り出した最初のカテゴリーを取得します。例として以下のように祖先カテゴリーを持たないCSS、HTML、JavaScriptの3つのカテゴリーを指定する場合を考えます。

この例ではCSSが一番最初に取り出されるカテゴリーなのでCSSのカテゴリー情報が23行目の$target_catに代入されます。

17行目:$cat_ancestors = get_ancestors($cat->term_id, ‘category’);

$cat_ancestorsは$catの祖先のカテゴリーのIDを取得します。

  • get_ancestors($object_id, $object_type) : 特定のオブジェクトの祖先のIDの配列を返す。
  • ・$object_id : タームID(またはカテゴリーID)を指定する。
  • ・$object_type : 祖先の種類(’page'(固定ページ)、’category'(カテゴリー)、階層を持った投稿タイプまたはタクソノミー名)を指定する。

19行目:$current_cat_ancestors = get_ancestors($target_cat->term_id, ‘category’);

$target_catにカテゴリー情報が存在する場合、$target_catの祖先カテゴリーのIDを取得します。

22-24行目:if(empty($target_cat) || count($cat_ancestors) > count($target_cat_ancestors)) {~}

$target_catが空または、$cat_ancestorsの祖先カテゴリーの数が$current_cat_ancestorsの祖先カテゴリーの数より多いとき$target_catに$catを代入します。

カテゴリーが階層構造じゃない場合は$catsで取り出す最初のカテゴリー、階層構造になっている場合は最下層のカテゴリーを$target_catに代入します。

  • empty() : 変数が空かどうかを判定する。変数が存在しないか空の場合はtureを返す。
  • count() : 配列の要素数を返す。

27行目:$target_cat_ancestors = array_reverse(get_ancestors($target_cat->term_id, ‘category’));

$target_catの祖先カテゴリーのidを取得してます。カテゴリーが親、子、孫カテゴリーまである場合、get_ancestors()は子→親の順番で取得するのでarray_reverse()を使うことで親→子の順番の配列が作成されます。

  • array_reverse() : 要素の順番を逆にした配列を返す。例:array_reverse([1,2,3])は[3,2,1]を返す。

30-33行目:foreach($target_cat_ancestors as $target_cat_ancestor) {~}

$target_cat_ancestors(祖先カテゴリーのid)の要素を1つずつ取り出して処理を実行します。

31行目:$ancestor_category = get_category($target_cat_ancestor);

祖先のカテゴリー情報を取得します。

  • get_category($category) : カテゴリー情報を取得する。
  • ・$category:カテゴリーIDかカテゴリーオブジェクトを指定する。

32行目:$html .= ‘<li><a href=”‘.esc_url(get_category_link($target_cat_ancestor)).'”><span class=”arrow”>></span>’.esc_html($ancestor_category->name).'</a></li>’;

祖先カテゴリーを表示するhtmlタグを変数$htmlに追加します。

  • get_category_link($category) : カテゴリーページのURLを取得する。
  • ・$category:カテゴリーIDかオブジェクトを指定する。
  • esc_html() : HTMLに出力するデータに「<」「>」「’」「”」「&」の文字が含まれている場合は別の文字に置き換える。これにより、クロスサイトスクリプティング(XSS)攻撃を防ぐことができる。

36行目:$html .= ‘<li><span class=”arrow”>></span><a href=”‘.esc_url(get_category_link($target_cat->term_id)).'”>’.esc_html($target_cat->name).'</a></li>’;

カテゴリーを表示するhtmlタグを変数$htmlに追加します。

38行目: $html .= ‘<li><span class=”arrow”>></span>’.esc_html(get_the_title()).'</li>’;

記事のタイトルを表示するhtmlタグを変数$htmlに追加します。

  • get_the_title() : 投稿ページや固定ページのタイトルを取得する。
 //固定ページ  
  }else if(is_page()) {
    $page = get_queried_object();
    $ancestors = array_reverse(get_ancestors($page->ID, 'page'));

    if($ancestors) {
      foreach($ancestors as $ancestor) {
        $ancestor_page = get_post($ancestor);
        $html .= '<li><a href="'. esc_url(get_page_link($ancestor_page)) .'"><span class="arrow">></span> '. esc_html($ancestor_page->post_title) .'</a></li>';
      }
    }
    $html .= '<li><span class="arrow">></span>'. esc_html(get_the_title()) .'</li>';
  //カテゴリーページの場合  
  } elseif (is_category()) {

40-52行目:else if(is_page()) {~}

現在表示されているページが固定ページの場合は処理を実行します。

  • is_page() : 現在表示されているページが固定ページの場合true、それ以外はfalseを返す。

41行目:$page = get_queried_object();

固定ページの情報を取得します。

  • get_queried_object() : 現在表示しているページの情報を取得します。

42行目:$ancestors = array_reverse(get_ancestors($page->ID, ‘page’));

現在表示している固定ページに祖先ページがある場合、祖先ページのIDを取得します。

44-49行目:if($ancestors) {~}

$ancestorsに1つ以上の要素がある場合(現在表示している固定ページに祖先ページがある場合)、処理を実行します。

46行目:$ancestor_page = get_post($ancestor);

現在表示している固定ページの祖先ページ情報を取得します。

  • get_post($post) : 投稿ページ、固定ページの情報を取得する。
  • ・$post : 投稿ページまたは、固定ページのIDを指定する。

47行目:$html .= ‘<li><a href=”‘. esc_url(get_page_link($ancestor_page)) .'”><span class=”arrow”>></span> ‘. esc_html($ancestor_page->post_title) .'</a></li>’;

固定ページの祖先ページを表示するhtmlタグを変数$htmlに追加します。

  • get_page_link($id) : 固定ページのパーマリンクを取得する。
  • ・$id : 固定ページのIDを指定する。
  //カテゴリーページ  
  } elseif (is_category()) {
    $cat = get_queried_object();
   
    if ($cat->parent != 0) {
      $ancestors = array_reverse(get_ancestors($cat->term_id, 'category'));

      foreach ($ancestors as $ancestor) {
        $ancestor_category = get_category($ancestor);
        $html .= '<li><a href="'. esc_url(get_category_link($ancestor_category->term_id)) .'"><span class="arrow">></span> '. esc_html($ancestor_category->name) .'</a></li>';
      }
      $html .= '<li><span class="arrow">></span> '. esc_html($cat->name) .'</li>';
    } else {
      $html .= '<li><span class="arrow">></span> '. esc_html($cat->name) .'</li>';
    }
  //月別アーカイブページ
  }else if(is_month()) {

52-67行目:else if(is_category()) {~}

現在表示されているページがカテゴリーページの場合、処理を実行します。

  • is_category() : 現在表示されているページがカテゴリーページの場合はtrue、それ以外はfalseを返す。

55-65行目:if ($cat->parent != 0) {~}

カテゴリーに祖先カテゴリーがあるかどうかを判定しています。祖先カテゴリーがある場合は処理を実行します。

60行目:$html .= ‘<li><a href=”‘. esc_url(get_category_link($ancestor_category->term_id)) .'”><span class=”arrow”>></span> ‘. esc_html($ancestor_category->name) .'</a></li>’;

祖先のカテゴリーを表示するhtmlタグを変数$htmlに追加します。

62行目:$html .= ‘<li><span class=”arrow”>></span> ‘. esc_html($cat->name) .'</li>’;

カテゴリー(最下層のカテゴリー)を表示するhtmlタグを変数$htmlに追加します。

  //月別アーカイブ
  }else if(is_month()) {
    $html .= ' <li><span class="arrow">></span>'. esc_html(get_the_date('Y年m月')) .'の記事一覧</li>';
 //検索ページ
  }else if(is_search()) {

67-70行目:else if(is_month()) {~}

現在表示されているページが月付アーカイブページの場合は処理を実行します。

  • is_month() : 現在表示されているページが月付アーカイブページの場合はtrue、それ以外はfalseを返す。

68行目:$html .= ‘ <li><span class=”arrow”>></span>’.esc_html(get_the_date(‘Y年m月’)).’の記事一覧</li>’;

月別アーカイブページの年月を表示するhtmlタグを$htmlに追加します。

  • get_the_date($format) : 投稿日を取得する。
  • ・$format:投稿日のフォーマットを指定する。「Y」は4桁の西暦(2024、2025など)、「m」は2桁の月(06、12など)を表示する。
 //検索ページ
  }else if(is_search()) {
  //検索キーワードが入力されているかどうかを判定
    if(get_search_query()) {
      $html .= '<li><span class="arrow">></span>「'. esc_html(get_search_query()) .'」の検索結果</li>';
    }else {
      $html .= '<li><span class="arrow">></span>検索キーワードが未入力</li>';
    }
 //404ページ
  }else if(is_404()) {

70-78行目:else if(is_search()) {~}

現在表示しているページが検索ページの場合は処理を実行します。

  • is_search() : 現在表示されているページが検索ページの場合はtrue、それ以外はfalseを返す。

72-76行目:if(get_search_query()) {~}

検索キーワードが入力されているかどうかを判定し、true、falseのそれぞれの場合に表示するhtmlタグを変数$htmlに追加します。

  • get_search_query() : 検索キーワードを取得する。
 //404ページ
  }else if(is_404()) {
    $html .= '<li><span class="arrow">></span>ページが見つかりません</li>';
  }

78-80行目:else if(is_404()) {~}

現在表示しているページが、404ページの場合は処理を実行します。

  • is_404() : 現在表示されているページが、404ページの場合はtrue、それ以外はfalseを返す。

3-2. style.cssファイルを編集する

style.cssにパンくずリストのスタイルを指定します。以下はコードの例です。

フォントサイズやリストの間隔などはWebサイトのデザインによって変わると思うので、必要に応じて変更してください。

.breadcrumbs-list {
  margin-bottom: 10px;
}

.breadcrumbs-list ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}

.breadcrumbs-list li {
  line-height: 2;
  font-size: 12px;
}

.breadcrumbs-list li:not(:first-child) {
  padding-left: 5px;
}

.breadcrumbs-list li .arrow {
  margin-right: 5px;
}

.breadcrumbs-list li a {
  color: #333;
  font-size: 12px;
}

3-3. 関数の呼び出し

関数を呼び出す方法はパンくずリストを表示したい位置に以下のコードを記述します。

<?php  custom_breadcrumb(); ?>

以上でパンくずリストの作成は完了です。パンくずリストが表示されているか確認してみてください。

4. まとめ

今回はパンくずリストをプラグインを使わずに作成する方法をご紹介しました。

プラグインでもパンくずリストは設置できますが、自作することで勉強になると思うのでご自身で作成してみてください。

参考にしていただければ幸いです。

関連記事