
公司網站常有這種需求:
- 首頁放「最新消息」分類的最新 5 篇。
- 服務介紹頁下面,列出同一類的案例文章。
- 另一個網站(例如集團的另一個品牌站)也要顯示這裡的最新文章。
這篇從最簡單的方法開始:先看內建區塊做不做得到,再用 WP_Query 寫一個短代碼,最後說明外站怎麼用 REST API 讀文章。
先試試內建的區塊
區塊編輯器已經有兩個現成的區塊,很多情況不用寫程式:
- 「最新文章」區塊:選分類、篇數,要不要顯示日期、摘要、精選圖片,勾一勾就好。
- 「查詢迴圈」區塊:版面可以自己排(標題、日期、圖片的位置),適合區塊佈景主題的首頁和分類頁。
用傳統編輯器、頁面編輯器,或要放在佈景主題的版型檔裡,才需要下面的寫法。
寫一個短代碼:[zw_posts]
放在子佈景主題的 functions.php,或用 Code Snippets 這類外掛新增:
// 短代碼 [zw_posts category="最新消息" count="5"]:列出指定分類的最新文章
add_shortcode( 'zw_posts', function ( $atts ) {
$atts = shortcode_atts( array(
'category' => '', // 分類的代稱;中文分類名稱直接寫也可以
'count' => 5, // 幾篇
'orderby' => 'date', // date 發佈日、modified 更新日、rand 隨機
), $atts );
$query = new WP_Query( array(
'post_type' => 'post',
'posts_per_page' => min( 20, max( 1, absint( $atts['count'] ) ) ),
'category_name' => sanitize_title( $atts['category'] ),
'orderby' => in_array( $atts['orderby'], array( 'date', 'modified', 'rand' ), true ) ? $atts['orderby'] : 'date',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
) );
if ( ! $query->have_posts() ) {
return '';
}
$html = '<ul class="zw-posts">';
while ( $query->have_posts() ) {
$query->the_post();
$html .= '<li><a href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a>'
. ' <time datetime="' . esc_attr( get_the_date( 'c' ) ) . '">' . esc_html( get_the_date() ) . '</time></li>';
}
wp_reset_postdata();
return $html . '</ul>';
} );在頁面放一個「短代碼」區塊,填入:
[zw_posts category="最新消息" count="5"]就會列出「最新消息」分類最新的 5 篇文章,有標題連結和日期。
WP_Query 的幾個設定
category_name填分類的代稱。中文分類名稱的代稱,WordPress 存的是一串編碼過的文字,用sanitize_title()轉一次,直接寫中文名稱也能對上。測試時用「最新消息」這個中文分類,正確撈到該分類的文章。posts_per_page篇數,程式裡限制最多 20 篇。測試時故意填count="100",只列出 20 篇以內(那個分類只有 7 篇,就列 7 篇)。orderby只接受date、modified、rand三種,填其他東西一律用發佈日排序。短代碼是在編輯器裡填的,會編輯文章的人都能改,參數要先檢查過再交給查詢。ignore_sticky_posts設成true,忽略「置頂文章」的特殊待遇。不加的話,沒有指定分類時,置頂文章會被額外塞進列表,而且不算在篇數裡。測試時要列最新 3 篇,結果多了一篇 2020 年的置頂文章,變成 4 篇;加了這行就正常了。no_found_rows設成true,告訴資料庫不用計算總共有幾篇。這個列表不需要分頁,省下一次計算,比較快。
用完要 wp_reset_postdata()
$query->the_post() 會把全域的「目前這篇文章」換成列表裡的文章。迴圈結束後一定要呼叫 wp_reset_postdata() 換回來,不然這一頁後面的留言、分享按鈕、相關文章,都可能抓到列表最後那篇。
標題用 esc_html() 輸出
文章標題可能有 &、< 這類符號。用 esc_html() 輸出,顯示的是文字本身,不會被瀏覽器當成 HTML 執行。
另一個網站要顯示這裡的文章:REST API
每個 WordPress 網站都有內建的 REST API,用網址就能讀到文章資料:
https://你的網址/wp-json/wp/v2/posts?per_page=5&_fields=title,link,dateper_page=5:最新 5 篇。_fields=title,link,date:只要標題、網址、日期,資料量小很多。- 只要某個分類,加上
&categories=分類編號。分類編號在後台「文章 → 分類」,滑鼠移到分類名稱上,網址列裡tag_ID=後面的數字就是。
方法一:在對方網頁用 JavaScript 讀
對方網站不一定是 WordPress,放一段 HTML 就好:
<ul id="news-list"></ul>
<script>
// 換成對方 WordPress 網站的網址;per_page 是篇數
const api = 'https://example.com/wp-json/wp/v2/posts?per_page=5&_fields=title,link,date';
fetch(api)
.then((res) => res.json())
.then((posts) => {
const list = document.getElementById('news-list');
posts.forEach((post) => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = post.link;
// 標題可能有 & 這類符號,先轉回一般文字
a.textContent = new DOMParser().parseFromString(post.title.rendered, 'text/html').body.textContent;
li.append(a, ' ', new Date(post.date).toLocaleDateString('zh-TW'));
list.append(li);
});
})
.catch(() => {
document.getElementById('news-list').textContent = '最新消息暫時讀不到,請稍後再試。';
});
</script>- 標題用
textContent放進網頁,就算標題裡有奇怪的符號,也只會顯示成文字。DOMParser那行是把&這類符號轉回一般字元。 - 跨網域可以直接讀。WordPress 的 REST API 會回應允許其他網域讀取的標頭。我們另外開了一個不同網址的網頁測試,成功讀到 5 篇文章的標題和日期。
- 對方網站連不上時,顯示「最新消息暫時讀不到」,不會整塊空白。
缺點是文章列表是瀏覽器載入後才出現,搜尋引擎不一定看得到這些連結。
方法二:對方也是 WordPress,用 PHP 讀並快取
// 短代碼 [zw_remote_posts]:讀另一個 WordPress 網站的最新文章,存一小時快取
add_shortcode( 'zw_remote_posts', function () {
$api = 'https://example.com/wp-json/wp/v2/posts?per_page=5&_fields=title,link,date'; // 換成對方網站的網址
$posts = get_transient( 'zw_remote_posts' );
if ( false === $posts ) {
$response = wp_remote_get( $api, array( 'timeout' => 5 ) );
$posts = array();
if ( ! is_wp_error( $response ) && 200 === wp_remote_retrieve_response_code( $response ) ) {
$posts = (array) json_decode( wp_remote_retrieve_body( $response ), true );
}
// 讀不到也存起來,10 分鐘後再試,不要每個訪客都去等對方網站
set_transient( 'zw_remote_posts', $posts, $posts ? HOUR_IN_SECONDS : 10 * MINUTE_IN_SECONDS );
}
if ( ! $posts ) {
return '';
}
$html = '<ul class="zw-remote-posts">';
foreach ( $posts as $post ) {
$title = wp_strip_all_tags( html_entity_decode( $post['title']['rendered'] ?? '', ENT_QUOTES, 'UTF-8' ) );
$html .= '<li><a href="' . esc_url( $post['link'] ?? '' ) . '">' . esc_html( $title ) . '</a></li>';
}
return $html . '</ul>';
} );wp_remote_get()是 WordPress 內建的連線函式,timeout設 5 秒,對方網站很慢時不會把自己的網站拖住。- 讀到的資料存一小時(
set_transient)。一小時內不管多少人來看,都只去對方網站讀一次。 - 讀不到也存 10 分鐘。對方網站掛掉時,不會每個訪客都卡 5 秒等它。
- 列表是在伺服器上組好的,搜尋引擎看得到這些連結。
測試結果:正常時列出對方網站最新 5 篇,標題裡的 & 正確顯示、HTML 標籤被拿掉;把網址改成連不上的位置,短代碼什麼都不顯示,頁面其他內容照常。
不想寫程式:RSS 區塊
只要顯示另一個網站的最新文章標題,區塊編輯器的「RSS」區塊填入對方的 RSS 網址(WordPress 網站是 網址/feed/)就可以,也有內建快取。只是版面能調整的地方比較少。
延伸閱讀
- WordPress 顯示相關文章:不用外掛,依分類與標籤撈出相關文章
- WordPress 頁面怎麼執行 PHP?自訂短代碼、頁面範本的安全做法
- WordPress 隨機文章:orderby rand 寫法與效能、快取問題
網站內容放對位置,客人才看得到。正威網路行銷是 25 年經驗的基隆網頁設計工作室,首頁消息、案例列表這類版面都會依你的內容規劃,台北與全台客戶也歡迎來聊聊。







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