How to filter popular_list in Cocoon by tag id?

Cocoon

This blog page uses “Cocoon” as theme, which is famous in Japan.

I added function to this theme so that we can show “popolar_list” by filtering tag id.

This is what I introduced in Twitter.
– Sorry for Japanese.

How to implement 

 I added some code to child theme to avoid affecting parant theme.

Existing implementation of showing “popular_list” is

  1. popular_entries_shortcode is called.
  2. generate_popular_entries_tag is called in popular_entries_shortcode.
  3. get_access_randking_records is called in generate_popular_entries_tag.



To visualize, you can see this structure.

 popular_entries_shortcode
  -> generate_popular_entries_tag
    -> get_access_ranking_records



These 3 functions are implemented in parent theme and are considered to customize like below.

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



So the best strategy to add function is below.
– Copying corresponding functions from parent theme to child theme functions.php
– Modifying source code of funtions.php

 Code modification

 Let’s see actual source code which I implemented.
* Please be noted that Cocoon is on development now so there will be update. So source code in this article and actual source code in Cocoon may differ.



Firstly popular_entries_shortcode.
I show code diffs with symbol “+” and “-” which seems “diff -ruN”.
Do not include “+” and “-” to source code in your case.

“tags” is added in attribute as well as “cats”.
If both are in short code, cats are higher priority.

 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();
  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;



Next is “generate_popular_entries_tag”.
This is also easy to understand, just adding “tag_ids” and “excluding_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);
(snip)



Lastly modify “get_access_ranking_records”. 

 //アクセスランキングを取得
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()) {
(略)
    $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;
(snip)
  //カテゴリを指定する場合
  if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(snip)
+  // In case specifying tag id
+  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';
+    //specifying tag id to be included
+    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;
+    }
+    //specifying excluding tag id
+    if (is_ids_exist($exclude_cat_ids)) {
+      //remove empty arrays
+      $exclude_tag_ids = array_filter($exclude_tag_ids, "strlen");
+      //separating by comma
+      $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;
+(snip - do same as category)
  } 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);
  }



Diffs seems many lines of code, but I just added based on this way.

Before

//カテゴリを指定する場合
if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(Code of category)
} else {
(Code of non category)
}

After

//カテゴリを指定する場合
if (is_ids_exist($cat_ids) || is_ids_exist($exclude_cat_ids)) {
(Code of category)
+else if (is_ids_exist($tag_ids) || is_ids_exist($exclude_tag_ids)) {
+ (Code of tag)

} else {
(Code of non category/tag)
}



If “taxonomy” is there it was forced to category base.
I added to support tag by specifying “post_tag” like this.

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



WordPress article can be got by PHP code.
Please see this page for more detail. 



If everything is fine, you can filter popular_list by tag id.

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



 Conclusion

 How was it?

I modified because I want this function.

I am very happy if this customization is useful for you!

Author
yatch

I am software engineer at foreign company in Japan.
My experience of embedded software is over 15 years.
I was in charge of designing of software which has embedded linux.
I love Raspberry Pi.
I earn 10000USD per year on the stock market.
I married Hong Konger.

Please follow me
CocoonWordpress
Please follow me
The World's Linux Journal

Comments

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