iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 29
1
Software Development

PHP 大師之路 - 開源的技術淬練系列 第 29

Day 29- WordPress 外掛設計實戰 (5) 快取外掛功能實作

  • 分享至 

  • xImage
  •  

經過在 Day 27 介紹 WordPress 的 Hook,之後,想必對於 WordPres 的事件處理機制有了進一步的認識,接下來就是利用 Hook 來變魔術的時間囉。非常簡單的程式碼,輕鬆完成 WordPress 的快取外掛,真心不騙!

功能規劃

這次的進度主要實作以下邏輯:

  • 快取的存放目錄
  • 快取的產生
  • 設定值儲存、使用。

完成以上三個項目,讓外掛可以正常運作。

檔案結構

今日的檔案結構如下:

.                              
├── LICENSE                    
├── README.md                  
├── README.txt                     
├── cache-master.php           
├── composer.json                     
├── inc                        
│   ├── admin                  
│   │   ├── menu.php           
│   │   ├── register.php       
│   │   ├── setting-update.php 
│   │   └── setting.php        
│   ├── autoload.php           
│   ├── class-cache-master.php 
│   └── helpers.php            
├── languages                  
├── phpcs.xml                  
└── vendor                     

對比 Day 27 的檔案結構多了以下檔案:

  • setting-update.php
  • helpers.php

而在 Day 27 時檔案還是空的「class-cache-master.php」已經寫好主功能。也是今天變出快取功能的主角!

以下是新增的檔案結構說明:

檔案路徑 說明
inc/admin/setting-update.php 在設定頁面時按下送出按紐,觸發的事件處理。
inc/helpers.php 函式集,包含檢查 Driver、一個產出 SimpleCache 物件的簡單工廠。

初始化檔案第 2 版

範例:/day-29/cache-master/cache-master.php

(圖 A:cache-master.php 程式碼截圖)

Day 27 比較起來,多了以下的改變:

第 7 行:載入需要用的函式集。

第 10 行:在 WordPress 管理介面的外掛列表中,啟用外掛後,會觸發的 Hook。
第 11 行:在 WordPress 管理介面的外掛列表中,移除外掛後,會觸發的 Hook。
第 19 行:儲存設定值時的事件處理。

第 23-25 行:實例化主功能類別 Cache_Master

快取的存放目錄

WordPress 外掛在存放自己產生的檔案,都是在 wp-content/uploads 這個目錄裡。因此,這個作品要產生的檔案也在這裡。

(圖 B:uploads 目錄截圖)

由上圖可以看到,以年份作為名稱的目錄是 WordPress 自身的媒體庫,專門放上傳的圖片、影片等等。而 sites 這個目錄是啟用多站點後,各部落格自身的媒體庫。

除了以上兩者外,都是其它外掛產生的檔案、日誌等等。因為我們也要產生一個和外掛名稱 (slug) 同名的目錄,「cache-master」。

目錄安全性考量

基於不同的網站伺服器 (web server) 的設定值不同。建議要考慮到目錄若沒有 index.html 檔案,可能是可以被瀏覽目錄的情況。為了防偷窺,我們會產生空白的 index.html 檔案,和 .htaccess 檔案。

這個功能實作在 register.php 這個檔案中。

(圖 C:register.php 下半部程式碼截圖)

而這支建立目錄用的函式由那裡呼叫呢?
見下圖的第 19 行。

(圖 D:register.php 最上方程式碼截圖)

scm_activation 這個函式會在啟用外掛時觸發。

在初始化檔案中:

register_activation_hook( __FILE__, 'scm_activation' );

而 scm_activation 函式使用 add_option 在啟用外掛時先寫入一些預設的設定值。

結果:

(圖 E:cache-master 目錄截圖)

然後再把資料放在下一層目錄,此層為空。因為要考慮到多站點放不同目錄的情況。在這個範例,筆者以開頭為 blog_id 和 8 字元雜湊碼作目錄名稱。

快取的產生

快取主功能,就是把整個 WordPress 網頁 HTML 存起來,然後就不在從資料庫撈資料,直接從快取拿出來吐給網站訪客。這樣的主功能,含註解,只要 106 行

(圖 F:class-cache-master.php 檔案截圖)

第 28 行:在實例化這個類別時,從 helper.php 的簡單工廠函式拿到 Simple Cache 物件。
第 28 行:每個網站的快取資料的 key 值就是它的路徑的 md5 值。
第 35-39 行:這個 init 方法,就是我們從初始化檔案呼叫這個主功能程式的地方。(圖 A 第 24 行)它分別把 ob_startob_stopget_post_data 這三個方法注入到三個不同的 Hook 執行,這就是產生魔法的地方唷!

