【WordPress】パンくずリストの作り方

2021年4月12日
パンくずリスト

WordPressで固定ページの親子関係とカテゴリのスラッグに基づいて表示できるパンくずリストを作成した。

前提

下記を定義済みの想定とする。

手順

パンくずリストのデータを管理するクラスを定義する

下記のクラスを定義する。

final class BreadcrumbItemData 
{
    public $name    = '';
    public $uri     = '';

    /**
     * コンストラクタ
     * @param $name 名前
     * @param $uri  URI
     */
    public function __construct( $name, $uri ) 
    {
        $this->name = $name;
        $this->uri  = $uri;
    }
}

パンくずリストを表示するクラスを定義する

下記のクラスを定義する。

final class BreadcrumbList extends StaticClass 
{
    private static function get_page_id_list() 
    {
        return [];
    }

    public static function show() 
    {
        $item_datas = is_page() ? self::get_item_datas_for_page() : self::get_item_datas_for_post();
        self::show_list( $item_datas );
    }

    private static function show_list( $item_datas ) 
    {
        if ( $item_datas === [] ) return;

        echo '<nav><ol class="breadcrumb-list" itemscope itemtype="https://schema.org/BreadcrumbList">';
        self::show_items( $item_datas );
        echo '</ol></nav>';
    }

    private static function show_items( $item_datas ) 
    {
        $number = 1;

        foreach ( $item_datas as $data ) 
        {
            if ( $data->uri === '' ) 
            {
                self::show_item_without_link( $data->name );
            }
            else 
            {
                self::show_item( $data->name, $data->uri, $number );
                ++$number;
            }
        }
    }

    private static function show_item( $name, $uri, $number ) 
    {
        echo <<< EOT
<li class="item" itemprop="itemListElement" itemscope itemtype="https://schema.org/ListItem">
    <a class="hover-text-line" itemprop="item" href="$uri">
        <span itemprop="name">$name</span>
    </a>
    <meta itemprop="position" content="$number">
</li>
EOT;
    }

    private static function show_item_without_link( $name ) 
    {
        printf( '<li class="item">%s</li>', $name );
    }

    private static function get_item_datas_for_post() 
    {
        $categories = self::get_categories_by_family_order();
        if ( $categories === [] ) return [];

        $page_id_list   = self::get_page_id_list();
        $on_map         = function( $category ) use ( $page_id_list )
        {
            $id     = $page_id_list[ $category->slug ];
            $name   = get_post( $id )->post_title;
            $uri    = get_permalink( $id );
            
            return new BreadcrumbItemData( $name, $uri );
        };
        
        $datas = array_map( $on_map, $categories );
        array_unshift( $datas, new BreadcrumbItemData( 'ホーム', self::get_home_uri() ) );

        return $datas;
    }

    private static function get_item_datas_for_page() 
    {
        $datas              = [ new BreadcrumbItemData( 'ホーム', self::get_home_uri() ) ];
        $current_article    = get_post();
        $target_article     = $current_article;

        while ( $target_article->post_parent !== 0 ) 
        {
            $parent_id      = $target_article->post_parent;
            $parent_article = get_post( $parent_id );
            $parent_name    = $parent_article->post_title;
            $parent_uri     = get_permalink( $parent_id );

            $datas[]        = new BreadcrumbItemData( $parent_name, $parent_uri );
            $target_article = $parent_article;
        }

        $datas[] = new BreadcrumbItemData( $current_article->post_title, "" );
        return $datas; 
    }

    private static function get_categories_by_family_order() 
    {
        $descendant = self::get_descendant_category();
        if ( is_null( $descendant ) ) return [];

        $ancestor_ids   = get_ancestors( $descendant->term_id, 'category' );
        $ancestor_ids   = array_reverse( $ancestor_ids );
        
        $categories     = array_map( fn( $id ) => get_category( $id ), $ancestor_ids );
        $categories[]   = $descendant;
        
        return $categories;
    }

    private static function get_descendant_category() 
    {
        $categories = get_the_category();
        if ( $categories === [] ) return null;

        $descendant = array_shift( $categories );

        foreach ( $categories as $category ) 
        {
            if ( !cat_is_ancestor_of( $descendant, $category ) ) continue;
            $descendant = $category;
        }

        return $descendant;
    }

    private static function get_home_uri() 
    {
        $uri = home_url();
        return esc_url( $uri );
    }
}

get_page_id_list関数内のリストに要素を追加する

パンくずリストの項目を表示するため、パンくずリストを表示するクラス( BreadcrumbList )の5行目に定義されている、get_page_id_list関数のリストに「カテゴリのスラッグ」をキー、「固定ページのID」を値とした要素を追加する。

private static function get_page_id_list() 
{
    // カテゴリのスラッグと固定ページのIDを関連付けたリスト
    return [
        'hoge' => 111,
        'fuga-in-hoge' => 123,
        'piyo' => 987,
    ];
}

表示させたい箇所で関数を呼ぶ

表示させたい箇所で下記の関数を呼ぶ。

BreadcrumbList::show();

これで下記のようなHTMLを出力できる。

<nav>
    <ol class="breadcrumb-list" itemscope="" itemtype="https://schema.org/BreadcrumbList">
        <li class="item" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
            <a class="hover-text-line" itemprop="item" href="http://test">
                <span itemprop="name">ホーム</span>
            </a>
            <meta itemprop="position" content="1">
        </li>
        <li class="item" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
            <a class="hover-text-line" itemprop="item" href="http://test/hoge/">
                <span itemprop="name">Hoge</span>
            </a>
        <meta itemprop="position" content="2">
        </li>
        <li class="item" itemprop="itemListElement" itemscope="" itemtype="https://schema.org/ListItem">
            <a class="hover-text-line" itemprop="item" href="http://test/hoge/fuga/">
                <span itemprop="name">Fuga</span>
            </a>
            <meta itemprop="position" content="3">
        </li>
    </ol>
</nav>

CSSで見た目を整える

出力されたHTMLの各要素に付いているクラスを用いて、CSSで見た目を整える。

これでパンくずリストは完成となる。

パンくずリスト

関連ページ

参考ページ