Cocoonの人気記事ウィジェットには表示している記事やカテゴリアーカイブでのカテゴリ別人気記事を表示する機能があります。

ところが、SWELLの人気記事ウィジェットは、カテゴリの絞り込み機能がありません。
検索しても、ブログパーツを使ったカテゴリ固定の機能拡張の記事は見つかりますが、Cocoonの人気記事ウィジェットのようにカテゴリ別人気記事を表示するカスタマイズは見つけられませんでした。
以前、SWELLの新着記事ウィジェットをカテゴリ別新着記事を表示できるように機能拡張しました。

その仕組みを応用して、Cocoonのカテゴリ別人気記事ウィジェットの機能をSWELLの人気記事ウィジェットを拡張して実現してみようと思いました。
もともとSWELLはカテゴリアーカイブページで、カテゴリ内の人気記事を表示する機能がありますから、必要な情報は持っているはずです。
この記事では、SWELLの人気記事ウィジェットをカテゴリ別表示できるように機能拡張するカスタマイズをご紹介します。
WordPressのウィジェットは機能拡張しやすい
WordPressのウィジェットは、WordpressのWP_Widget
classから継承して作られるのが一般的です。
SWELLのウィジェットもその流儀に従っています。
ウィジェットを機能拡張したい場合は、継承して機能追加した後に、オリジナルを置き換えればいいです。
このあたりの説明については、前回の記事でご説明しあります。
人気記事ウィジェットをカテゴリ別人気記事を表示できるように機能拡張する
カテゴリ別人気記事は、人気記事を取得する時のクエリパラメータにカテゴリ絞り込みを追加すれば実現できます。
具体的には、表示している記事が属しているカテゴリを取得、そのカテゴリをクエリパラメータで渡してあげればカテゴリ内の人気記事だけが取得できます。
ウィジェットのform()
部分に、チェックボックスを追加して、カテゴリ絞り込みのON/OFFを切り替える機能を追加します。
ウィジェットのwidget()
部分で、カテゴリ絞り込みがONの時にはクエリパラメータで現在のカテゴリを渡します。
SWELLの子テーマのfunctions.phpにそのままコピペ可能なソースは以下になります。
<?php
use \SWELL_Theme\Legacy_Widget as Widget;
function override_widget_categories() {
/**
* 人気記事一覧ウィジェット
*/
class SWELL_Popular_Posts_mod extends SWELL_Popular_Posts {
public function __construct() {
parent::__construct(
false,
$name = '[SWELL] ' . __( '人気記事', 'swell' ),
['description' => __( 'PV数の多い順で記事を表示', 'swell' ) ]
);
}
// 設定
public function form( $instance ) {
$instance = wp_parse_args( (array) $instance, [
'title' => '',
'num' => 5,
'type' => 'card_style',
'show_date' => false, // null -> falseに
'show_cat' => false, // null -> falseに
'show_views' => false, // null -> falseに
'show_big' => false, // null -> falseに
'hide_top' => false,
'hide_post' => false,
'hide_page' => false,
'hide_archive' => false,
//↓追加
'only_current_cat'=>false,
] );
Widget::text_field([
'label' => __( 'タイトル', 'swell' ),
'id' => $this->get_field_id( 'title' ),
'name' => $this->get_field_name( 'title' ),
'value' => $instance['title'],
]);
Widget::num_field([
'label' => __( '表示する投稿数', 'swell' ),
'id' => $this->get_field_id( 'num' ),
'name' => $this->get_field_name( 'num' ),
'value' => $instance['num'] ?: 5,
'step' => '1',
'min' => '1',
'max' => '10',
'size' => '3',
]);
Widget::radio_field([
// 'label' => __( '', 'swell' ),
'id' => $this->get_field_id( 'type' ),
'name' => $this->get_field_name( 'type' ),
'value' => $instance['type'] ?: 'card_style',
'choices' => [
[
'key' => 'card',
'label' => __( 'カード型', 'swell' ),
'value' => 'card_style',
],
[
'key' => 'list',
'label' => __( 'リスト型', 'swell' ),
'value' => 'list_style',
],
],
]);
Widget::check_field([
'label' => sprintf( __( '%sを表示する', 'swell' ), __( '投稿日', 'swell' ) ),
'id' => $this->get_field_id( 'show_date' ),
'name' => $this->get_field_name( 'show_date' ),
'checked' => '1' === $instance['show_date'],
]);
Widget::check_field([
'label' => sprintf( __( '%sを表示する', 'swell' ), __( 'カテゴリー', 'swell' ) ),
'id' => $this->get_field_id( 'show_cat' ),
'name' => $this->get_field_name( 'show_cat' ),
'checked' => '1' === $instance['show_cat'],
]);
Widget::check_field([
'label' => sprintf( __( '%sを表示する', 'swell' ), __( 'PV数', 'swell' ) ),
'id' => $this->get_field_id( 'show_views' ),
'name' => $this->get_field_name( 'show_views' ),
'checked' => '1' === $instance['show_views'],
]);
Widget::check_field([
'label' => __( '1位を大きく表示する', 'swell' ) . '(' . __( 'カード型でのみ有効', 'swell' ) . ')',
'id' => $this->get_field_id( 'show_big' ),
'name' => $this->get_field_name( 'show_big' ),
'checked' => '1' === $instance['show_big'],
]);
Widget::check_field([
'label' => sprintf( __( '%sを表示する', 'swell' ), __( 'カテゴリー内ランキング', 'swell' ) ),
'id' => $this->get_field_id( 'only_current_cat' ),
'name' => $this->get_field_name( 'only_current_cat' ),
'checked' => '1' === $instance['only_current_cat'],
]);
?>
<div class="swl-widgetExSetting">
<div class="__title">
<?=sprintf( esc_html__( '%sにするページを選択', 'swell' ), '<b>' . esc_html_x( '非表示', 'show', 'swell' ) . '</b>' )?>
</div>
<?php
$hide_arr = [
'hide_top' => _x( 'トップページ', 'page', 'swell' ),
'hide_post' => _x( '投稿ページ', 'page', 'swell' ),
'hide_page' => _x( '固定ページ', 'page', 'swell' ),
'hide_archive' => _x( 'アーカイブページ', 'page', 'swell' ),
];
foreach ( $hide_arr as $key => $label ) :
Widget::check_field([
'label' => $label,
'id' => $this->get_field_id( $key ),
'name' => $this->get_field_name( $key ),
'checked' => '1' === $instance[ $key ],
]);
endforeach;
?>
</div>
<?php
}
// 出力
public function widget( $args, $instance ) {
$instance = wp_parse_args( (array) $instance, [
'title' => '',
'num' => 5,
'type' => 'card_style',
'show_date' => false,
'show_cat' => false,
'show_views' => false,
'show_big' => false,
'hide_top' => false,
'hide_post' => false,
'hide_page' => false,
'hide_archive' => false,
//↓追加
'only_current_cat'=>false,
] );
// ajax時は未定義となることに注意
if ( \SWELL_Theme::is_top() && $instance['hide_top'] ) {
return;
} elseif ( is_single() && $instance['hide_post'] ) {
return;
} elseif ( is_page() && $instance['hide_page'] ) {
return;
} elseif ( is_archive() && $instance['hide_archive'] ) {
return;
}
if ( !(is_category() || is_single()) && $instance['only_current_cat'] ){
return;
}
$widget_title = $instance['title'] ?: __( '人気記事', 'swell' );
$list_args = [
'widget_type' => 'ranking',
'list_type' => $instance['type'],
'show_date' => $instance['show_date'],
'show_cat' => $instance['show_cat'],
'show_views' => $instance['show_views'],
'show_big' => $instance['show_big'],
];
// クエリ生成
$query_args = [
'post_status' => 'publish',
'meta_key' => SWELL_CT_KEY,
'orderby' => 'meta_value_num',
'order' => 'DESC',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
'posts_per_page' => (int) $instance['num'],
];
// 人気記事一覧で除外指定が有効なのはタグのみ
$exc_tag = explode( ',', \SWELL_Theme::get_setting( 'exc_tag_id' ) );
if ( ! empty( $exc_tag ) ) {
$query_args['tag__not_in'] = $exc_tag;
}
$include_children = 0;
$taxonomy = 'category';
//現在のカテゴリを取得
$categories = array();
if ( ! empty( $instance['only_current_cat'] ) ) {
$categories = get_category_ids();//カテゴリ配列の取得
$query_args['tax_query'] = array(
'relation' => 'AND',
array(
'taxonomy' => $taxonomy,
'terms' => $categories,
'include_children' => $include_children,
'field' => 'term_id',
'operator' => 'IN',
),
);
}
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
echo $args['before_widget'];
echo $args['before_title'] . apply_filters( 'widget_title', $widget_title ) . $args['after_title'];
// 投稿一覧
\SWELL_Theme::get_parts( 'parts/post_list/loop_by_widget', [
'query_args' => $query_args,
'list_args' => $list_args,
] );
echo $args['after_widget'];
}
}
unregister_widget( 'SWELL_Popular_Posts' );
register_widget( 'SWELL_Popular_Posts_mod' );
}
add_action( 'widgets_init', 'override_widget_categories',99 );
//現在のカテゴリをカンマ区切りテキストで取得する
if ( !function_exists( 'get_category_ids' ) ):
function get_category_ids(){
if ( is_single() ) {//投稿ページでは全カテゴリー取得
$categories = get_the_category();
$category_IDs = array();
foreach($categories as $category):
array_push( $category_IDs, $category -> cat_ID);
endforeach ;
return $category_IDs;
} elseif ( is_category() ) {//カテゴリページではトップカテゴリーのみ取得
$obj = get_queried_object();
return array( $obj->cat_ID );
}
return null;
}
endif;
まとめ
SWELLとCocoonを比べると、Cocoonの方がやはり多機能というか多様性があると感じがします。
SWELLのサイトは金太郎あめのように同じサイトばかりでちょっと食傷気味になりますよね。
テーマをカスタマイズをするのに疲れた人か、興味が無い人、その知識が無い人がSWELLのユーザーの大部分なのかなと思います。
SWELLはユーザーのカスタマイズの記事が殆どなく、使い方のアフィリエイト記事ばかりです。
SWELLはGPL100%のテーマですが、githubでのソースコードは公開されなくなりました。

もう少し、機能拡張の可能性を残し、ユーザーごとの多様性を許容しないと、枯れたSEOテクニックと同じでサイト毎に差別化できない金太郎あめテーマになり、ユーザー離れが起きる可能性があります。
SANGO開発者が書いた、SANGOとSWELLを比較した記事が大変興味深いので、一読をおススメします。

コメント