🙌

【Wordperss】投稿画面でチェックを入れた記事を表示させる

2022/10/16に公開

概要

よくWordpressで記事の詳細ページ(single.phpなど)のページ下部で「おすすめ事例」「関連する記事」など表示することがある。
プラグインのAdvanced Custom Fieldを使用すれば、フィールドタイプで「関連」を選べば、記事を投稿する画面で「関連」する記事を選択することができる。
ただ記事毎に設定しないといけなかったりとめんどくさい。。

今回は詳細ページ(single.phpなど)のページの下部に乗せる記事を投稿画面でチェックを入れた記事を表示させるような方法をメモ。

前提

今回は「おすすめ事例」として、case-studyというカスタム投稿タイプを作成。
で作業にあたって下記の流れ。

  • プラグイン「Advanced Custom Fields」をインストールしておく。
  • おすすめ記事用のカスタムフィールを真偽フィールドとして作成
  • 投稿画面におすすめ記事のカスタムフィールドを表示させる(今回はチェックを入れる)
  • チェックの入った記事のみ、記事詳細ページの下部に表示させる

表示させるルールとしては、下記とする

  • 「おすすめ事例」として表示させる記事は3記事とする
  • 仮に「おすすめ事例」のチェックが3件未満、0件だった場合は他の記事を表示させる
  • 「おすすめ事例」のチェックが入った記事を優先的に表示させる
  • 表示してる記事は「おすすめ事例」から除外する

実制作の流れ

実際の流れ。
プラグイン「Advanced Custom Fields」の細かい説明は省きます。

おすすめ事例用のカスタムフィールドを作成する

ますはカスタムフィールドで、「おすすめ事例」用のフィールドを作成。

下記のように設定する。

  • フィールド名:case-flag
  • フィールドタイプ:真/偽
  • ルール:投稿タイプ - 等しい - case-study

設定が完了するとカスタム投稿タイプ「case-study」の投稿画面で下記のように「おすすめ事例」のチェック項目が表示される。

記事詳細ページで表示させる

実際に表示させるには、WP_Queryでオプションで指定する必要があります。

single-case-study.php
<?php
//現在の記事は除く
$current_post_id =get_the_ID();
//最大記事数
$max_posts_num=3;
//カスタム投稿タイプで「おすすめ事例」にチェックがあった記事を取得する
 $case_args = array(
     'posts_per_page' => $max_posts_num,
     'post_type' => 'case-study', // カスタム投稿タイプ名
     'order' => 'date',
     'post__not_in'=>[$current_post_id],
     'meta_query' => array(
       array(
            'key' => 'case-flag', // カスタムフィールド名
            'value' => true
            )
       )
   );
   $query = new WP_Query($case_args);
   if($query->have_posts()): while($query->have_posts()): $query->the_post();
 ?>
 <div>
   <a href="<?php the_permalink(); ?>">
     <p><?php the_title(); ?></p>
     <p><?php the_post_thumbnail(); ?></p>
   </a>
 </div>
<?php endwhile; endif; wp_reset_postdata(); ?>

まず、get_the_ID()で現在の記事のIDを取得して、post__not_inに指定する。
post_typeはカスタム投稿タイプのcase-studyを指定。
カスタムフィールドの値はmeta_queryで配列としてkeyvalueで指定することができる。
meta_queryではなくmeta_keymeta_valueとして指定することもできる。

'meta_query' => array(
   array(
    'key' => 'case-flag', // カスタムフィールドのキー
    'value' => true //カスタムフィールドの値
    )
)

'meta_key' => 'case-flag', //カスタムフィールドのキー
'meta_value' => true, //カスタムフィールドの値

上記の方法で「おすすめ事例」にチェックを入れた記事を出力することができる。

ただ上記の方法だと、3件表示させたい場合にチェックの入っていないものは表示されないので、
1件しかチェックが入っていなかったら、1件しか表示されない。

今回の条件として、「おすすめ事例」のチェックが3件未満、0件だった場合は他の記事を表示させるという条件なので、成立しません。

チェックが3件未満や0件だった場合は他の記事を表示させる

実際に、条件を満たすには下記のような流れで実装してみた。

  • 記事用の配列を用意:$posts_arr
  • 取得した記事の数の変数:$current_posts_num
  • チェックした記事をWP_Queryに指定する
  • チェックした記事の数を$current_posts_numに保存しておく
  • ループ処理で必要なデータをオブジェクトとして取り出し、配列に保存する
  • 記事の総数(3件)とチェックした記事の数をチェックして、総数に達してるかどうかを調べる
  • もし3件未満だったら、WP_Queryでカスタム投稿タイプ:case-studyの記事を再取得する
  • 再度、ループ処理で必要なデータをオブジェクトとして取り出し、配列に保存する
  • 保存した配列をforeachで回す
