Cocoonの人気記事popular_listでタグ指定を可能にする方法

Cocoon

このサイトはWordPressのテーマ「Cocoon」を使っています。

人気記事表示機能popular_listでタグ指定での絞り込みを行えるようソースコード修正して対応したので、やり方を載せておきます。

対応すると下記ツイートの通り人気記事をタグで絞り込むことができます。

popular_listでタグ指定を可能にする方法

子テーマ側に既存関数を修正実装して実現します。
 親テーマ側に影響を与えないようにするため。

既存の実装は、popular_entries_shortcodeとgenerate_popular_entries_tagでショートコードから各属性の値を取り出し、get_access_ranking_recordsでWordPressデータベースから記事情報を取り出しています。

呼び出し構造はこんな感じ。

popular_entries_shortcode
 generate_popular_entries_tag
  get_access_ranking_records



↑の3関数は既に親テーマ側に実装されていますが、いずれも

if ( !function_exists( 'get_access_ranking_records' ) ):
function get_access_ranking_records(略

というように子テーマ側での関数カスタマイズが考慮済なので、
 ・親テーマから関数を子テーマのfunctions.phpにコピー
 ・必要部分を修正
というやり方が最も楽に対応できると思います。

実際にやってみた

ここから実際のコードを見ながら修正していきましょう。
※Cocoonは現在も更新がされていますが、それに伴いこれらのソースコードが修正されることがあります。この記事で紹介したコードと一致しない可能性があります。ご注意ください。



まずpopular_entries_shortcodeです。
差分はdiff -ruNっぽく +- で表示しています。
実際のソースコードには含めないので注意。

まあ簡単ですね。
cats属性と同様にtags属性を指定できるようにします。
catsとtags両方指定された場合はcats優先とします。

2022/01/20更新
$tag_idsの初期化が漏れていたので、追加しました。
 Risa Yazawaさん、ありがとうございます!

if ( !function_exists( 'popular_entries_shortcode' ) ):
function popular_entries_shortcode($atts) {
  extract(shortcode_atts(array(
    'days' => 'all',
    'count' => 5,
    'type' => 'default',
    'rank' => 0,
    'pv' => 0,
    'cats' => 'all',
    'children' => 0,
+    'tags' => 'all',
    'bold' => 0,
    'arrow' => 0,
    'class' => null,
  ), $atts, 'popular_list'));
  $cat_ids = array();
+  $tag_ids = array(); // 2022/01/20追加
  if ($cats && $cats != 'all') {
    $cat_ids = explode(',', $cats);
  }
+  else if ($tags && $tags != 'all') {
+    $tag_ids = explode(',', $tags);
+  }
  $atts = array(
    'days' => $days,
    'entry_count' => $count,
    'entry_type' => $type,
    'ranking_visible' => $rank,
    'pv_visible' => $pv,
    'cat_ids' => $cat_ids,
    'children' => $children,
+    'tag_ids' => $tag_ids,
    'bold' => $bold,
    'arrow' => $arrow,
    'class' => $class,
  );
  ob_start();
  generate_popular_entries_tag($atts);
  //_v($atts);
  //generate_popular_entries_tag($days, $count, $type, $rank, $pv, $categories);
  $res = ob_get_clean();
  return $res;
}
endif;



お次はgenerate_popular_entries_tagです。
こちらも単純にtag_ids/exclude_tag_idsによるタグ指定を追加しただけ。

//人気ランキングリストの取得
if ( !function_exists( 'generate_popular_entries_tag' ) ):
function generate_popular_entries_tag($atts){
  extract(shortcode_atts(array(
    'days' => 'all',
    'entry_count' => 5,
    'entry_type' => ET_DEFAULT,
    'ranking_visible' => 0,
    'pv_visible' => 0,
    'cat_ids' => array(),
    'children' => 0,
+    'tag_ids' => array();
    'exclude_post_ids' => array(),
    'exclude_cat_ids' => array(),
+    'exclude_tag_ids' => array(),
    'bold' => 0,
    'arrow' => 0,
    'class' => null,
  ), $atts));

-  $records = get_access_ranking_records($days, $entry_count, $entry_type, $cat_ids, $exclude_post_ids, $exclude_cat_ids, $children);
+  $records = get_access_ranking_records($days, $entry_count, $entry_type, $cat_ids, $tag_ids, $exclude_post_ids, $exclude_cat_ids, $exclude_tag_ids, $children);
(略)



これで最後。
get_access_ranking_recordsを修正します。
2022/01/20更新
$tagsの初期化が漏れていたので、追加しました。
 Risa Yazawaさん、ありがとうございます!

//アクセスランキングを取得
if ( !function_exists( 'get_access_ranking_records' ) ):
-function get_access_ranking_records($days = 'all', $limit = 5, $type = 'post', $cat_ids = array(), $exclude_post_ids = array(), $exclude_cat_ids = array(), $children = 0){
+function get_access_ranking_records($days = 'all', $limit = 5, $type = 'post', $cat_ids = array(), $tag_ids = array(), $exclude_post_ids = array(), $exclude_cat_ids = array(), $exclude_tag_ids = array(), $children = 0){
(略)

  //アクセスキャッシュを有効にしている場合
  if (is_access_count_cache_enable()) {
(略)
    $tags = implode(',', $tag_ids); //2022/01/20追加

    //除外投稿
    $archive_exclude_post_ids = get_archive_exclude_post_ids();
    if ($archive_exclude_post_ids && is_array($archive_exclude_post_ids)) {
      $exclude_post_ids = array_unique(array_merge($exclude_post_ids, $archive_exclude_post_ids));
    }

    $expids = implode(',', $exclude_post_ids);
    $excats = implode(',', $exclude_cat_ids);
+    $extags = implode(',', $exclude_tag_ids);
    $type = get_accesses_post_type();
-    $transient_id = TRANSIENT_POPULAR_PREFIX.'?days='.$days.'&limit='.$limit.'&type='.$type.'&cats='.$cats.'&children='.$children.'&expids='.$expids.'&excats='.$excats;
+    $transient_id = TRANSIENT_POPULAR_PREFIX.'?days='.$days.'&limit='.$limit.'&type='.$type.'&cats='.$cats.'&tags='.$tags.'&children='.$children.'&expids='.$expids.'&excats='.$excats.'&extags='.$extags;
(略)
  //カテゴリを指定する場合
  if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(略)
+  //タグを指定する場合
+  else if (is_ids_exist($tag_ids) || is_ids_exist($exclude_tag_ids)) {
+    global $post;
+    $term_relationships = $wpdb->term_relationships;
+    $term_taxonomy = $wpdb->term_taxonomy;
+    $joined_table = 'terms_accesses';
+    //タグ指定
+    if (is_ids_exist($tag_ids)) {
+      $tag_ids = implode(',', $tag_ids);
+      //$where .= " AND {$term_relationships}.term_taxonomy_id IN ({$tag_ids}) ".PHP_EOL;
+      $where .= " AND {$term_taxonomy}.term_id IN ({$tag_ids}) ".PHP_EOL;
+    }
+    //除外タグ指定
+    if (is_ids_exist($exclude_cat_ids)) {
+      //空の配列を取り除く
+      $exclude_tag_ids = array_filter($exclude_tag_ids, "strlen");
+      //カンマ区切りにする
+      $ex_tag_ids = implode(',', $exclude_tag_ids);
+      $ex_tag_ids = preg_replace('/,$/', '', $ex_tag_ids);
+      $where .= " AND {$term_relationships}.term_taxonomy_id NOT IN ({$ex_tag_ids}) ".PHP_EOL;
+    }
+
+    $where .= " AND {$term_taxonomy}.taxonomy = 'post_tag' ".PHP_EOL;
+(略 - 前記カテゴリー指定時のコードと同じ)
  } else {
    $query = "
      SELECT {$access_table}.post_id, SUM({$access_table}.count) AS sum_count
        FROM {$access_table} $where
        GROUP BY {$access_table}.post_id
        ORDER BY sum_count DESC
    ";
    //1回のクエリで投稿データを取り出せるようにケーブル結合クエリを追加
    $query = wrap_joined_wp_posts_query($query, $limit);
  }



追加コードが長いですが、以下のようにコード修正しただけです。
 マジメに設計するのがだるかったので、手抜き。

修正前

//カテゴリを指定する場合
if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(カテゴリ指定時のコード)
} else {
(カテゴリ指定しない時のコード)
}


修正後

//カテゴリを指定する場合
if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(カテゴリ指定時のコード)
+else if (is_ids_exist($tag_ids) || is_ids_exist($exclude_tag_ids)) {
+ (タグ指定時のコード)

} else {
(カテゴリ、タグ指定しない時のコード)
}



taxonomy指定時にカテゴリの場合はcategoryとしますが、タグの場合はpost_tagとします。
こんな感じ。

$where .= " AND {$term_taxonomy}.taxonomy = 'post_tag' ".PHP_EOL;



WordPress記事は全てデータベースに入っていてPHPから中身を取り出せるようになっています。
詳細はこのページなどを見ていただくとわかります。



すべてうまく行っていれば、以下のようなショートコードでタグ指定ができます。

[popular_list count="2" type="border_square" tags="271"]



終わりに

いかがでしたか。

私の使い方ではどうしてもタグでの人気記事絞り込みをやりたかったので、実装しました。

この記事が役に立ったら嬉しいです!

この記事を書いた人
yatch

組込ソフト歴15年の外資系エンジニア。
前職で組込Linuxを使った商品設計/品質確保の業務に従事。
Raspberry Piが好き。
株式投資で年100万円を稼ぐ。
妻は香港人(国際結婚)。

Please follow me
CocoonWordpress
Please follow me
世界Linux新聞

Comments

  1. あひ より:

    こちらを参考に、実装に成功しました。どうもありがとうございます。

    • yatch yatch より:

      あひさん
      コメントありがとうございます!
      機能実装できたということで、私も嬉しいです!

  2. あひ より:

    お返事どうもありがとうございます。運用して一週間程度経ち、気づいたことをご報告します。php初心者なので、わたしの記述ミスの可能性もかなりありますが、なにとぞご容赦ください。

    ショートコードは、パソコンだと問題なく表示されます。同じページの中にいくつかリストを入れても、問題なく作動します。

    ですが、スマホから見ると、違うタグのリストが表示されてしまうことに気づきました。
    具体的には、1,2,3というidのタグを使っています。パソコンでは問題なく表示されますが、スマホで見ると、どのリストでも、一番最後にショートコードを書いたリストが表示されます。1のリストを記述した記事を更新したら、ショートコードが2や3を指定しても、全部1が表示されます。

    パソコンでは問題なく表示されているので、もしかしてスマホだと別の指定があるのかな、とも思ったのですが、いかんせん初心者なので追及できずにいます。

    以上、何かお役に立てばと思いご報告いたします。リンクには、この現象が起きているページを貼っておきます。

    • yatch yatch より:

      ありがとうございます!
      気付きませんでした。
      こちらでもやってみます!

      • yatch yatch より:

        あひさん

        ご提示いただいたURLリンクですが、スマホ・Chromebook・WindowsPCのいずれも同じように記事が表示されているように見えます。
        記事内のどの箇所で不具合が発生しているか、教えていただきたく。

        お手数ですが、お願いいたします。

        • Risa Yazawa より:

          お返事ありがとうございます。
          ページ内の「人気のフィンランドのクリスマスレシピはこちらです」と「人気のフィンランド料理はこちらです」には、それぞれ別のタグを指定しています。それぞれのタグで記事の重複はないので、全く別のランキングが表示されるはずです。
          パソコンでは正しく見えているのですが、スマホからだと2つとも同じ内容が見えてしまいます。スマホのchromeとfirefoxで試して両方とも同様に見えるのですが、私だけでしょうか。お手を煩わせてしまってすみません。

          • yatch yatch より:

            こんにちは。
            情報ありがとうございました。

            私の手持ち環境では、どの環境でも問題が発生していることがわかりました。
            ↓の動作となっていました。

            期待動作
            ■人気のフィンランドのクリスマス料理のレシピはこちらです。
             → 「フィンランドのクリスマス料理」タグの人気記事が表示される
            ■人気のフィンランド料理はこちらです。
             → 「日本でも作れるフィンランドのレシピ」タグの人気記事が表示される

            実際の動作
            ■人気のフィンランドのクリスマス料理のレシピはこちらです。
             → 「日本でも作れるフィンランドのレシピ」タグの人気記事が表示される
               (期待動作と違う)
            ■人気のフィンランド料理はこちらです。
             → 「日本でも作れるフィンランドのレシピ」タグの人気記事が表示される
               (これは期待通り)

            自分のサイト(ここ)でも似たような状態を作ってやってみます。

          • yatch yatch より:

            このサイトで以下のようにショートコードを書いてやってみましたが、期待通り表示されてしまいました。
            [popular_list count="2" type="border_square" tags="1"]
            [popular_list count="2" type="border_square" tags="2"]
             ※タグIDは実際の値と別の値として1,2としています。

            順番を逆にしても同様に正常に表示されました。

            うーん、何が原因なんだろう…

          • yatch yatch より:

            Risa Yazawaさん

            [popular_list count="2" type="border_square" tags="1"]
            ↑このような感じで、実際に埋め込んでいるショートコードを見せてもらうことはできますでしょうか。
            タグIDは1とか2といった仮の値でOKです。

            このサイトでは再現していなくて、Risaさんのところで必ず発生している、
            ということは、何かしらの有意差があるはずなので、それを捕まえたいです。

          • Risa Yazawa より:

            試していただいてありがとうございます!
            実際のショートコードは
            [popular_list days=7 rank=1 count=4 type=large_thumb tags=1]
            です。””つきでも試してみましたが変化ありませんでした。

            yatchさんの環境ではしっかり表示されたとなると、わたしのphpの修正が間違っているのが原因な気がします。初心者ながらどうしても実装したい機能で、あれこれ調べながら手探りでやったので、その可能性が大きいような気がしてきました。もう一度、記事を参考にphpの書き換えにミスがないかチェックしてみます。

          • yatch yatch より:

            情報ありがとうございます。
            うーん、やはりこのサイトでご提示いただいたコードを入れると期待通りに動作しますね…
             タグの値は変更

            Risa Yazawaさんの環境でもう一度確認してみていただいて原因がわからなければ、一度ご連絡したメールアドレスに連絡いただけますか?
            ここまで乗りかかった船ですし、解決まで持っていきたいと思って。

            PCではOKでスマホではNGというのが気になりますね。
            技術的には何らかの有意差に置き換えられるはずなのですが、今は想像がつかないです。

          • Risa Yazawa より:

            ありがとうございます!メールがスパムに振り分けられていて、ご連絡頂いていたのに今気づきました。今後はそちらに連絡させていただきます。
            ご丁寧な対応本当にありがとうございます。引き続き、どうぞよろしくお願いいたします。

          • yatch yatch より:

            メールにて相談させていただいた結果、この記事で紹介していたコードにバグがあることがわかりました。
            ■popular_entries_shortcode
             $tag_idsの初期化が漏れていたので、追加しました。
            ■get_access_ranking_records
             $tagsの初期化が漏れていたので、追加しました。

            記事内容に反映しました。

            ちなみにRisa Yazawaさんの仰っていた
             スマホだとうまく表示されない
            は、
             管理者としてログインしていない
            に置き換えることができました。
            そのため、yatchが閲覧したときはスマホだけでなくPCでも症状が出ていました。

            お付き合いくださり、誠にありがとうございました!

タイトルとURLをコピーしました