在WP中提供兩個快取資料來讓時間保有時間有效性,Cache API
與Transient API
,這些其實與ROR或者是Laravel如出一徹,只是後者比較特別一點,是使用我們admin中講到的Options API
改裝而成的,只不過他也是會隨著時間過期的。
快取的概念大家都了解,是現在保存資料後給之後使用,不過Wordpress只提供有時效性的快取,也因此你可以設定很多次的快取,讓你資料庫少些直接存取的問題;而wp提供了三個方式可以來做操作,與JS的cookie有異曲同工之妙,有興趣可以參考這一篇講cookie
// 設定快取資料
wp_cache_add( int|string $key, mixed $data, string $group = '', int $expire = 0 );
// 取代已經存在的資料
wp_cache_replace( int|string $key, mixed $data, string $group = '', int $expire = 0 );
// 這個是兩者的綜合體,大部分我們用這個來做
wp_cache_set( int|string $key, mixed $data, string $group = '', int $expire = 0 );
我們來時做一個有快取功能的頁面吧!目標是將recently的資料放進快取並且顯示,我們會預設他們開起在一個單獨的Post之中,然後試著被我們先儲存過的快取資料來當相關資料的基底,而如果沒有快取資料,則發一個新的post然後快取他們,最後再我們取得的資料列印在html上。
我們在判斷是否是獨一的post,可以使用is_single
或是is_singular('post')
來做判斷,不過在Wordpress的開發書上也有看到不同的判斷方式,是利用in_the_loop
的方式,也是可行的。
add_filter( 'the_content', 'gogo_power_ranger_related_posts' );
function gogo_power_ranger_related_posts( $content ) {
if ( is_single() && 'post' == get_post_type() ) {
return $content;
}
$post_id = get_the_ID();
// 我們在這取快取
$posts = wp_cache_get( $post_id, 'gogo_power_ranger_related_posts' );
// 來這裡判斷是否有快取資料
if ( ! $posts ) {
// 沒有就存
$categories = get_the_category();
$posts = get_posts( [
'category' => absint( $categories[0]->term_id ),
'post__not_in' => [ $post_id ],
'numberposts' => 5
] );
if ( $posts ) {
wp_cache_set(
$post_id,
$posts,
'gogo_power_ranger_related_posts',
DAY_IN_SECONDS
);
}
} else {
$content .= '<h3>相關內容</h3>';
$content .= '<ul>';
foreach ( $posts as $post ) {
$content .= sprintf(
'<li><a href="%s">%s</a></li>',
esc_url( get_permalink( $post->ID ) ),
esc_html( get_the_title( $post->ID ) )
);
}
$content .= '</ul>';
}
return $content;
}
而接下來的這個,老實我很少使用這項功能,可以說不是很熟悉它來tune 效能,如果你的資料庫需要一個過一天就會消失的型態,那麼transients
就是你需要的,如果你有去接經委會的即是報價API(假如他有也可以申請的到),則我們可以利用這個功能來做儲存並且有一定的時效性來驗證裡頭資料是否正卻,才不會被人以為是攻擊直接被ban了。
而在其他的外掛備啟動時,Transients很有可能會被轉去使用快取,也就是轉到去Cache API來事件這幾個程式碼了,所以你不想讓你的記憶體沒了造成資料庫還得重新開機的話,請好好設定時效何時該結束,而這邊我們也提到大神Ryan McCue對於這個的解釋
Everyone seems to misunderstand how transient expiration works, so the long and short of it is: transient expiration times are a maximum time. There is no minimum age. Transients might disappear one second after you set them, or 24 hours, but they will never be around after the expiration time.
好了我們來使用儲存、取得與刪除,分別是set_transient
、get_transient
與delete_transient
,而照慣例我們也來做一個簡單的transients應用,來獲取網路上的資料,假設我們是取得某個id的最近tweet,不過我不會真的去接,這邊需要你自己發揮了。
function gogo_power_ranger_fetch_tweet_by_id($ID) {
return get_tweet($ID);
}
// Returns the video title.
function gogo_power_ranger_get_video_title($ID) {
$tweet = get_transient( 'gogo_power_ranger_latest_tweet_'.$ID );
if ( ! $tweet ) {
$tweet = gogo_power_ranger_fetch_tweet_by_id($ID);
set_transient( 'gogo_power_ranger_latest_tweet_'.$ID, $tweet, DAY_IN_SECONDS );
}
return $tweet;
}
總概而言,網路上大家會比較推薦Transient來取代快取,畢竟不是每個資料都需要那麼即時,不過最重要的是挑選正確的使用型態,如果你要顯示這幾年很火紅的虛擬貨幣,兌換的匯率放進Transient會是個好的選擇來確保短的時程變化的正確性,以及極短時間不會有太多請求出去,而你也可以將有hashtag的Instagram加進自己的transient,這個片段是可以設計的長一點,對於需要做接到Http取回的資料,都是建議使用這個來做處理,而其餘的靜態資料與檔案,就交給cache來做吧。
最後,為何效能之前是安全性呢?其實有很多方式是可以去使用,我們中間有提到的不只是輸入項目,輸出項目也得要做淨化,才能確保你的程式碼是以安全的方式增進效能,而理解淨化的重要性後,再來確實挑選transient與快取,而針對於大量使用transient,因為是進到資料庫拿資料難免比較慢,而且在同時間他並沒有多執行緒的支援,你會需要非同步的套件來幫助你使用,Async Transients是個還不錯的選擇
WP-object_cache::set
Better caching in Wordpress
wordpress - transients api
The Deal with WordPress Transients
PHP Performance Tuning: 12 Simple Tips
Improving WordPress Transients