
部落格經營久了,很多寫得不錯的舊文章慢慢沉到後面,沒什麼人看到。在文章最後或側邊欄放一個「隨機文章」清單,每次顯示不同的幾篇,就能讓舊文章多一些曝光的機會。
這篇教你用程式碼做隨機文章,也說明網站文章很多時要注意的效能問題。
程式碼要放在哪裡?
下面的 PHP 程式碼都加在子主題的 functions.php,或用 Code Snippets 外掛新增,不要直接改主題本身的檔案。詳細說明請看 WordPress functions.php 實用程式碼整理。
基本寫法:orderby => rand
function ahwei_random_posts( $count = 5 ) {
$query = new WP_Query( array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $count,
'orderby' => 'rand',
'post__not_in' => is_singular() ? array( get_queried_object_id() ) : array(),
'has_password' => false,
'ignore_sticky_posts' => true,
'no_found_rows' => true,
) );
if ( ! $query->have_posts() ) {
return '';
}
$html = '<ul class="random-posts">';
while ( $query->have_posts() ) {
$query->the_post();
$html .= sprintf(
'<li><a href="%s">%s</a></li>',
esc_url( get_permalink() ),
esc_html( get_the_title() )
);
}
wp_reset_postdata();
return $html . '</ul>';
}
// 短代碼:[random_posts count="5"]
add_shortcode( 'random_posts', function ( $atts ) {
$atts = shortcode_atts( array( 'count' => 5 ), $atts );
$count = max( 1, min( 20, absint( $atts['count'] ) ) );
return ahwei_random_posts( $count );
} );幾個參數的用意:
'orderby' => 'rand':隨機排序。post__not_in:在文章頁時,排除正在看的這一篇。'has_password' => false:不顯示有密碼保護的文章。no_found_rows:不需要分頁,省掉計算總篇數的查詢。
放到網站上
- 文章內或小工具:加一個「短代碼」區塊,填入
[random_posts count="5"]。 - 區塊主題:到「外觀 → 編輯器 → 範本 → 單篇文章」,在文章內容下方加入「短代碼」區塊。
- 傳統主題:在子主題的
single.php想顯示的位置加上<?php echo ahwei_random_posts( 5 ); ?>。
清單的樣式可以用 CSS 針對 .random-posts 調整。
舊版程式碼的問題
這篇文章舊版的程式碼直接寫 SQL 查資料庫,還用資料表裡的 guid 欄位當作文章網址。guid 只是文章的識別碼,不一定等於真正的網址(例如換過網域、改過固定網址之後就會不同),請改用上面 WP_Query 加 get_permalink() 的寫法。
文章很多時:ORDER BY RAND() 會拖慢網站
'orderby' => 'rand' 在資料庫裡是 ORDER BY RAND()。它的做法是:先幫每一篇符合條件的文章產生一個隨機數,全部排序之後,才取出前幾篇。
- 文章不多的網站,幾乎感覺不出差別。
- 文章數量很多、流量又大的網站,每一次瀏覽都要把所有文章排一次序,資料庫的負擔會很明顯,頁面也會變慢。
比較省資源的寫法:先取候選清單,再用 PHP 隨機挑
換個方式:先抓最近 200 篇文章的 ID 當候選清單,暫存起來;每次要顯示時,在 PHP 裡把清單打亂,取前幾篇就好。資料庫不用每次都做隨機排序。
把前面的 ahwei_random_posts() 換成下面這個版本(短代碼那一段不用改)。注意是「換掉」,同一個函式名稱出現兩次,網站會出錯:
/**
* 取得隨機文章 ID:候選清單暫存 12 小時,在 PHP 裡隨機挑選
*/
function ahwei_random_post_ids( $count = 5 ) {
$pool = get_transient( 'ahwei_random_pool' );
if ( false === $pool ) {
$pool = get_posts( array(
'post_type' => 'post',
'posts_per_page' => 200,
'fields' => 'ids',
'has_password' => false,
'no_found_rows' => true,
) );
set_transient( 'ahwei_random_pool', $pool, 12 * HOUR_IN_SECONDS );
}
// 在文章頁時排除目前這篇
$current = is_singular() ? get_queried_object_id() : 0;
$pool = array_diff( $pool, array( $current ) );
shuffle( $pool );
return array_slice( $pool, 0, $count );
}
// 發佈或更新文章時,清掉候選清單,下次重新抓
add_action( 'save_post_post', function () {
delete_transient( 'ahwei_random_pool' );
} );
function ahwei_random_posts( $count = 5 ) {
$ids = ahwei_random_post_ids( $count );
if ( ! $ids ) {
return '';
}
$query = new WP_Query( array(
'post__in' => $ids,
'orderby' => 'post__in',
'posts_per_page' => count( $ids ),
'ignore_sticky_posts' => true,
'no_found_rows' => true,
) );
$html = '<ul class="random-posts">';
while ( $query->have_posts() ) {
$query->the_post();
$html .= sprintf(
'<li><a href="%s">%s</a></li>',
esc_url( get_permalink() ),
esc_html( get_the_title() )
);
}
wp_reset_postdata();
return $html . '</ul>';
}- 候選的 200 篇可以依網站調整。想讓更早的文章也有機會出現,就把數字調大;因為只抓 ID、又有暫存,調到上千篇負擔也不大。
- 候選清單 12 小時才重新抓一次,發佈或更新文章時也會自動清掉重抓。
orderby => post__in讓顯示順序跟隨機挑出來的順序一樣。
網站有頁面快取時,隨機文章不會變?
裝了 WP Rocket、LiteSpeed Cache 這類快取外掛,整個頁面會被存成靜態檔案送給訪客。隨機清單也跟著被存起來,在快取更新之前,每個人看到的都是同一組。
對大多數網站來說,這其實可以接受:等於每次快取更新時換一批文章,網站速度也不受影響。
如果一定要每位訪客看到不同的組合,可以改成頁面載入後,由瀏覽器用 JavaScript 向 WordPress 的 REST API 取得最近幾十篇文章,再在瀏覽器裡隨機挑幾篇顯示。這樣頁面照樣可以快取,隨機的部分交給瀏覽器處理。
隨機文章、相關文章、熱門文章怎麼選?
- 隨機文章:讓舊文章被看到,適合題材比較分散的部落格。
- 相關文章:同一個主題的文章,讀者比較可能繼續看下去,做法請看用代碼顯示相關文章。
- 熱門文章:依閱讀次數排序,做法請看顯示文章閱讀次數與熱門文章排行。
三種可以搭配使用,例如文章最後放相關文章、側邊欄放熱門文章。
延伸閱讀
- WordPress 顯示相關文章:不用外掛,依分類與標籤撈出相關文章
- WordPress 顯示文章閱讀次數:不用外掛的程式碼寫法(含快取網站解法)
- WordPress 網站加速完整攻略:測速、主機、快取、圖片、外掛與資料庫清理
讓讀者一篇接一篇看下去,靠的是好內容,也靠網站的動線設計。正威網路行銷是基隆在地、擁有 25 年網站設計經驗的工作室,提供基隆網頁設計與網站維護託管等服務,歡迎來聊聊。







發表留言
還沒有人留言,歡迎第一個分享你的想法或問題。留言經審核後才會顯示,Email 不會公開。