single-case-study.php
<?php
    //現在の記事は除く
    $current_post_id =get_the_ID();
    //最大記事数
    $max_posts_num=3;
    //取得した記事のデータ数
    $current_posts_num=0;

    //記事のデータ
    $posts_arr=array();
    
    //おすすめ事例の記事のオプション
    $case_args = array(
    'posts_per_page' => $max_posts_num,
    'post_type' => 'case-study', // カスタム投稿タイプ名
    'order' => 'date',
    'post__not_in'=>[$current_post_id],
    'meta_query' => array(
        array(
            'key' => 'case-flag', // カスタムフィールド名
            'value' => true
        )
    )
    );
    
    $query = new WP_Query($case_args);
    
    //取得した「おすすめ事例」の記事の数を取得
    $current_posts_num=$query->post_count;
   
    if ($query->have_posts()) :
    while ($query->have_posts()) : 
        $query->the_post();
        $post_obj=getCasePost();
        array_push($posts_arr,$post_obj);
    endwhile;
    wp_reset_postdata();
endif;

//記事の総数が3件に届かなかった場合は他の記事から穴埋めする
if ( $current_posts_num < $max_posts_num ){

  //通常の事例の記事を取得するオプション
    $other_args = array(
        'posts_per_page' => $max_posts_num - $current_posts_num,
        'post_type' => 'case-study', // カスタム投稿タイプ名
        'order' => 'date',
        'post__not_in'=>[$current_post_id]
    );

    $query = new WP_Query($other_args);

    if ($query->have_posts()) :
        while ($query->have_posts()) : 
            $query->the_post();

            $post_obj=getCasePost();    
            array_push($posts_arr,$post_obj);
        endwhile;
        wp_reset_postdata();
    endif;
    }
    
    //データを取得する関数
    function getCasePost(){
    //サムネイル画像のパス
    if (has_post_thumbnail()) {
        $thumb_path = get_the_post_thumbnail_url();
    } else {
        $thumb_path = get_template_directory_uri() . "/assets/images/common/img_no-thumb.png";
    }

    //ターム名を取得
    $terms = get_the_terms(get_the_ID(),'case-study_cat');
    $term_name = isset($terms) ? esc_html($terms[0]->name) : "no term";

    //記事のオブジェクト
    $obj=(object) [
        'post_title' => get_the_title(),
        'link' => esc_url(get_permalink()),
        'thumb' => $thumb_path,
        'term'=> $term_name,
    ];                 
    return $obj;
    }

?>

//取得したデータをforeachでデータを出力する
<?php foreach ($posts_arr as $post): ?>
    <div>
      <a href="<?php echo $post->link; ?>">
         <img src="<?php $post->thumb ?>" />
         <p><?php echo $post->term; ?></p>
         <p><?php echo $post->post_title; ?></p>
      </a>
    </div>
<?php endforeach; ?>

ポイントだけ説明

説明すると長くなるが、ループ内で必要な記事のデータをオブジェクトとして作成して、それを返す関数(getCasePost)を作成してる。その関数からデータを取得したら、記事保存用の配列($posts_arr)に保存している。

この処理をおすすめ事例のループと通常の記事のループと2回行う事で「おすすめ事例」のチェックが3件ない場合は通常の記事のデータを取ってきて追加している。

オブジェクトとしているのはデータに$post->nameとアクセスできるようにしてるためである。
シンプルに記述すると下記のようになる。

if ($query->have_posts()) :
        while ($query->have_posts()) : 
            $query->the_post();
  //記事のオブジェクト
    $obj=(object) [
        'post_title' => get_the_title(),
        'link' => esc_url(get_permalink()),
        'thumb' => $thumb_path,
        'term'=> $term_name,
    ]; 
   
   //配列に追加
  array_push($posts_arr,$obj);
     
     endwhile;
  wp_reset_postdata();
endif;

オブジェクトは配列の前に(object)[]と記述すればいいらしい。
上記のループを繰り返したら、あとは配列をforeachで出力すればいい。

まとめ

今回は条件を満たす為に2回ほどループ処理をしている。
WQ_Queryにオプションを指定する時にmeta_queryでもっとうまく条件を指定できる方法があればという印象。

https://allegretto-works.com/customfields/622
https://www.kerenor.jp/loop-sorted-by-customfield/#Advanced_custom_fields
https://simplesimples.com/web/application/wordpress/wp_queryの引数にセットして絞り込み検索を容易にする/
https://wpdocs.osdn.jp/関数リファレンス/WP_Query
https://prograshi.com/language/php/php-array-object/

Discussion