コーポレートサイトなどで「製品情報」などのコンテンツをカスタム投稿タイプで作成した時、製品の投稿一覧の上に固定ページでいろいろな説明などを記載したいと思った事はないでしょうか?

実際問題「それって『製品情報』の固定ページ作ってその固定ページ の中で『製品情報』を引っ張る投稿リストブロック配置すれば一緒じゃね?」というツッコミはごもっともだったりするのですが、受託案件などでそうもいかない時?などに有効になるのが、投稿リストの上にウィジェットエリアを設けて、そのウィジェットエリアに、テキストウィジェットや ExUnit の VK 固定ページ本文 ウィジェット を配置すれば実現できます。

その「投稿リストの上にウィジェットエリアを追加する方法」を紹介します。

この方法はテーマを問わずどのテーマでも有効です。
※世の中には全く想定しない変な作りのテーマもあるので100%どれでもというわけではないかもしれません。

この記事は「Vektor WordPress Solution Advent Calendar 2020」の12月1日の記事になります。

投稿リストの上にウィジェットエリアを追加する

子テーマのfunctions.phpなどに以下のPHPを貼り付ければOKです。

/**
* 各投稿タイプのループの前にウィジェットエリアを追加する
*/
function my_set_archive_loop_before_widget_area(){

    // 公開されている投稿タイプを呼び出し
    $postTypes = get_post_types( array( 'public' => true ) );
    // 固定ページはアーカイブないので削除
    unset( $postTypes['page'] );

    // 投稿タイプをループしながらウィジェットエリアを設定
    foreach ( $postTypes as $postType ) {

        // Get post type name
        /*-------------------------------------------*/
        $post_type_object = get_post_type_object( $postType );
        if ( $post_type_object ) {

            // Set post type name
            $postType_name = esc_html( $post_type_object->labels->name );

            // Set post type widget area
            register_sidebar(
                array(
                    'name'          => sprintf( 'アーカイブページのループ前 (%s)', $postType_name ),
                    'id'            => $postType . '-archive-loop-before',
                    'description'   => '',
                    'before_widget' => '<aside class="widget %2$s" id="%1$s">',
                    'after_widget'  => '</aside>',
                    'before_title'  => '<h2 class="widget-title">',
                    'after_title'   => '</h2>',
                )
            );
        } // if( $post_type_object ){

    } // foreach ($postTypes as $postType) {

}
add_action( 'widgets_init', 'my_set_archive_loop_before_widget_area' );

/**
* 作成したウィジェットエリアを投稿タイプアーカイブページのループ前に出力する
*/
function my_display_archive_loop_before_widget_area( $query ){

    // アーカイブページじゃない場合は何もしない
    if ( ! is_post_type_archive() && ! is_home() && ! is_front_page() ){
        return;
    }

    // $loop_action_point を loop_start ではなくテーマ固有にする場合は以下3行のコメントアウト
    if ( ! $query->is_main_query() ) {
        return;
    }

  global $wp_query;

	if ( ! empty( $wp_query->query_vars['post_type'] ) ) {
        $post_type = $wp_query->query_vars['post_type'];

        if ( ! empty( $wp_query->posts ) ){
            // 2ページ目以外は非表示
            if ( get_query_var( 'paged', 0 ) !== 0 ){
                return;
            }
        }

        // ※ get_post_type() は該当記事がない場合に投稿タイプが取得できないため
        $widget_area = $post_type . '-archive-loop-before';
        if ( is_active_sidebar( $widget_area ) ) {
            dynamic_sidebar( $widget_area );
        }
	}
}
// // Lightningの場合
// $loop_action_point = 'lightning_loop_before';
// // Katawaraの場合
// $loop_action_point = 'katawara_loop_before';
// その他のテーマの場合(該当記事が0件の場合は表示されません)
$loop_action_point = 'loop_start';
add_action( $loop_action_point, 'my_display_archive_loop_before_widget_area' );

WordPressはループの前に loop_start というアクションフックがあるので、そこに対してウィジェットエリアを出力しています。

このコードの欠点

コードが悪いわけではないのですが、あくまで loop_start のフックなので、投稿件数が0件の場合はループが存在しないために表示されなくなります。

そのため、弊社 Lightning や Katawara では ループ前に別途アクションフックが設けてあるため、ウィジェットエリアはそこから出力する事ができます。

プラグインで実装しました

と、コードを書きましたが、おそらく「よくわかんねーよ!」という方も多いと思いますので プラグイン VK All in One Expansion Unit の機能の一つとして実装しました(9.49.0.0 以降)。

デフォルトでは無効になっていますので、有効にしたい方は ExUnit > 有効化設定 画面から有効化してください。

Follow me!

この記事を書いた人

石川栄和代表取締役
名古屋のウェブ制作会社数社に10年程度務めた後、株式会社ベクトル設立。
企画・運営・コンサルティング〜WordPressを中心としたシステム開発まで幅広く携わる。
[ 著書 ]
・いちばんやさしいWordPressの教本(共著)
・現場でかならず使われているWordPressデザインのメソッド(共著)
[ 最近のWordPressコミュニティでの活動 ]
2019 WordCampNiigata セッションスピーカー
2019 WordCampHaneda セッションスピーカー
2018 WordCampOsaka セッションスピーカー
2017 WordCampKyoto セッションスピーカー

初心者でも簡単!無料WordPressテーマ

100%GPL / 商用利用可能

Lightning は WordPress公式ディレクトリに登録されているカスタマイズ性の高いテーマです。
デモデータも配布されているので、ビジネスサイトの雛形が数分でセットアップできます。

VWSオンラインコミュニティー

オンラインコミュニティでは、より良いテーマ・プラグイン開発のため、機能改善・追加要望などの書き込み大歓迎です!
ユーザー同士の交流や意見交換の場としてもお気軽にご参加ください。
※質問はフォーラムでのみ対応となります。