前言
在 WordPress 部落格中,提供文章的上下篇導覽是一個常見需求,可以提升使用者閱讀體驗與網站停留時間。這段 PHP 程式碼實作了一個簡單的短碼(shortcode),用來在單篇文章頁面顯示前一篇與下一篇文章的連結,並且自訂了標題截斷與箭頭圖示,適合有基礎 PHP 與 WordPress 開發經驗的工程師或自學者參考。
短碼功能說明
這個短碼名為 ks_post_prev_next,只會在單篇文章頁面(post)生效,避免在其他頁面出現不相關的導覽。它會取得目前文章的前一篇與下一篇文章物件,並動態產生 HTML 連結。
標題截斷函式
為了避免標題過長影響排版,使用匿名函式 $trim_title 限制標題最多顯示 20 個字元,超過部分會以「…」取代。這裡使用了 PHP 的多字元字串函式 mb_strlen 與 mb_substr,確保中文標題不會被截斷成亂碼。
$trim_title = function($title) {
$max = 20;
return mb_strlen($title, 'UTF-8') > $max
? mb_substr($title, 0, $max, 'UTF-8') . '...'
: $title;
};
箭頭 SVG 圖示
為了美化導覽連結,內嵌了 SVG 圖示作為箭頭,並包裹在 <span class="ks-arrow"> 中。前一篇連結箭頭在左側,下一篇箭頭在右側,透過 CSS 可以輕鬆調整樣式。
HTML 組合邏輯
- 若有前一篇文章,產生左箭頭加標題的連結。
- 若同時有前後篇,兩者中間會插入一個分隔符號
<span class="ks-nav-sep"></span>。 - 若有下一篇文章,產生標題加右箭頭的連結。
整個區塊包在 <div class="ks-post-nav"> 方便後續 CSS 控制。
$html = '<div class="ks-post-nav">';
if ($prev) {
$html .= '<a class="ks-nav-prev" href="' . get_permalink($prev->ID) . '">'
. $arrow_svg . esc_html($trim_title(get_the_title($prev->ID))) . '</a>';
}
if ($prev && $next) {
$html .= '<span class="ks-nav-sep"></span>';
}
if ($next) {
$html .= '<a class="ks-nav-next" href="' . get_permalink($next->ID) . '">'
. esc_html($trim_title(get_the_title($next->ID))) . $arrow_svg . '</a>';
}
$html .= '</div>';
實務應用與優化建議
- CSS 樣式調整:可依照網站風格調整
.ks-post-nav、.ks-nav-prev、.ks-nav-next與箭頭的顏色與大小,提升視覺一致性。 - 多語系支援:目前標題截斷固定 20 字,若有多語系需求可以考慮依語言調整截斷長度。
- SEO 考量:連結文字使用
esc_html輸出,避免 XSS 攻擊,但可進一步加入 aria-label 屬性提升無障礙。 - 短碼擴充:可加入參數控制是否顯示箭頭、截斷長度等,增加彈性。
常見問題與注意事項
- 若文章為第一篇或最後一篇,對應的前一篇或下一篇連結會自動隱藏,避免出現空白或錯誤連結。
- 使用短碼時,請確保主題模板中有呼叫
the_content()或支援短碼解析。 - 由於使用
get_previous_post()與get_next_post(),文章必須在相同分類或條件下才會正確導覽,若需要跨分類可調整函式參數。
完整程式碼
<?php
// Shortcode: [ks_post_prev_next]
function ks_post_prev_next_shortcode() {
if (!is_singular('post')) return '';
$prev = get_previous_post();
$next = get_next_post();
// 保留 20 字,超過補 ...
$trim_title = function($title) {
$max = 20;
return mb_strlen($title, 'UTF-8') > $max
? mb_substr($title, 0, $max, 'UTF-8') . '...'
: $title;
};
$arrow_svg = '
<span class="ks-arrow">
<svg width="46" height="46" viewBox="0 0 46 46" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="45" height="45" rx="22.5" stroke="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.1465 27.8536C19.9512 27.6583 19.9512 27.3417 20.1464 27.1465L24.7929 22.4996L20.1465 17.8536C19.9512 17.6583 19.9512 17.3417 20.1464 17.1465C20.3417 16.9512 20.6583 16.9512 20.8535 17.1464L25.8535 22.146C26.0488 22.3413 26.0488 22.6579 25.8536 22.8531L20.8536 27.8535C20.6583 28.0488 20.3417 28.0488 20.1465 27.8536Z" fill="currentColor"/>
</svg>
</span>';
$html = '<div class="ks-post-nav">';
if ($prev) {
$html .= '<a class="ks-nav-prev" href="' . get_permalink($prev->ID) . '">'
. $arrow_svg . esc_html($trim_title(get_the_title($prev->ID))) . '</a>';
}
if ($prev && $next) {
$html .= '<span class="ks-nav-sep"></span>';
}
if ($next) {
$html .= '<a class="ks-nav-next" href="' . get_permalink($next->ID) . '">'
. esc_html($trim_title(get_the_title($next->ID))) . $arrow_svg . '</a>';
}
$html .= '</div>';
return $html;
}
add_shortcode('ks_post_prev_next', 'ks_post_prev_next_shortcode');