方法:ob_start

還記得 Day 28 介紹的 WordPress Hook 生命週期吧?

(圖:Action Hook 的生命週期圖表)

Cache_Master 類別的 ob_start 方法,注入到 init 這個很早期的 Hook。

開始產生頁面的 Hook 是 template_redirect,距離 init 很遠呀!但筆者要求這個外掛越早輸出快取,略過越多的流程,節省的 CPU 和記憶體效率越高。

(圖 G:方法 ob_start 程式碼截圖)

第 7 行:從快取讀取頁面的 key 值,有的話呢....
第 10 行:筆者要留一行 debug 的 HTML 註解訊息在原始碼最尾端,來辨別是不是快取網頁。當然,一般人看不到。因為它是 HTML 註解語法。
第 11-12 行:有快取就輸出,然後離開程式啦。
第 15 行:當沒有快取的時候,使用 PHP 原生函式 ob_start 來收集緩衝區資料。

方法:ob_stop

(圖 H:方法 ob_stop 程式碼截圖)

這個方法是注入到 shotdown 這個 Hook,是 WordPress Hook 生命週期中的最後一個。

第 8 行:這一行是判斷該頁面是否可以被快取喔!條件決定在 get_post_data (圖 F 第46-71行),不是每一頁都會加進快取,本外掛只存放首頁、文章 (post) 和頁面 (page)。

第 9 行:將緩衝區資料存到 $content 變數。
第 12 行scm_option_ttl 是在設定頁面中讓使用者自己設定的快取存活時間,快取如果過期就自動清除唷!
第 14 行:接著將資料放進快取中。

如果該頁面是不支援快取,就什麼事都不會發生。讀 WordPress 原本的網頁。

方法:get_post_data

(圖 I:方法 get_post_data 程式碼截圖)

預設 $this->cachefalse

第 8 行:這是外掛設定值中,使用者自己設定那幾個頁面類型要快取。
第 11 行:設定是 yes 且目前頁面在首頁。
第 15 行:設定是 yes 且目前頁面在文章。
第 19 行:設定是 yes 且目前頁面在頁面。

以上是判斷頁面。不過有以下情況,則不能快取喔!

第 24 行:404 頁面不能快取啦。
第 28 行:使用者登入不能快取啦,因為快取是存整張頁面,包含登入的使用者可以看到的所有東西,網頁上方的 admin bar 會被沒登入的一般訪客看到哦。

這個方法是注入到 pre_get_posts 這個 Hook,但其實注入到更早的 wp 就可以使用 is_homeis_singleis_page 這三個 WordPress 函式了。不過日後應該還會新加功能,直接注入到 pre_get_posts 就可以取文章資料,不需要再換 Hook 囉。

設定值儲存、使用

(圖 J:Cache Master 外掛設定頁面截圖)

  • 在 Day 27 做的設定頁面,在選擇 Driver 的地方並沒有判斷系統支不支援,因此補上了。如果系統不支援的話就不能選擇。
  • 再多加了可以自由選擇要快取的 Post type。

動態 Hook

(圖 J:setting-update.php 程式碼截圖)

WordPress 很多這種 update_option_{option} 後面加上動態 ID 的 Hook。點進去看官方文件,說明長 update_option_{option} 的就屬於動態 Hook。

以這個例子來說。scm_option_driver 是設定頁面的一個選項。會產生一個動態 Hook,update_option_ 加上 scm_option_driver 變成:

update_option_scm_option_driver

然後筆者注入函式到裡面,當這個選項有更新時,快取的 Driver 會重建資料表。

scm_option_post_types 這個也是一個設定頁面選項,讓使用者選擇想快取的類型。這邊的注入函式的作用是,當這個選項更新時。快取全部清除。(因為要還要寫今天的文章,所以先全清掉啦。以後再說?)

總結

就這樣,一個快取外掛完成了。

範例原始碼

鐵人賽終於剩最後一天了,我們明天見。不對。兩小時候見。因為筆者要一股作氣完成鐵人賽。終於解脫了。><||


上一篇
Day 28- WordPress 外掛設計實戰 (4) 深入淺出 WordPress Hook
下一篇
Day 30 - WordPress 外掛設計實戰 (6) 外掛發行、鐵人賽總結
系列文
PHP 大師之路 - 開源的技術淬練30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言