WordPressには、特定の記事を先頭に固定表示させる機能があります。
記事の中でも特に重要なもの・目立たせたいものを、記事一覧の先頭に固定して表示できるので、「はじめにお読みください」とか「今月のお休み」など、他の記事に埋もれてほしくない記事に便利です(^^)

この機能自体は、はじめからWordPressに用意されていますが、例えばサイトのトップページなど、任意の場所にサブループで表示させた記事一覧にも対応させるにはテンプレート側で対応が必要です。
まずは固定記事を表示させ、その後にその記事を省いた他の記事を指定したmax表示件数の残り件数分表示させるかたちです。
この記事では、先頭固定記事の作り方、装飾方法、サブループでの表示方法などをシェアします♪


この機能は、通常の投稿のみで、カスタム投稿タイプは対象外なので注意してください。
(カスタム投稿タイプで同様のことを行いたい場合はカスタムフィールドで対応すると良いと思います。)

投稿の設定

image

まずは先頭に固定する記事の作り方を。

投稿画面の「ステータスと公開状態」という箇所の「ブログのトップの固定」にチェックをいれて「更新」するだけです!
投稿一覧画面の「クイック編集」からも可能です。「この投稿を先頭に固定表示」にチェックを入れて更新!

メインループの場合はこれだけでOKです♪
これだけでメインループの先頭に表示されるようになります。
ページごとの記事数も、「設定」>「表示設定」で指定した「1ページに表示する最大投稿数」の投稿数ごとにページ送りしてくれます。

サブループの場合は後述します(^^)→その場所へジャンプ

固定記事の装飾を変更して目立たせる

記事一覧の中で、固定記事のみスタイルを変更することも可能です。
固定した記事にはstickyというクラスが付きますので、これにcssを当てればOKです。
自作テーマや、クラス付与されないテーマをお使いの方はpost_class()を適宜追加してください(^^)

<li <?php post_class();?>><!--投稿関連のクラスを追加する-->
.sticky{
    font-weight: bold;/*太字にする*/
    border: 2px solid #f00; /*赤枠で囲う*/
  }  

サブループ(WP_Query)でも先頭に固定表示させる

メインループだけでなく、サブループでも先頭固定記事を反映させたい場合のコードです。

まず先頭固定記事を表示させ、その後にそれ以外の通常記事を表示させています
通常投稿は、表示したいからから先頭固定記事の件数を引いた数の分を表示させます。

★の部分を変更すればあとはでコピペでOKです!
カテゴリを指定しない場合は、最初の方の$post_ttlに表示させたい合計記事数を入れるだけです。

先に書いておくと、後述する問題点があり、それを解消したコードも後述しています。
ただ、簡易的な表示や運用法によってはこの方法で十分かと思います!

<ul class="archive-list">
<?php 
$post_ttl = 5; //★表示させたい記事の合計件数(固定記事+通常記事)
$post_cnt = $post_ttl; //表示させる記事数残り
$sticky = get_option('sticky_posts'); //先頭固定の記事を取得
if(!empty($sticky)){ //先頭固定記事がある場合に実行
  $post_cnt -= count($sticky); //固定記事の件数を「$post_cnt」の値から引く
  $args = array(
    'post_type'=> 'post', 
    //'cat'=> 1,//★カテゴリーを絞る場合
    'post__in' => $sticky,
  );
  $the_query = new WP_Query($args);
  while($the_query->have_posts()) : $the_query->the_post();
?>
  <li <?php post_class();?>><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
  <?php 
  endwhile;
  } 
  //先頭固定以外の記事の表示
  if($post_cnt > 0){ //表示させたい記事数に余りがある場合
    $args = array(
      'post__not_in' => $sticky,
      'post_type'=> 'post' , 
      //'cat'=> 1,//★カテゴリーを絞る場合
      'posts_per_page' => $post_cnt,
      'ignore_sticky_posts' => 1,
    );
    $the_query = new WP_Query($args);
    while($the_query->have_posts()) : $the_query->the_post();
  ?>
  <li <?php post_class();?>><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
<?php 
  endwhile; 
}
//固定記事も通常記事もない場合
if($post_cnt == $post_ttl ) echo '<p class="none">記事はまだありません。</p>';
wp_reset_postdata();
?>
</ul>  

このループの問題点

先にも書いたように、このループには問題点もいくつかあります。

  • 表示させたい件数以上の先頭固定記事が表示されてしまう
    全部で5件だけ記事を表示させたい際に、先頭固定記事が7件あると、固定記事の7件全てが表示されてしまいます。
    レイアウトによっては崩れる可能性があるので、利用箇所によっては問題となりそうです。

  • 下書きやレビュー待ちの固定記事もカウントされてしまう。
    下書きの固定記事があった場合、その記事分が全体の表示件数から引かれてしまいます。

     例)全部で5件表示したい。先頭固定記事は、公開済みが1件、下書きが2件ある。
     この場合、通常投稿の表示件数が5件から3件引かれて2件のみとなってしまう。
     そのため、固定記事1件、通常記事2件の、全部で3件しか表示されなくなってしまう。

    公開まで固定のチェックを外しておけば問題ないのですが、お客様に困ると言われたらなんとかしないといけません(^_^;)

そこで、先頭固定記事のうち、公開済みの記事数だけを取得し、その差分の通常投稿を表示させる様に書き直したループが次の改訂版です。

サブループ(WP_Query)でも先頭に固定表示させる:改訂版

