BOGOでカテゴリーウィジェットの投稿数を言語に合わせる方法

2021年4月18日

こんにちは。「Javaを復習する初心者」です。最近、サイトの多言語化に挑戦しました。WordpressにはBOGOという多言語化のプラグインがあります。このプラグインを使うと、日本語のトップページ、英語のトップページという切り替えができます。

カテゴリーウィジェットには投稿数を表示するというオプションがあります。BOGOを使った場合、この投稿数は言語別になっていません。今回は、この投稿数を表示中のページの言語に合わせる方法を考えました。

スポンサーリンク

確認時の環境

Windows 10のノートPCにXAMPPをインストールして、Wordpressを表示させています。

今回実験に使ったWordpressについては、以下の状況です。

  • WordPress 5.6.2
  • BOGO 3.5
  • 親テーマ:Twenty Twenty-One 1.1
  • 子テーマ:上記を親テーマにしただけのもの

子テーマはstyle.cssとfunctions.phpを格納しただけのものです。

今回は子テーマのfunction.phpに記述を追加して、カテゴリーウィジェットに表示される投稿数を言語で切り替えるということをしました。

BOGOの言語設定は次のようにしました。

Language Status
Japanese [ja] Site Language
English (United States) [en_US] Active

サイトの言語は日本語、翻訳先の言語は英語だけ追加しているという設定です。

カテゴリーと記事の状況

カテゴリーは以下のように作成しました。

カテゴリー0001
- カテゴリー0001-0001
- カテゴリー0001-0002

カテゴリー0001が2つの子カテゴリーを持つという状態です。

上記の英語の翻訳を以下のように設定しました。

日本語 英語
カテゴリー0001 category0001
カテゴリー0001-0001 category0001-0001
カテゴリー0001-0002 category0001-0002

記事は次のように作りました。

記事タイトル 言語 カテゴリー
タイトル:0001 ja カテゴリー0001-0001
タイトル:0010 ja カテゴリー0001-0001
title: 0001 en_US カテゴリー0001-0001
タイトル:0011 ja カテゴリー0001-0002

カテゴリー0001-0001には日本語の記事が10件、英語の記事が1件あります。カテゴリー0001-0002には日本語の記事が1件あります。カテゴリー0001-0002の英語の記事が0件です。

カテゴリー 日本語記事数 英語記事数
カテゴリー0001-0001 10 1
カテゴリー0001-0002 1 0

BOGOの日本語ページ、英語ページそれぞれカテゴリーウィジットで投稿数を表示させると、言語の区別をしないで記事を合計した数字が表示されます。

日本語ページ

カテゴリー0001 (12)
 カテゴリー0001-0001 (11)
 カテゴリー0001-0002 (1)
英語ページ

category0001 (12)
 category0001-0001 (11)
 category0001-0002 (1)

要するに日本語ページ、英語ページで同じ件数が表示されます。

注目個所

どのようにカテゴリーウィジットの投稿数を変更すればよいか、このウィジットで呼び出される関数の処理を大まかに追いました。

wp-includesフォルダのcategory-template.phpにwalk_category_tree()という関数が定義されています。この関数が呼び出されていることがわかりました。

以下のように定義されています。

walk_category_tree()の抜粋

