WordPress 的 Rewrite API 是專為網址靜態化設計的,它把含有 ?
、=
的網址參數去除,轉換成像是靜態網頁般的網址結構。在 WordPress 的世界中,稱作永久連結 (permalink)。
在早期的搜尋引擎對於這樣的靜態網址十分友好,對搜尋結果的排名有些許幫助,於是 WordPress 在 2005 年 發布的 1.5 版引進了 Rewrite API,提供了一套靈活的 URL 重寫系統,允許開發者和使用者自定義他們的網站的永久連結結構。
圖:網址改寫靜態化
現今這樣的靜態網址已經對 SEO 沒什麼幫助,原因之一是藏在網址上的關鍵字被濫用,其二是大家都是靜態化的網址,都一樣,自然沒優劣之分,但靜態網址比起重寫前的動態網址來得較短、好記憶,有助於使用者更好地理解網址結構。
圖:收到請求到重寫 URL 流程
讀取與解析: 伺服器收到請求,會讀取 .htaccess 檔案 (Apache) 或設定檔案 (Nginx) 中的 rewrite 規則,並解析請求的 URL。
匹配規則: 接著,系統會從上到下依次嘗試匹配設定的 rewrite 規則。一旦找到匹配的規則,系統將重寫 URL 或終止進一步的規則處理。
查詢與載入: 之後,WordPress 根據解析結果生成對應的查詢。根據這個查詢,載入並顯示對應的頁面或文章。
開始自定義網址改寫規則的範例之前,先認識一下 WordPress 的 WP_Rewrite
類別。
它在 wp-includes/rewrite.php
中被定義為一個單一實例的全域變數 $wp_rewrite
,並在 wp-settings.php
中初始化,用於管理永久連結功能的重寫規則。
我們可以直接使用 $wp_rewrite
這個全域變數,並使用它的方法,不過 WordPress 提供了相關的函式來包裝 WP_Rewrite 物件使用,這樣可以讓程式碼看起來比較整潔,更好使用。
add_rewrite_rule( $regex, $redirect, $after );
用於新增自定義的 URL 重寫規則,將美化的 URL 映射到 WordPress 查詢變數。
$regex
匹配 URL 的正則表示式。$redirect
匹配到的 URL 將要重定向到的目標。$after
控制新規則將被加到重寫規則陣列的哪個部分。關於第三個參數 $after
可以接收兩個值:
top
:你的自定規則將被排在 WordPress的所有內建規則的最前面。WordPress 在解析 URL 時會首先考慮自定規則。在多數情況下,自定義規則能夠優先於 WordPress 的內建規則的話,才不會被內建的規則覆蓋掉或者被忽略。
bottom
:自定的規則將被排在所有內建規則的最後面,通常是為了讓規則只在內建規則無法套用的情況下才生效,才會設定為這個值。
圖:add_rewrite_rule 範例程式碼
第 7 行:我們的主角,add_rewrite_rule 函式。
第 8 行:第一個參數,為定義靜態網址規則。
第 9 行:第二個參數,映射到原始的 PHP 動態網址的規則。
第 10 行:第三個參數,設為 top,讓我們的自定義的規則高於內建的頁面規則。如果設為 bottom 的話,此規則會失效而 404。
add_rewrite_tag( $tag, $regex, $query );
建立自定的查詢變數並用於 URL 重寫規則,通常與 add_rewrite_rule
結合使用。
$tag
:格式為 %my_var%
的字串,定義了查詢變數的名稱。$regex
:匹配查詢的變數值的正則表示式。$query
(可選):定義如何在查詢中使用這個變數。
圖:add_rewrite_tag 範例程式碼
第 7 行:我們的主角,add_rewrite_tag 函式,第一個參數定義變數名稱,第二個參數為正規表示式比對匹配的值。
第 8 行:我們的男配角,add_rewrite_rule 函式。
第 9 行:第一個參數,為定義靜態網址規則。
第 10 行:第二個參數,映射到原始的 PHP 動態網址的規則,my_var
是我們剛剛在第 7 行定義的變數名稱。
取得變數的值
add_action( 'template_redirect', function () {
$var = get_query_var('my_var');
} );
接下來,我們可以使用 get_query_var
函式取得該變數的值,不過要註冊在 template_redirect
鉤點,待 WP_Query 類別實例化之後才生效。
add_rewrite_endpoint( $name, $places, $query_var );
為 WordPress 的重寫規則系統新增新的端點,這些端點可用於 URL 中的任何位置。
$name
:新端點的名稱,這個名稱將會成為查詢變數的名稱,同時也將用於 URL 結構中。$places
: 一個位元遮罩 (bitmask),用來定義端點在哪些位置是有效的。WordPress 定義了幾個常數來幫助設定這個值,包括 EP_PERMALINK
、EP_ATTACHMENT
、EP_ROOT
和 EP_CATEGORIES
等,從變數的字面上看可以得知是用在那些種類的頁面。$query_var
(可選):將 $name
作為查詢變數的名稱添加到查詢變數列表中,或者使用自定義的查詢變數名稱。基本上不用理會這個值,預設值為 true
。
圖:add_rewrite_endpoint 範例程式碼
這個例子中,add_my_endpoint 函式加入了一個名為 api 的新端點,並通過 EP_PAGES
常數指定這個端點只在頁面類型的 URL 中有效。當這個端點被加入後,它將可以用作查詢變數,並且可以在 URL 中像這樣使用:
http://yoursite.com/sample-page/api/1
在這個 URL 中, api
是新增的端點,而 1
是 api
端點的值。接著我們可以在佈景主題的範本檔案中,或者在編寫外掛的時候,註冊到 template_redirect
之後的鉤點,透過以下方式取值。
$api = get_query_var( 'api' );
// 1
add_permastruct( $name, $struct, $args );
定義新的永久連結結構,允許開發者定義並 URL 結構模式。
$name
:Permastruct 的名稱,它在內部用來作為識別碼。$struct
:URL 結構。包含用百分比符號 (%) 括起來的重寫標籤。$args
(可選):一個參數陣列。
圖:add_permastruct 範例程式碼
第 10 行:我們的主角,add_permastruct 函式,第一個參數定義識別名稱。
第 11 行:第二個參數為正規表示式比對匹配的值,匹配的標籤需先定義,因此第 7 行及第 8 行定義了這兩個查詢變數標籤。
第 13 行:可選參數,請參考以下表格。
參數 | 型別 | 預設值 | 說明 |
---|---|---|---|
with_front | bool | true | URL 是否在「前端」有基底。例如,如果你的永久連結結構是 /blog/%postname%/ ,並且此值設為 true 則結構會是 /blog/my_custom_structure 。 |
ep_mask | int | EP_PERMALINK | 端點 (mask) 用來描述支持的端點類型。如果沒有設定,將使用預設的 EP_PERMALINK。 |
paged | bool | true | 是否允許分頁。 |
feed | bool | true | 是否允許 feed 端點。 |
forcomments | bool | false | 是否允許迴響分頁端點。 |
walk_dirs | bool | true | 是否 URL 中分層。 |
endpoints | bool | true | 是否允許其他端點。 |
移除之前用 add_rewrite_tag
定義的查詢變數及其相關的重寫標籤。
這這個函式很不常用。如果你有用到它的情境歡迎留言分享喔。
圖:後台頁面 - 永久連結設定
當設計完我們的路由重寫規則後,必須保存設定,才能把這些資料寫回資料庫讓它生效。來到後台「設定」,「永久連結」設定頁面,下方的「儲存設定」按紐,按下即可。
另外一個更新路由設定的方法是使用 flush_rewrite_rules
這個函式,它的使用時機適合在「外掛啟用」的時刻,把我們外掛有用到的路由設定儲到資料庫去。
圖:資料表 wp_options
由於這個函式會觸發清空、更新資料表 wp_options
的 rewrite_rules
欄位,此欄位尺寸不小,加上更新資料表很耗能。如果把它註冊到每一頁都可觸發的鉤點,CPU 的負擔會很重,資料庫的 binlog 體積也會肥的很快速,小心使用!
WordPress 的 Rewrite API 可以讓我們設定有特色的頁面專屬網址,藉由今天提到的五個相關函式,很方便地用來設計外掛功能的專屬頁面網址。
不過要特別注意,由於 WordPress 的路由規則是存在資料表中,並不是很直接地可以檢視它們的先後順序,因此在測試路由的時候要特別小心,以免覆蓋到現有功能所需要的功能頁面網址哦。
課後思考:
實務上,如果遇到外掛開發者會把 flush_rewrite_rules 之類會立即刷新資料庫資料的函式註冊到每一頁會觸發的鉤點,要怎麼發現?
前篇解答參考:
在設計權限的時候,最好的作法是採用「最小權限」原則,先賦予最小的權限,只給該角色任務需要的權限。另外,越高的權限,例如管理團隊內的權限,則限制 IP ,只能在公司網路登入,在外工作時則需透過 VPN 連線,達到最基本的安全管控。