表示させたい件数の中でのみ先頭固定記事を表示させ、全体の表示件数には下書きの固定記事を含めないようにしたコードです。
うまくズバッと取得できなかったので、実際にループさせた数をカウントしています。
(もっとスマートなやり方があったら教えて下さい!)

★の部分を適宜変更してお使いください♪

<ul class="archive-list">
<?php //先頭固定の記事を表示
$post_ttl = 5; //★表示させたい記事の合計件数(固定記事+通常記事)
$post_cnt = $post_ttl; //表示させる記事数残り
$sticky = get_option('sticky_posts'); //先頭固定の記事を取得
if(!empty($sticky)){ //先頭固定記事がある場合に実行
  $args = array(
    'post_type'=> 'post', 
    //'cat'=> 1,//★カテゴリーを絞る場合
    'post__in' => $sticky,
    'posts_per_page' => $post_cnt,//最大投稿数を表示させたい記事数にする
    'ignore_sticky_posts' => 1,//これも合わせて指定しないと'posts_per_page'が効かない
  );
  $the_query = new WP_Query($args);
  while($the_query->have_posts()) : $the_query->the_post();
?>
  <li <?php post_class();?>><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
  <?php    
  $count++;//出力記事数取得
  endwhile;
$post_cnt -= $count; //先頭固定の記事がある場合は、その件数を「$post_cnt」の値から引く
};

//先頭固定以外の記事の表示
if($post_cnt > 0) {//先頭固定以外の記事の表示
  $args = array(
    'post__not_in' => $sticky,
    'post_type'=> 'post' , 
    //'cat'=> 1,//★カテゴリーを絞る場合
    'posts_per_page' => $post_cnt,
    'ignore_sticky_posts' => 1,
  );
  $the_query = new WP_Query($args);
  while ($the_query->have_posts()) : $the_query->the_post(); 
?>
  <li <?php post_class();?>><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
<?php 
  endwhile;
};
//先頭固定記事と公開済みの投稿が0の場合に表示         
if($post_cnt == $post_ttl ) echo '<p class="none">記事はまだありません。</p>';
wp_reset_postdata();
?>
</ul>

カテゴリーページで先頭固定表示をさせる

今までのコードはトップページに置くことを想定していましたが、 カテゴリーページなどでページ送りと併用する場合はis_paged()で条件分岐して対応します。

<ul class="archive-list">
<?php  
$sticky = get_option('sticky_posts'); //先頭固定記事を取得

//-----先頭ページにのみ適応-----
if(!is_paged()&&!empty($sticky)){//先頭ページかつ先頭固定記事がある場合に実行
$args = array(
'post__in' => $sticky,
'category_name' => $category_name,//カテゴリーを指定
);
$the_query = new WP_Query($args);
while($the_query->have_posts()) : $the_query->the_post();
?>
  <li class="sticky"><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
  <?php 
  endwhile;
}

//-----カテゴリーの記事一覧(全ページ共通)-----
$paged = get_query_var('paged') ? get_query_var('paged') : 1 ; 
$args = array(
  'category_name' => $category_name,//カテゴリーを指定
  'paged' => $paged,
  'post__not_in' => $sticky,//先頭固定記事以外を取得
);
$the_query = new WP_Query($args);
if($the_query->have_posts()){
?>
<?php while($the_query->have_posts()) : $the_query->the_post(); ?>
  <li><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
<?php 
  endwhile; 
} 
if(function_exists('wp_pagenavi')) { wp_pagenavi(array('query'=>$the_query)); } 
wp_reset_postdata();
?>
</ul>

1ページ目の頭に先頭固定記事を表示させ、その後はWP_Queryのパラメーターに'post__not_in' => $stickyを追加して、先頭固定記事ではない記事をループしています。

1ページ目は、通常のループにプラスで先頭固定記事が出力されます。
ページごとの記事数を厳密に合わせたい場合はis_paged()の条件も加えて「サブループ(WP_Query)でも先頭に固定表示させる:改訂版」と合わせればできると思います。(ここでは割愛)

先頭固定記事を固定させない方法

最後に、先頭固定記事はトップページでのみ表示させて、記事一覧ページでは固定させたくないという場合の方法です。
先頭に固定するという機能が無効化され、通常投稿と一緒に表示される様になるイメージです。

WP_Queryのパラメーターに'ignore_sticky_posts' => 1を追加します。
これだけで先頭に固定されず、日付順に表示されるようになります♪

<?php
  $args = array(
  'posts_per_page' => 10,
  'post_type' =>'post',
  'ignore_sticky_posts' => 1, //これを追加します
);
$the_query = new WP_Query($args);
if($the_query->have_posts()){
?>
<ul class="archive-list">  
  <?php while($the_query->have_posts()) : $the_query->the_post(); ?>
  <li <?php post_class();?>><?php the_title();?><span><?php the_time('Y.m.d');?></span></li>
  <?php endwhile; ?>
</ul>  
<?php 
  }else{   
    echo '<p class="none">記事はまだありません。</p>';
  }; 
  wp_reset_postdata();
?>

さいごに

先頭固定記事、そこまで対応する頻度が多くないせいか、毎回調べていたので、今回まとめられてスッキリしました(^^)!
特に昨今の緊急事態宣言のお知らせなどでトップに固定したいという需要が多いように思います。
使う人にとっては便利な機能なこと間違い無いはずですので、参考になれば幸いです♪