WordPress临时选项(Transients API)全解析
WordPress 2.8 版本添加了叫做 Transients 的 API,虽然已经过去了很久,但是现在了解的人非常少,实际上它非常有用。
本文我将详细的介绍 Transients 是什么、怎么使用、它与 Options 和缓存之间有什么不同以及能利用 Transients 干什么。
Transients 是什么?
Transients 中文直译为“瞬间、转瞬即逝的”,是 WordPress 中用于存储缓存和临时数据的 API,以 “key-value” 的形式保存数据,你可以给它设置一个到期时间,时间过后清除储存的数据。非常类似于 ThinkPHP 框架中的 S() 函数。
目前 Transients 并没有一个官方的中文名,这里我暂时叫做临时选项,但并不准确的,所以还是尽量使用英文称呼。
默认情况下,Transients 被利用 Options API 储存在 wp_options 表,但是每次储存会生成两条记录,分别是数据内容和它的到期时间。
如果你安装了类似 Memcached 的外部对象缓存插件,WordPress 则会把 Transients 数据直接放到缓存里,提高读取速度。
使用 Transients
对临时选项(Transients)的操作有三种,分别是获取、添加和删除,每个操作都有对应的函数,并且每个函数还有一个用来在多站点模式下储存全局数据的版本。
利用三个基本函数,就可以基本满足绝大多数对于临时数据的操作需要。
添加
使用 set_transient() 函数添加(或更新)一个临时选项,这个函数有三个参数:
$transient
(字符串)(必须)临时选项的名字。名字的长度不能超过 40 个字符,否则将无法建立 Transients。
$value
(混合)(必须)临时选项的值。可以保存除了句柄(resource)之外的任何数据类型,以后获取时也会返回同样的数据类型。
$expiration
(整数)(可选)临时选项的有效时间(秒),从创建时开始,过了规定时长后会自动删除。Transients 可能提前消失(比如启用外部对象缓存或数据库升级),但正常情况下不会在过期之后依然存在。
举一个例子:
set_transient( 'site_name', 'wp自学笔记说', 60 * 60 );
这里保存了一个叫做 “site_name” 的临时选项,值为 “wp自学笔记说
”,有效期一小时,过期后自动删除。
返回值为是否保存成功,如果保存成功则返回 True,否则返回 False。
注意:如果把临时选项的有效期留空或者设置成 “0”,则永不过期;永不过期的 Transients 会自动加载(即在加载任何页面的一开始会统一载入到缓存,安装了外部对象缓存插件除外)。
获取
获取一个临时选项需要使用 get_transient() 函数,它只有一个参数:
$transient
(字符串)(必须)临时选项的名字。
$value = get_transient( 'site_name' );
if( $value === false ){
//Transients 已过期或者未找到
}
如果临时选项已过期或者不存在则返回 False,否则返回它的值。
注意:因为过期或未找到的时候会返回 False,所以不建议在 Transients 中存储布尔值。如果真的需要存储布尔值,可以使用整型数字来代替,即 1 和 0。
删除
要删除一个临时选项,可以使用 delete_transient() 函数,它也只有一个参数:
$transient
(字符串)(必须)临时选项的名字。
例子:
delete_transient( 'site_name' );
如果删除成功,则返回 False;如果因为未找到 Transients 或者其它原因删除失败则返回 False。
多站点
上面的三个函数可以应对绝大多数情况,但如果网站是多站点模式,则创建的临时选项只能用于当前的站点。如果需要创建和使用所有站点公用的 Transients,可以使用 set_site_transient()、get_site_transient() 和 delete_site_transient() 函数,用法和上边介绍的函数一样。
Transients 与 Options 和缓存的区别
上面说到,Transients API 实际上是利用 Options API 和使用了外部对象缓存插件的缓存来存储数据,那他们直接有什么区别的?
与 Options
首先,使用 Options 的目的是在数据库永久储存数据,比如网站的设置、数据库版本等等,这些数据没有过期时间,只能手动删除,和一个网站同生同灭;而 Transients 则不同,他可能随时消失,而且支持设置到期时间,意味着它注定不能用来储存永久数据。
与缓存
有人会好奇了,如果不是永久储存数据,也同样可以设置到期时间,那它和缓存有什么区别呢?这里就要说到 WordPress 数据缓存的原理。在没有使用类似 Memcached 的外部对象缓存插件时,缓存数据只能被储存到 PHP 变量里,意味着一次请求结束所有缓存都没了,所以只能用来存储一些简单的 SQL 的查询结果以避免没必要的重复查询,只有使用了外部对象缓存插件,才可以将数据缓存到下一次请求;而 Transients 则可以在不支持跨请求缓存的情况下把数据保存到数据库,它实际上是一种强制的跨请求数据缓存,因为数据保存成功后,一定可以在下一次请求的时候使用。
Transients 的用途和例子
Transients 大概有缓存和储存临时数据两种用途,下边我来举几个例子,分别介绍一下基本的用法。
缓存标签云集
本站的标签云集页面展示了所有的标签,并且每个标签都显示了它的最新文章。
这个标签云页面虽然很漂亮,但是生成起来却非常麻烦。首先需要获取到网站所有的标签,然后再循环输出标签,循环到每个标签的时候需要单独去查询这个标签的最新文章,也就是页面所展示的每一个标签都需要经历一次单独的 SQL 查询。
标签比较少的时候还好说,但日后内容慢慢变多以后,生成这个标签云集需要大量的时间,而且也要耗费非常多的服务器资源。
这时候可以把标签云集的内容缓存起来。生成好 HTML 代码之后先保存到 Transients 里,然后再输出,下次再加载时直接从 Transients 里获取 HTML 代码,只需要一条甚至零条 SQL 就能获取到整个标签云集的代码:
//获取标签云集
function tiezhu_page_tags(){
if( ( $cache = get_transient( 'page_tags_list' ) ) !== false ) return $cache;//如果有 Transients 缓存则直接返回
//如果没有缓存则开始生成 HTML 代码
$code = '';
if( $tags = get_tags( 'orderby=count&order=DESC' ) ){
foreach( $tags as $tag ){
$code .= '<li class="tag-box">';
$post = current( get_posts( array(
'tag_id' => $tag->term_id,
'posts_per_page' => 1
) ) );
$code .= "<p class='tag-name'>$tag->name</p>";
$code .= sprintf( '<a href="%s">%s</a>', esc_url( get_permalink( $post ) ), get_the_title( $post ) );
$code .= '</li>';
}
$code .= "<ul id='tags_list'>$code</ul>";
}
//建立 Transients 缓存并返回代码
set_transient( 'page_tags_list', $code, DAY_IN_SECONDS );//缓存有效 24 小时
return $code;
}
上面的代码用来生成标签云集的 HTML 代码,并且缓存 24 小时(DAY_IN_SECONDS 为时间常量,表示 24 小时的秒数),如果存在缓存则直接返回,不用再次生成,避免大量 SQL 查询。
不过仅仅是上边的代码还是不够完美的,虽然一次缓存最多只会存在 24 小时,但是这期间修改标签或文章却无法立即显示,所以还需要在特定事件清除缓存:
//清除标签云集缓存
function tiezhu_clear_page_tags_cache(){
delete_transient( 'page_tags_list' );//删除 Transients 缓存
}
add_action( 'save_post', 'tiezhu_clear_page_tags_cache' );//创建和编辑文章
add_action( 'deleted_post', 'tiezhu_clear_page_tags_cache' );//删除文章
add_action( 'created_post_tag', 'tiezhu_clear_page_tags_cache' );//创建标签
add_action( 'edited_post_tag', 'tiezhu_clear_page_tags_cache' );//编辑标签
add_action( 'delete_post_tag', 'tiezhu_clear_page_tags_cache' );//删除标签
缓存标签云集的用法主要适用于将需要耗费大量时间和服务器资源来生成的内容缓存到 Transients 里,下一次调用时从 Transients 里获取,大大节省时间和服务器资源。
缓存天气
Transients 还经常被用作缓存从网络 API 获取的内容,比如赛事排行榜和天气预报等等。因为服务器发送网络链接需要耗费一定的时间,如果每次加载页面都请求一次,会大大拖慢加载速度,这时就可以缓存到 Transients 里,每隔一段时间再重新请求一次。
下面的例子从中国气象局的 API 获取北京现在的天气,并缓存下来:
//获取北京现在的天气
function tiezhu_weather_Beijing(){
if( ( $cache = get_transient( 'weather_Beijing' ) ) !== false ) return $cache;//先从缓存获取,如果有则直接返回
//从 API 获取数据
$api = 'http://www.weather.com.cn/adat/cityinfo/101010100.html';
$response = wp_remote_get( $api );
if( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) return;
//解析数据
$result = json_decode( wp_remote_retrieve_body( $response ) );
if( empty( $result->weatherinfo ) ) return;
//生成数据
$weather = "北京现在 {$result->weatherinfo->temp1} 到 {$result->weatherinfo->temp2},{$result->weatherinfo->weather}。n";
$weather .= '最后更新:' . $result->weatherinfo->ptime;
//缓存数据并返回
set_transient( 'weather_Beijing', $weather, HOUR_IN_SECONDS );//缓存一小时,到期重新获取
return $weather;
}
因为天气并不是实时更新,所以在 Transients 里缓存一小时,缓存过期之后再去重新获取数据。
邮件登录
除了能缓存之外,Transients 还能保存一些有时间限制的 Key、授权代码之类的信息。
下面这个例子是用发送邮件的形式登录账号。原理是提交邮箱时生成一个用于登录账号的 Key,通过这个 Key 就能登录使用该邮箱的账号,下面只展示生成和校验 Key 部分的代码:
//生成邮件登录 key
function tiezhu_set_mail_login_key( $user_id ){
$user_id = (int) $user_id;
if( !( $user = get_userdata( $user_id ) ) ) return;
$key = md5( wp_generate_password() );//生成 Key
$result = set_transient( 'mail_login_key_user_' . $user_id, $key, MINUTE_IN_SECONDS * 15 );//保存 Key;15 分钟后过期无效
if( $result ) return $key;//保存成功则返回 Key,用于发邮件
}
//使用邮件 key 登录
function tiezhu_mail_key_login( $user_id, $key ){
$user_id = (int) $user_id;
$user = get_userdata( $user_id );
if( !$user || empty( $key ) ) return;
$transient_key = get_transient( 'mail_login_key_user_' . $user_id );//获取保存的 Key
if( $transient_key === false ) wp_die( 'Key 无效或者已过期' );//Key 无效或者已过期
if( $transient_key == $key ){
delete_transient( 'mail_login_key_user_' . $user_id );//Key 有效,登录之前先删除 Key
//登录并跳转到后台
wp_set_current_user( $user_id, $user->user_login );
wp_set_auth_cookie( $user_id );
do_action( 'wp_login', $user->user_login );
wp_safe_redirect( admin_url() );
die;
}
}
上面的代码有两个函数,一个用来生成并保存登录 Key,一个用来校验 Key 和登录,其中 Key 保存在可以设置期限的 Transients 里,非常方便。
其它
关于临时选项(Transients)就介绍到之类,结尾最后强调一下 Transients 的特点:
- Transients 并不是永久储存,它的数据可能随时消失,即使还没有到期;但是在到期之后它不会再继续“存在”
- Transients 可能存储在数据库里,也可能存储在外部对象缓存里
- 如果需要缓存一些很轻松就能获取到的内容,请不要使用 Transients,而是缓存
- Transients 会在一些时候自动消失(例如数据库升级和启用外部对象缓存),所以不用担心它会永远留在服务器中,成为垃圾
- Transients 的名字是独一无二的