
WordPressで記事をランダムに表示したい場面は多いですよね。例えば、トップページのおすすめ記事や、記事下の関連記事などで「毎回違う記事を見せたい」というニーズがあります。
その際、WP_Query の引数で orderby => 'rand'
を指定するのが最も手軽な方法としてよく紹介されます。しかし、この orderby=rand
、実はサイトの表示速度を低下させる大きな原因になることがあるんです。
この記事では、orderby=rand
を使うことのデメリットと、サイトパフォーマンスを落とさずにランダム表示を実現するための PHP とトランジェントキャッシュを使った方法、そして具体的なコード例(WordPressの基本的なループ形式)をご紹介します。
`orderby=rand` がサイト速度を遅くする理由
なぜ orderby=rand
は遅いのでしょうか?それは、データベースの処理方法に関係があります。
WordPressは記事データをデータベースに保存しています。orderby=rand
を指定して記事を取得しようとすると、データベースは以下の処理を行います。
- 条件に合う全ての記事をデータベースから引っ張ってくる。
- それぞれの記事にランダムな番号を割り振る。
- そのランダムな番号で記事を並べ替える。
- 指定された件数だけ記事を取り出す。
記事数が少なければ問題ありませんが、サイトの記事数が増えてきたり、同じページ内で何度も orderby=rand
のクエリが実行されたりすると、この「全ての記事を引っ張ってきて、ランダムな番号を割り振って、並べ替える」という処理がデータベースに大きな負荷をかけます。
結果として、ページの表示に時間がかかるようになり、ユーザーの離脱率増加や検索エンジンの評価低下につながる可能性があります。
なぜ高速化が重要か?
サイトの表示速度は、ウェブサイト運営において非常に重要な要素です。
- ユーザー体験の向上: ページがすぐに表示されると、訪問者はストレスなくサイトを閲覧できます。表示が遅いと、多くのユーザーは待たずに他のサイトへ移動してしまいます。
- SEO評価の向上: Googleをはじめとする検索エンジンは、ページの表示速度をランキング要因の一つとしています。速いサイトは評価されやすく、検索結果で上位表示される可能性が高まります。
- サーバー負荷の軽減: データベースへの不要な負荷を減らすことは、サーバーのリソースを効率的に使うことにつながります。特に共有レンタルサーバーを利用している場合、リソース超過による制限を防ぐことができます。
高速なランダム表示を実現する方法:PHPとキャッシュの組み合わせ
orderby=rand
を使わずにランダム表示を実現し、かつ高速化するためには、以下のステップを踏む方法が効果的です。
- 条件に合う記事のIDだけを取得する: WP_Query で
fields => 'ids'
を指定し、posts_per_page => -1
ですべてのIDを取得します。IDだけを取得するクエリは、記事データ全体を取得するよりも一般的に高速です。 - PHPでランダムにIDを選択する: 取得したIDの配列から、PHPの
array_rand()
関数などを使って、表示したい件数分のIDをランダムに選びます。 - トランジェントキャッシュに選択したIDを保存する: WordPressのトランジェントAPI(
set_transient()
)を使って、ランダムに選んだIDのリストを一時的にキャッシュに保存します。 - キャッシュがあればそれを使う: 次回以降のページ表示時、キャッシュが存在していれば、ID取得とランダム選択の処理をスキップし、キャッシュされているIDリストをそのまま利用します。
- 選択したIDの記事データを取得する: キャッシュされた、または今回新しく選択されたIDリストを
WP_Query
のpost__in
パラメータに指定して、記事データを取得します。orderby => 'post__in'
を指定すると、選択したIDの順序(この場合はランダムに選ばれた順)で表示できます。 - 基本的なWordPressループで表示する: 取得した記事データを、
while ( have_posts() ) : the_post(); ... endwhile;
という基本的なWordPressのループ構造で表示します。
この方法のメリットは、重いデータベースのランダム並べ替え処理を行わないこと、そしてキャッシュによって同じクエリが連続して実行されるのを防げることです。
デメリットとしては、キャッシュ期間中は表示される記事のセットが固定されてしまうため、「ページをリロードするたびに必ず違う記事が出る」という厳密なランダム性ではなくなる点が挙げられます。しかし、多くの場合、数時間~1日程度同じ記事が表示されていてもユーザー体験に大きな影響はありませんし、速度向上によるメリットの方が大きいことが多いです。
実装例:特定のカテゴリからランダムな記事を5件表示(キャッシュ付き)
ここでは、カテゴリ ‘pickup’ の公開記事の中から、ランダムに選ばれた5件の記事を基本的なWordPressループで表示するコード例を示します。このコードは、テーマのテンプレートファイル(例: index.php
や home.php
など)内に記述することを想定しています。
<?php // ランダム表示したい記事の数を定義 $posts_to_show = 5; // キャッシュキーを定義(他の場所と重複しないユニークな名前にする) $cache_key = 'my_random_pickup_posts'; // キャッシュの有効期限を定義(例: 1時間 = HOUR_IN_SECONDS) $cache_duration = HOUR_IN_SECONDS; // または 60*60 (1時間) など // キャッシュされた投稿IDを取得 $cached_post_ids = get_transient( $cache_key ); // キャッシュが存在しない場合、または期限が切れている場合 if ( false === $cached_post_ids ) { // 条件に合う記事のIDを全て取得するクエリ(ランダム並び替えはしない) $args_ids = array( 'category_name' => 'pickup', // 例: カテゴリ 'pickup' 'posts_per_page' => -1, // 条件に合う全ての記事IDを取得 'fields' => 'ids', // IDのみを取得 'post_status' => 'publish', // 公開済みの記事のみ // 必要に応じて他の条件(メタキーなど)もここに追加 ); $query_ids = new WP_Query( $args_ids ); $all_eligible_ids = $query_ids->posts; // 取得した記事IDの配列 // 取得したIDの中から、表示したい数だけランダムに選択 if ( ! empty( $all_eligible_ids ) ) { // 取得できたID数と表示したい数の少ない方を実際に選択する数とする $num_to_select = min( count( $all_eligible_ids ), $posts_to_show ); // array_rand() でランダムにキー(配列のインデックス)を選択 $random_keys = array_rand( $all_eligible_ids, $num_to_select ); // array_rand() は1件選択の場合はキー(数値)を返すため、配列に変換 if ( ! is_array( $random_keys ) ) { $random_keys = array( $random_keys ); } // 選択されたキーに対応するIDを取得して配列にする $selected_ids = array(); foreach ( $random_keys as $key ) { $selected_ids[] = $all_eligible_ids[ $key ]; } // 選択したIDリストをキャッシュに保存 set_transient( $cache_key, $selected_ids, $cache_duration ); $cached_post_ids = $selected_ids; // 今回取得したIDリストを使用 } else { // 条件に合う記事が一件も見つからなかった場合 $cached_post_ids = array(); // 空の配列を設定 } // ID取得クエリの後でリセット wp_reset_postdata(); } // キャッシュされたIDリストが存在する場合、そのIDを使って記事データを取得するクエリを実行 $the_query = false; // デフォルトではクエリを実行しない if ( ! empty( $cached_post_ids ) ) { $args_final = array( 'post__in' => $cached_post_ids, // キャッシュされたIDリストを指定 'posts_per_page' => $posts_to_show, // 表示件数 'orderby' => 'post__in', // post__in で指定した順序を維持する 'ignore_sticky_posts' => 1, // 先頭固定表示を無視 'post_status' => 'publish', // 公開済みの記事のみ (念のため) ); $the_query = new WP_Query( $args_final ); } ?> <?php // 取得した記事があるかチェックし、基本的なWordPressループで表示 if ( $the_query && $the_query->have_posts() ) : ?> <div class="random-articles-list"> <?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?> <div class="article-item"> <a href="<?php echo esc_url(get_permalink()); ?>"> <?php // アイキャッチ画像があるかチェックして表示 if ( has_post_thumbnail() ) : the_post_thumbnail('medium', array('alt' => esc_attr(get_the_title()), 'class' => 'article-thumbnail')); // サイズは適宜変更 else : // アイキャッチ画像がない場合の代替画像を考慮 // catch_that_image() 関数がテーマに定義されている前提 if ( function_exists('catch_that_image') ) : ?> <img src="<?php echo esc_url( catch_that_image() ); ?>" alt="<?php echo esc_attr(get_the_title()); ?>" class="article-thumbnail fallback-thumbnail" /> <?php else : // catch_that_image 関数もない場合のデフォルト画像 ?> <img src="<?php echo get_template_directory_uri(); ?>/images/default-thumbnail.jpg" alt="<?php echo esc_attr(get_the_title()); ?>" class="article-thumbnail default-thumbnail" /> <?php endif; endif; ?> </a> <h3 class="article-title"><a href="<?php echo esc_url(get_permalink()); ?>"><?php echo esc_html(get_the_title()); ?></a></h3> <!-- 必要に応じて投稿日や抜粋なども表示 --> <div class="article-date"><i class="far fa-calendar fa-fw"></i><?php the_time('Y/m/d');?></div> </div><!-- /.article-item --> <?php endwhile; ?> </div><!-- /.random-articles-list --> <?php else : ?> <!-- 記事が見つからなかった場合のメッセージ --> <p>該当する記事は見つかりませんでした。</p> <?php endif; ?> <?php // カスタムクエリの後で必ずリセットする wp_reset_postdata(); ?>
コードの解説
上記のコードの主要なポイントを解説します。
- キャッシュのチェックとID取得:
$cache_key
でこのキャッシュに固有の名前を定義します。get_transient($cache_key)
でキャッシュデータを取得しようとします。キャッシュが存在しないか有効期限が切れている場合はfalse
が返ります。- キャッシュがない場合、
WP_Query
を使って条件に合う記事のIDだけを全て取得します ('fields' => 'ids', 'posts_per_page' => -1
)。
- IDのランダム選択とキャッシュ保存:
! empty($all_eligible_ids)
で取得できたIDがあるか確認します。array_rand()
を使って、取得したIDリスト (`$all_eligible_ids`) からランダムにキー(インデックス)を選びます。選ぶ数はmin()
を使って、実際のID数と指定した表示件数 (`$posts_to_show`) の少ない方にしています。- 選ばれたキーに対応するIDを抽出し、新しい配列 (`$selected_ids`) に格納します。
set_transient($cache_key, $selected_ids, $cache_duration)
で、選ばれたIDリストをキャッシュに保存します。HOUR_IN_SECONDS
はWordPressの定数で1時間を表します。有効期限は必要に応じて変更してください。- ID取得クエリの後に
wp_reset_postdata()
を呼び出すことを忘れないでください。
- 記事データの取得:
! empty($cached_post_ids)
で、キャッシュされた(または新しく選択された)IDリストがあるか確認します。- IDリストがある場合、再び
WP_Query
を使いますが、今度は'post__in' => $cached_post_ids
を指定して、特定のIDの記事のみを取得します。 'orderby' => 'post__in'
を指定することで、post__in
で指定したIDリストの順番(この場合はランダムに選択された順番)で記事が並び替えられます。
- 基本的なループでの表示:
if ( $the_query && $the_query->have_posts() ) :
で、クエリが正しく実行され、かつ記事が見つかったかを確認します。while ( $the_query->have_posts() ) : $the_query->the_post();
という標準的なループ構造で各記事のデータにアクセスします。the_post()
が内部的に記事データをセットします。- ループ内で、
get_permalink()
(URL)、get_the_title()
(タイトル)、has_post_thumbnail()
(アイキャッチの有無)、the_post_thumbnail()
(アイキャッチ画像)などのテンプレートタグを使用して記事情報を表示します。 - タイトルや代替テキスト (`alt` 属性)、URLなどの出力には、セキュリティのために必ず
esc_html()
,esc_attr()
,esc_url()
などのエスケープ関数を使用します。 - アイキャッチ画像がない場合の代替処理(
catch_that_image()
またはデフォルト画像)も実装しています。
- リセット:
- カスタムクエリ (`new WP_Query`) のループ処理の後には、必ず
wp_reset_postdata()
を呼び出して、グローバルな投稿データを元の状態に戻してください。
- カスタムクエリ (`new WP_Query`) のループ処理の後には、必ず
まとめ
orderby=rand
は手軽にランダム表示を実現できますが、サイトの記事数が増えるとデータベースに大きな負荷をかけ、表示速度低下の原因となります。
今回ご紹介した「PHPでIDをランダム選択し、トランジェントキャッシュと組み合わせる」方法は、初回アクセス時やキャッシュ有効期限切れの際に多少の処理は発生しますが、キャッシュが有効な期間は非常に高速に動作します。データベースへの直接的なランダム並べ替え処理を回避し、キャッシュによってクエリ実行回数を減らすことで、特にアクセスが多いページでのパフォーマンス改善に大きく貢献します。
サイトのパフォーマンスはユーザー体験とSEOに直結する重要な要素です。もしあなたのWordPressサイトで orderby=rand
を多用していて速度に課題を感じているなら、ぜひこの代替方法を検討してみてください。サイトの規模や要件に応じて、最適な方法を選択することが大切です。