SWELLカスタマイズ|新着記事ウィジェットをカテゴリ別新着記事に対応させる

Cocoonの新着記事ウィジェットにはカテゴリ別新着記事の機能があります。

SWELLの新着記事ウィジェットはカスタマイザー内にカテゴリ除外の機能はありますが、カテゴリ別新着記事の機能はありません。
Cocoonユーザーでもある私は、記事を表示している時の新着記事ウィジェットは、その記事が属するカテゴリ内の新着記事を表示させたいと思いました。
SWELLの新着記事ウィジェットのソースコードを拝見したところ、それほど大きな修正をせずにカテゴリ別新着記事を表示できるように拡張できたので、この記事でご紹介します。
この記事を書いた後に、SWELLのブロックを使った同じような記事を見つけました。その記事の内容では表示しているカテゴリに記事一覧のカテゴリが自動追従しないので、この記事のカスタマイズの内容とは異なります。
SWELL 新着記事ウィジェットに機能を追加するには?
基本的な考え方
SWELLのウィジェットは、WordpressのWP_Widget
classから継承して作られています。
基本構造はこのようになっています。
class SWELL_New_Posts extends WP_Widget {
public function __construct() {
parent::__construct(
false,
$name = '[SWELL] ' . __( '新着記事', 'swell' ),
['description' => __( '新着順で記事を表示', 'swell' ) ]
);
}
:
:
}
SWELLのウィジェットを拡張する場合の手順
SWELLのウィジェットを拡張する場合の手順は以下のようになります。
- 機能拡張したいSWELLのウィジェットから継承
- 新たに機能を追加
- SWELLのウィジェットに置き換える
class SWELL_New_Posts_mod extends SWELL_New_Posts {
public function __construct() {
parent::__construct(
false,
$name = '[SWELL] ' . __( '新着記事', 'swell' ),
['description' => __( '新着順で記事を表示', 'swell' ) ]
);
}
:
ここを書き換える
:
:
}
SWELLの新着記事ウィジェットを置き換える
SWELLのウェジェットは、widgets_init
アクションフックで読み込まれます。
ウィジェットを置き換える場合はwidgets_init
アクションフックで、SWELLのウィジェットをunregister_widget()
で削除して、機能拡張したウィジェットをregister_widget()
で読み込めば置き換えられます。
子テーマのfunctions.phpにウィジェットのclass定義と、読み込み部分を追加すれば置き換えられます。
use \SWELL_Theme\Legacy_Widget as Widget;
function override_widget_categories() {
/**
* 最新記事一覧ウィジェット
*/
class SWELL_New_Posts_mod extends SWELL_New_Posts {
public function __construct() {
parent::__construct(
false,
$name = '[SWELL] ' . __( '新着記事', 'swell' ),
['description' => __( '新着順で記事を表示', 'swell' ) ]
);
}
}
unregister_widget( 'SWELL_New_Posts' ); // SWELLのウィジェットを削除
register_widget( 'SWELL_New_Posts_mod' ); // 機能追加版に置き換える
}
add_action( 'widgets_init', 'override_widget_categories',99 ); // 100より小さくないと動かない
新着記事ウィジェットにカテゴリ別新着記事表示を追加
カスタマイズ内容
カテゴリ別新着記事は、新着記事を取得する時のクエリパラメータにカテゴリ絞り込みを追加すれば実現できます。
具体的には、表示している記事が属しているカテゴリを取得、そのカテゴリをクエリパラメータで渡してあげればカテゴリ内の新着記事だけが取得できます。
ウィジェットのform()
部分に、チェックボックスを追加して、カテゴリ絞り込みのON/OFFを切り替える機能を追加します。
ウィジェットのwidget()
部分で、カテゴリ絞り込みがONの時にはクエリパラメータで現在のカテゴリを渡します。
カスタマイズコード
SWELLの子テーマのfunctions.phpにそのままコピペ可能なソースは以下になります。
コピペできるソース
<?php
use \SWELL_Theme\Legacy_Widget as Widget;
function override_widget_categories() {
/**
* 最新記事一覧ウィジェット
*/
class SWELL_New_Posts_mod extends SWELL_New_Posts {
public function __construct() {
parent::__construct(
false,
$name = '[SWELL] ' . __( '新着記事', 'swell' ),
['description' => __( '新着順で記事を表示', '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に
'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' ), __( '現在のカテゴリーのみ', '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, // null -> falseに
'show_cat' => false, // null -> 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' );
// クエリ生成
$query_args = [
'post_status' => 'publish',
'no_found_rows' => true,
'ignore_sticky_posts' => true,
'posts_per_page' => (int) $instance['num'],
];
// 除外するカテゴリー・タグ
$exc_cat = explode( ',', \SWELL_Theme::get_setting( 'exc_cat_id' ) );
$exc_tag = explode( ',', \SWELL_Theme::get_setting( 'exc_tag_id' ) );
if ( ! empty( $exc_cat ) ) {
$query_args['category__not_in'] = $exc_cat;
}
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',
),
);
}
$list_args = [
'widget_type' => 'new',
'list_type' => $instance['type'],
'show_date' => $instance['show_date'],
'show_cat' => $instance['show_cat'],
];
// 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_New_Posts' );
register_widget( 'SWELL_New_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;

参照情報
このカスタマイズは、Cocoonの新着記事ウィジェットのソースを参考・一部流用させていただいています。
この場を借りて、@MrYhira氏には感謝申し上げます。
参考:https://github.com/xserver-inc/cocoon/blob/d800ecc37ab15509cb041e037ad8246a7616e148/lib/utils.php
まとめ
SWELLのウィジェットの継承で機能拡張しているので、親テーマを修正せずにカスタマイズできます。
Cocoonと同じように、ラジオボタンにすればよかったと思いましたが、チェックボックスで作ってしまって後悔しています。
この方法を使えば簡単に人気記事ウィジェットもカテゴリ絞り込みに対応できるので、興味がある方はチャレンジしてみてください。

コメント