function walk_category_tree( …$args ) {
	// The user’s options are the third parameter.
	if ( empty( $args[2]['walker’] ) || ! ( $args[2]['walker’] instanceof Walker ) ) {
		$walker = new Walker_Category;
	} else {
		/**
		 * @var Walker $walker
		 */
		$walker = $args[2]['walker’];
	}
	return $walker->walk( …$args );
}

引数の$args[0]には、WP_Term Objectの配列が格納されています。今回の状況では以下のように格納されています。

$argsのindex 0

Array
(
    [0] => WP_Term Object
        (
            [term_id] => 2
            [name] => カテゴリー0001
            [slug] => cat-0001
            [term_group] => 0
            [term_taxonomy_id] => 2
            [taxonomy] => category
            [description] => 
            [parent] => 0
            [count] => 12
            [filter] => raw
            [cat_ID] => 2
            [category_count] => 12
            [category_description] => 
            [cat_name] => カテゴリー0001
            [category_nicename] => cat-0001
            [category_parent] => 0
        )

    [1] => WP_Term Object
        (
            …
        )

    [2] => WP_Term Object
        (
            …
        )

)

countというプロパティがあり、カテゴリーウィジットで表示される投稿数はこの値のようです。

if-else文では引数の$args[2]['walker]にWalkerクラスのインスタンスが格納されている場合、それを取り出すということをしています。カテゴリーウィジットの場合、$args[2]['walker]は空です。上記のif文のブロックの方に処理が進みます。Walker_Categoryというクラスについて調べてみると、表示用のhtmlを生成する役割をしているのがわかりました。

Walker_Categoryはclass-walker-category.phpに定義されています。コメントに以下の記述が見つかりました。

Core class used to create an HTML list of categories.

変数$walkerにインスタンスを格納し、walkメソッドを呼び出しています。上記のコメントの通り、このメソッドでhtmlが返却されるようです。

ここで思いついたのは、Walker_Categoryクラスを継承したクラスをあらかじめ定義しておき、walkメソッドをオーバーライドする方法です。$args[2]['walker’] にそのクラスのインスタンスを格納できれば、そのインスタンスのwalkメソッドを呼び出してくれます。

この関数の呼び出し元を調べると、以下のようにapply_filters()関数が使われている個所がありました。

ソース

	public function widget( $args, $instance ) {
		.
		.
		.
				wp_list_categories( apply_filters( 'widget_categories_args’, $cat_args, $instance ) );
		.
		.
		.
	}

調べてみると、walk_category_tree()の引数$argsの$args[2]が上記の$cat_argsでした。そのため、フィルター関数を追加して、$cat_argsを変更することができます。

実装

以下の方針で実装しようと思いつきました。

  1. Walker_Categoryクラスを拡張したクラスを作成し、walk()メソッドをオーバーライドする。walk()メソッドでカテゴリーのカウントを変更する。
  2. フィルター関数を使い、wp_list_categories()メソッドの引数$cat_argsに上記クラスのインスタンスを格納する。

BOGOが有効になっている前提で、子テーマのfunctions.phpに以下のプログラムを記載しました。

ソース

// クラスを拡張
class My_Walker_Category extends Walker_Category {
    public function walk( …$args ) {

        // 言語別に全件検索するための設定
        $get_posts_arg = array(
            'suppress_filters’ => false,
            'numberposts’      => -1,
        );

        foreach ( $args[0] as $key => $obj ) {
            // カテゴリーを指定するための設定
            $get_posts_arg[ 'category’ ] = $obj ->cat_ID;

            // 件数取得
            $count = count( get_posts( $get_posts_arg ) );

            if ( 0 == $count) {
                // 0件の場合、配列からオブジェクト削除する。
                unset( $args[0][$key] );
            } else {
                // それ以外の場合、プロパティの値を変更する。
                $args[0][$key]->count = $count;
            }
        }

        return parent::walk( …$args );
    }
}

// フィルター
function widget_categories_args_my_filter( $cat_args, $instance ) {
    // インスタンスを格納する。
    $cat_args['walker’] = new My_Walker_Category;

    return $cat_args;
}

add_filter( 'widget_categories_args’, 'widget_categories_args_my_filter’, 10, 2 );

以下のようにカテゴリーの投稿数の表示が変わりました。

日本語ページ

カテゴリー0001 (11)
 カテゴリー0001-0001 (10)
 カテゴリー0001-0002 (1)
英語ページ

category0001 (1)
 category0001-0001 (1)

My_Walker_Categoryクラスのwalk()メソッドでは、引数を調節して、継承元のwalk()メソッドを呼び出しています。

今回はカテゴリーの記事数を変更することなので、引数に含まれるWP_Term Objectのcountプロパティを変更しています。記事数の取得には、get_posts()メソッドを使いました。配列が返却されるので、count()メソッドで配列の長さを取得しています。

BOGOを有効化している場合、get_posts()メソッドに渡す引数の設定を調節することで、現在表示されているページの言語の記事を取得することができます。具体的には引数のプロパティsuppress_filtersをfalseにすることで、BOGOが表示中の言語を検索条件に付いてしてくれるようです。

$countに検索件数を格納し、条件分岐させています。記事数が0件のカテゴリーを表示させないための処理が必要だったからです。例えば、今回の場合は「カテゴリー0001-0002」は日本語の記事が1件、英語の記事が0件の状態です。なので、英語ページのカテゴリーウィジットでは、「カテゴリー0001-0002」自体を表示しないようにするということです。unset()メソッドを使って、配列から対象のWP_Term Objectを削除しています。

widget_categories_args_my_filter()メソッドでは、$cat_argsにMy_Walker_Categoryクラスのインスタンスを格納しています。これで、このインスタンスがwalk_category_tree()メソッドで使われます。

上記のようにプログラムを書いてみたのですが、get_posts()メソッドは処理が重いらしく、記事数とカテゴリー数が多いと画面の表示が遅くなりました。

以上、参考になれば幸いです。

スポンサーリンク