お問い合わせ

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/ef9954a12d4fbe768cc9f1b9c5dd99a8eecd747f/lib/widgets/new-entries.php

参考:https://github.com/xserver-inc/cocoon/blob/ad70b2101063e435e6cbde024b0b371ba2ca1689/lib/html-forms.php

参考:https://github.com/xserver-inc/cocoon/blob/d800ecc37ab15509cb041e037ad8246a7616e148/lib/utils.php

まとめ

SWELLのウィジェットの継承で機能拡張しているので、親テーマを修正せずにカスタマイズできます。

Cocoonと同じように、ラジオボタンにすればよかったと思いましたが、チェックボックスで作ってしまって後悔しています。

注意点としては、もとからあるSWELL新着記事ウィジェットは一度ウィジェットエリアから除外されてしまうので、もう一度設定する必要があります。

この方法を使えば簡単に人気記事ウィジェットもカテゴリ絞り込みに対応できるので、興味がある方はチャレンジしてみてください。

役に立ったら他の人にもシェア!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

Wordpressのカスタマイズ歴10年のプロです。無料から有料までWordpressテーマの使用経験は豊富。SWELLやCocoon、Snowmonkey、Arkheなどテーマのカスタマイズに関する知見も深い。Webサイト制作からカスタマイズまで仕事を請け負った実績は多数あり。
第二種情報処理技術者試験(合格率:15.5%)、Google アナリティクス上級者向けコースGoogle タグ マネージャーの基礎コース上級ウェブ解析士HTML5プロフェッショナル認定 レベル2

コメントを閉じる

コメント

コメントする

コメントは日本語で入力してください。(スパム対策)

この記事の内容