由于安装了很多人,我想我将与您分享缓存WordPress必不可少的关键技术,这将有助于您提高网站速度。
W3 Total Cache是实现缓存的理想插件,我会推荐给任何人。但是,有时您不希望长时间缓存整个页面,而是希望缓存整个页面的一部分,以使页面重建在服务器时间上不那么昂贵。
例如,我有一个网站,他们不想在整个主页上进行缓存,因为他们希望具有以下功能:
- •由php提供的旋转背景图片
- •替换广告脚本以供供应商比较
- •每5分钟更新一次的循环,以及每小时更新一次的循环
选择"子缓存"(以使用客户的首选术语)策略为最佳。现在,您了解了我们需要实现的场景:一个缓存的主页,其中可能有定期更新的项目,而没有使用W3TC的页面缓存。
为了实现客户想要的所有功能,我需要使用WordPress的Transients API
WordPress瞬态API
在WordPress的瞬态API是一组简单的三个命令的工作非常喜欢选项API,但是当一个定时器,你设置耗尽,瞬时被自动删除。在瞬变内部,您可以保存所需的任何类型的数据。它可以是数组,对象或只是一些文本,实际上存储在其中的内容并不重要,因为WordPress会根据需要对其进行序列化来处理它。
Transients API的作用还在于自动将瞬变保存在服务器上响应最快的位置。这可能在数据库,磁盘或内存缓存中,具体取决于您的服务器配置。
这是获取和设置瞬态的基本语法:
<?phpphp
$value = get_transient( 'value' );= get_transient( 'value' );
if ( false === $value ) {if ( false === $value ) {
// if transient not set, do this!// if transient not set, do this!
// create the data that needs to be saved.// create the data that needs to be saved.
$value = 1;= 1;
// save the newly created transient value// save the newly created transient value
// 60 seconds * 60 minutes * 24 hours = 1 day// 60 seconds * 60 minutes * 24 hours = 1 day
set_transient('value', $value, 60*60*24);('value', $value, 60*60*24);
}}
?>?>
注意它们如何相互配合工作。如果在瞬态中未设置任何名为"值"的内容,则代码会从if语句中的代码中设置新的"值"。
如您所见,我们设置瞬态的全部工作就是使用瞬态set_transient()
的名称,在本例中为"值",它$value
是您要保存的数据,最后一部分是将创建数字的计算瞬变应持续的秒数。
在WordPress内部的单个循环上使用瞬态
除非您是一个拥有100多个内容创建者的超级繁忙的网站,否则您可以确定在博客中显示帖子的循环不会经常改变。在那几天或只有几分钟的时间里,缓存将加快循环速度,因为服务器不必询问任何复杂的SQL查询,而只需一个简单的请求即可获取预先找到的数据,这是一个更快,更省力的事情。
<?phpphp
$loop = get_transient( 'loop' );= get_transient( 'loop' );
if ( false === $loop ) {if ( false === $loop ) {
// Show the last 100 tweets from the custom post type tweets.// Show the last 100 tweets from the custom post type tweets.
$query = array('post_per_page' => 100,= array('post_per_page' => 100,
'post_type' => 'tweets','post_type' => 'tweets',
'post_status' => 'publish' ) ;'post_status' => 'publish' ) ;
$loop = new WP_Query($query);= new WP_Query($query);
// transient set to last for 1 hour// transient set to last for 1 hour
set_transient('loop', $loop, 60*60);('loop', $loop, 60*60);
}}
// do normal loop stuff// do normal loop stuff
if ($loop->have_posts()) : while ($loop->have_posts()) : $loop->the_post();if ($loop->have_posts()) : while ($loop->have_posts()) : $loop->the_post();
// show content or whatever you like// show content or whatever you like
the_content();();
endwhile;endif;;endif;
?>?>
上面针对自定义帖子类型的100条推文的查询现在将保存在名为"循环"的瞬态中
数据或信息问题
使用以上瞬态,我们正在处理数据或未格式化的信息。一切都很好,并且效果很好,但是您可以将事情做得更远。
与其在每次页面加载时都处理数据,不如将所有HTML添加到循环中,然后将其保存到瞬态中,这样可以使其加载更快。
如下面的窗口小部件所示,所有窗口小部件在保存之前都被构建为完整的HTML部分。这是我的首选实现方法,因为要做的工作更少。
缓存具有瞬态的小部件
许多窗口小部件显示几乎不变的内容,例如网站上的类别或网站上的页面。只是真正的事情,如最新的评论往往会经常更改,即使如此,每分钟不止一次会令人怀疑。因此,即使使用了更活跃的小部件,也仍有缓存空间,更不用说久坐的了。
如果由于某种原因您的网站很忙,那一分钟之内可能有成千上万次点击,这会占用不必要的处理时间来一次又一次地检查所有小部件及其输出。
缓存小部件非常容易,这是一个示例小部件,用于显示来自名为" ak_events"的自定义帖子类型的事件表。
class show_ak_events_Widget extends WP_Widget { show_ak_events_Widget extends WP_Widget {
function show_ak_events_Widget() {function show_ak_events_Widget() {
/* Widget settings. *//* Widget settings. */
$widget_ops = array( 'classname' => 'ak-events', 'description' => 'Shows events in a table' );= array( 'classname' => 'ak-events', 'description' => 'Shows events in a table' );
/* Widget control settings. *//* Widget control settings. */
$control_ops = array( 'width' => 300, 'height' => 350, 'id_base' => 'ak-events' );= array( 'width' => 300, 'height' => 350, 'id_base' => 'ak-events' );
/* Create the widget. *//* Create the widget. */
$this->WP_Widget( 'ak-events', 'Show Events', $widget_ops, $control_ops );->WP_Widget( 'ak-events', 'Show Events', $widget_ops, $control_ops );
}}
function widget( $args, $instance ) {function widget( $args, $instance ) {
extract( $args );( $args );
// get cache if it exists// get cache if it exists
// $widget_id comes from the widget $args->widget_id and is the widgets unique ID// $widget_id comes from the widget $args->widget_id and is the widgets unique ID
$output = get_transient('events'.$widget_id);= get_transient('events'.$widget_id);
// if no $output do stuff inside this if statement// if no $output do stuff inside this if statement
if ( $output === false ) {if ( $output === false ) {
// set the title variable// set the title variable
$title = apply_filters('widget_title', $instance['title'] );= apply_filters('widget_title', $instance['title'] );
// standard opening of widget// standard opening of widget
$output = $before_widget;= $before_widget;
// if a title exists add it to the top of the widget// if a title exists add it to the top of the widget
$output .= ( !empty( $title ) )? $before_title . $title . $after_title : "" ;.= ( !empty( $title ) )? $before_title . $title . $after_title : "" ;
// Create query arguments for WP_Query to use// Create query arguments for WP_Query to use
$widgetargs = array( 'posts_per_page'=>'-1',= array( 'posts_per_page'=>'-1',
'post_type'=>'ak_events','post_type'=>'ak_events',
'post_status'=>'publish''post_status'=>'publish'
););
// WP_Query sets up a loop query// WP_Query sets up a loop query
$query = new WP_Query( $widgetargs );= new WP_Query( $widgetargs );
// create the opening table and top row// create the opening table and top row
$output .= "<table><tr><th>Event Name</th><th>Information</th></tr>";.= "<table><tr><th>Event Name</th><th>Information</th></tr>";
// If the WP_Query has results send them through the loop// If the WP_Query has results send them through the loop
if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();if ($query->have_posts()) : while ($query->have_posts()) : $query->the_post();
$output .= "<tr><td>" . get_the_title() . "</td><td> " . get_the_excerpt() . " </td></tr>";.= "<tr><td>" . get_the_title() . "</td><td> " . get_the_excerpt() . " </td></tr>";
endwhile;endif;;endif;
// close the table// close the table
$output .= "</table>";.= "</table>";
// close widget properly// close widget properly
$output .= $after_widget;.= $after_widget;
// save $output as a transient and set it to be 60 seconds * 5 = 5 minutes.// save $output as a transient and set it to be 60 seconds * 5 = 5 minutes.
////
set_transient( 'events'.$widget_id, $output, 60*5 );( 'events'.$widget_id, $output, 60*5 );
}}
echo $output;;
}}
function update( $new_instance, $old_instance ) {function update( $new_instance, $old_instance ) {
// save form data// save form data
$instance = $old_instance;= $old_instance;
$instance['title'] = $new_instance['title'];['title'] = $new_instance['title'];
// delete the transient so the new title setting is used// delete the transient so the new title setting is used
delete_transient('events'.$this->id);('events'.$this->id);
return $instance;return $instance;
}}
function form( $instance ) {function form( $instance ) {
$defaults = array(= array(
'title'=>'''title'=>''
););
$instance = wp_parse_args( (array) $instance, $defaults ); ?>= wp_parse_args( (array) $instance, $defaults ); ?>
<p><p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>"><label for="<?php echo $this->get_field_id( 'title' ); ?>">
<?php _e('Title:','proving-ground'); ?><?php _e('Title:','proving-ground'); ?>
</label></label>
<input id="<?php echo $this->get_field_id( 'title' ); ?>"<input id="<?php echo $this->get_field_id( 'title' ); ?>"
name="<?php echo $this->get_field_name( 'title' ); ?>"="<?php echo $this->get_field_name( 'title' ); ?>"
value="<?php echo $instance['title']; ?>" style="width:95%" />="<?php echo $instance['title']; ?>" style="width:95%" />
</p></p>
<?php<?php
}}
}}
如您所见,所有循环和处理活动都在调用小部件时运行的if语句内进行。还要注意的另一件事是,delete_transient()
每次您在管理屏幕上更新窗口小部件时,在update函数中还可以使用它来删除瞬态。
可以完成这项工作的位实际上是'events'。$ widget_id位,因为它为加载的小部件的每个实例分配了唯一的临时名称。因此,一个侧边栏中使用的窗口小部件与同一窗口小部件的相同实例分开缓存。
对主题选项使用缓存
主题选项在WordPress主题中越来越普遍。它们包含诸如主题设置之类的内容,该主题设置在每次加载网站时都会应用。很好,但是每次都会从数据库请求它,因为这是有效的方式get_option()
。
如果get_transient()
改用,则可能不会去数据库进行请求。可能来自更快访问的内存缓存或磁盘缓存。
每当我需要get_option()
使用my_get_cache_option()
我想要的WordPress选项时,这就是我为自己管理的一个简单小功能。以下代码进入functions.php
<?phpphp
function my_get_cache_option($option_name = 'ThemeAdminOptions' ){function my_get_cache_option($option_name = 'ThemeAdminOptions' ){
// get wanted transient// get wanted transient
$value = get_transient( $option_name );= get_transient( $option_name );
// check if it has any content// check if it has any content
if(false === $value){if(false === $value){
// if no content in the transient get new copy of wanted option// if no content in the transient get new copy of wanted option
$value = get_option( $option_name );= get_option( $option_name );
// set new transient with a refresh of 1 day// set new transient with a refresh of 1 day
set_transient( $option_name, $value, 60*60*24 );( $option_name, $value, 60*60*24 );
}}
// return the transient $value or newly created $value// return the transient $value or newly created $value
return $value;return $value;
}}
?>?>
我个人设置了默认的'ThemeAdminOptions'并将其用于主题选项,但是如果我想获得不同的瞬态或选项,可以这样使用它:
<?phpphp
// get cached option// get cached option
$options = my_get_cache_option('WantedOptionName');= my_get_cache_option('WantedOptionName');
// do code with options array/object/string// do code with options array/object/string
// example code// example code
echo $options['google_analytics_id'];['google_analytics_id'];
?>?>
如果要使用此解决方案,请不要delete_transient()
在将更新保存到管理页面的过程中使用。通常,您只需要更新选项,但同时您还需要删除存在的瞬态,因为其他代码将从瞬态中提取旧数据长达24小时。
<?phpphp
// update the option as normal// update the option as normal
update_option('WantedOptionName', $value );('WantedOptionName', $value );
// delete the transient that may be set// delete the transient that may be set
delete_transient('WantedOptionName');('WantedOptionName');
?>?>
将瞬变用于定时事件
Transients API的一大优点是能够设置非常简单的定时事件来为您执行功能。
假设您想每分钟从一家股票交易公司获得一个RSS feed,可以通过使用以下函数并调用来轻松实现:
<?phpphp
function setup_timed_event(){function setup_timed_event(){
// get value if set;// get value if set;
$value = get_transient('run_batch');= get_transient('run_batch');
// if not set run if statement;// if not set run if statement;
if($value === false){if($value === false){
// run every time the timer runs out// run every time the timer runs out
do_minute_batch();();
// set any value to $value;// set any value to $value;
$value = 'done';= 'done';
// setup transient to last for 60 seconds;// setup transient to last for 60 seconds;
set_transient('run_batch', $value, 60);('run_batch', $value, 60);
}}
}}
function do_minute_batch(){function do_minute_batch(){
////
// code to run in batch here that calls the RSS feed.// code to run in batch here that calls the RSS feed.
////
}}
////
// use an action to call the timed event every time the init is called. // use an action to call the timed event every time the init is called.
add_action('init','setup_timed_event');('init','setup_timed_event');
?>?>
并非每隔一分钟就会运行一次,这并不是完全正确的,就好像服务器超过一分钟不执行任何描述的活动一样,它不会运行,而是无论如何都会在下一个活动中运行。
可以通过瞬态缓存的其他活动
该列表包含了无穷无尽的内容,您可以使用transients API更快地在网站上进行搜索。在任何需要处理数据的地方,都可以使用它。如果编写了Twitter插件,则可以使用它来保存Twitter提要,并且仅在删除后更新。或者,也许您想在亚马逊商店中设置一小段时间进行缓存,这是完美且易于使用的。实际上,您需要从外部源获取数据的任何地方,都可以使用暂态API对其进行缓存。
没有什么可以阻止您根据内容的重要性使用具有不同缓存计时器的多循环进行第n次缓存的,或者确保您拥有的每个小部件都缓存了正确的内容生存期。实际上,没有什么可以阻止您通过具有秒数或用于设置的时间段的计算的字段来向小部件管理员提供缓存超时控制的widgets set_transient()
。您可以在这里无休止地走下去。
那回荡在屏幕上的东西呢?
在WordPress中,有很多东西会自动回显到屏幕上,例如the_content()
。有时您想使用这些项目,而不是使用get等价的get命令,即get_the_content()
,因为格式已经很好,不需要额外的操作。
或者,插件开发人员可能已在命令中添加了操作或过滤器,例如,the_content()
可能还添加了操作或过滤器,以将共享链接和图标附加到内容的末尾。
这两个示例都要求将数据保存到瞬态中的方式稍有不同。现在,我们必须使用ob_start()
,ob_get_contents()
,ob_end_clean()
组合保存我们呼应的屏幕,然后保存,作为一个变量作为瞬态数据
<?phpphp
$loop_output = get_transient( 'loopOutput' );= get_transient( 'loopOutput' );
if ( false === $loop_output ) {if ( false === $loop_output ) {
// Show the last 100 published posts.// Show the last 100 published posts.
$query = array('post_per_page' => 100,= array('post_per_page' => 100,
'post_status' => 'publish' ) ;'post_status' => 'publish' ) ;
// run the query// run the query
$loop = new WP_Query($query);= new WP_Query($query);
// start the output buffer to save contents of loop// start the output buffer to save contents of loop
ob_start();();
// do normal loop stuff// do normal loop stuff
if ($loop->have_posts()) : while ($loop->have_posts()) : $loop->the_post();if ($loop->have_posts()) : while ($loop->have_posts()) : $loop->the_post();
// show content or whatever you like// show content or whatever you like
?><h1><?php the_title() ?></h1><?php?><h1><?php the_title() ?></h1><?php
the_content();();
endwhile;endif;;endif;
// save the output buffer contents in a variable// save the output buffer contents in a variable
$loop_output = ob_get_contents();= ob_get_contents();
// clean the buffer as we will be using the variable from now on// clean the buffer as we will be using the variable from now on
ob_end_clean();();
// transient set to last for 1 hour// transient set to last for 1 hour
set_transient('loopOutput', $loop_output, 60*60);('loopOutput', $loop_output, 60*60);
}}
// output the new created loop if loop content does not exist. // output the new created loop if loop content does not exist.
echo $loop_output;;
?>?>
围捕
使用瞬变API可以显着提高WordPress插件,主题或小部件的速度。将来为WordPress创建时,真的值得考虑采用这种标准做法。
更新资料
感谢Erik的负载,他指出您必须WP_CACHE
启用所有这些功能才能工作。正如首席炼金术师正确地说的那样,这将导致许多白发和漫长的夜晚不知道。
要进行设置WP_CACHE
,您需要在Web服务器的根目录(或出于安全考虑而在上面的一个目录)中编辑wp-config.php。
define('WP_CACHE', true);('WP_CACHE', true);
/* Absolute path to the WordPress directory. *//* Absolute path to the WordPress directory. */
它位于" WordPress目录的绝对路径"行上方的末尾
缓存简码
也应要求提供简码。缓存简码的唯一问题是,您需要考虑它在何处以及如何出现。这是一些您可能会在其中使用短代码的地方的不同示例。
- 没有任何设置的简码,但与帖子有关。即分享与社交网络的链接
- 带有设置的简码。即按ID显示图库
- 没有设置或关系的简码。即显示当前的Facebook粉丝数
- 以上所有混合
// shortcode without any settings but relates to the post. can only be used inside the loop.
// shortcode usage// shortcode usage
// [share] // [share]
function sharelinks( $atts ){function sharelinks( $atts ){
$links = get_transient('share_links' . get_the_ID() );= get_transient('share_links' . get_the_ID() );
if($links === false){if($links === false){
// add the links you want// add the links you want
$links = "<a href='https://www.facebook.com/sharer.php?u=" . urlencode( get_permalink() ) . "&t=" . get_the_title(). "'></a>";= "<a href='https://www.facebook.com/sharer.php?u=" . urlencode( get_permalink() ) . "&t=" . get_the_title(). "'></a>";
// save the count for 30 days// save the count for 30 days
set_transient('share_links' . get_the_ID() , $links, 60*60*24*30 );('share_links' . get_the_ID() , $links, 60*60*24*30 );
}}
// return the response. **do not echo**// return the response. **do not echo**
return $links;return $links;
}}
// set shortcode // set shortcode
add_shortcode( 'share', 'sharelinks' );( 'share', 'sharelinks' );
设置的简码示例
// shortcode usage
// [my_gallery id="1" height="300" width="200"] // [my_gallery id="1" height="300" width="200"]
function shortcode_gallery( $atts ){function shortcode_gallery( $atts ){
// get the values from inside the shortcode and make them variables// get the values from inside the shortcode and make them variables
// the id, height and width have the default settings inside the array if not set// the id, height and width have the default settings inside the array if not set
// in the shortcode. // in the shortcode.
extract( shortcode_atts( array(( shortcode_atts( array(
'id' => '1','id' => '1',
'height' => '100','height' => '100',
'width' => '60','width' => '60',
), $atts ) );), $atts ) );
$gallery = get_transient('gallery' . $id . $height . $width );= get_transient('gallery' . $id . $height . $width );
if($gallery === false){if($gallery === false){
////
// Do the code that creates your gallery and return the output to a variable called Gallery// Do the code that creates your gallery and return the output to a variable called Gallery
$gallery = get_my_gallery($id, $height, $width);= get_my_gallery($id, $height, $width);
// save the count for 30 days// save the count for 30 days
set_transient('gallery' . $id . $height . $width, $gallery, 60*60*24*30 );('gallery' . $id . $height . $width, $gallery, 60*60*24*30 );
}}
// return the response. **do not echo**// return the response. **do not echo**
return $gallery;return $gallery;
}}
add_shortcode( 'my_gallery', 'shortcode_gallery' );( 'my_gallery', 'shortcode_gallery' );
显示Facebook关注人数的简码
// shortcode usage// shortcode usage
// [fans]// [fans]
function facebook_fans( $atts ){function facebook_fans( $atts ){
$fans = get_transient('facebook_fans');= get_transient('facebook_fans');
if($fans === false){if($fans === false){
// put in your own facebook ID// put in your own facebook ID
$page_id = "YOUR PAGE-ID";= "YOUR PAGE-ID";
// get the XML from facebook with the response// get the XML from facebook with the response
$xml = @simplexml_load_file("http://api.facebook.com/restserver.php? method=facebook.fql.query&query=SELECT%20fan_count%20FROM%20page%20WHERE%20page_id=".$page_id."") or die ("a lot");= @simplexml_load_file("http://api.facebook.com/restserver.php? method=facebook.fql.query&query=SELECT%20fan_count%20FROM%20page%20WHERE%20page_id=".$page_id."") or die ("a lot");
// get the fan count// get the fan count
$fans = $xml->page->fan_count;= $xml->page->fan_count;
// save the count for 1 day// save the count for 1 day
set_transient( 'facebook_fans', $fans, 60*60*24 );( 'facebook_fans', $fans, 60*60*24 );
}}
// return the response. **do not echo**// return the response. **do not echo**
return $fans;return $fans;
}}
// set shortcode // set shortcode
add_shortcode( 'fans', 'facebook_fans' );( 'fans', 'facebook_fans' );
真正实现这项工作的唯一技巧是拥有一个可以添加到词干的变量。与共享链接一样,我使用帖子ID对其进行单独设置,而在图库中则使用ID,高度和宽度,因为无论使用简码有多少种不同的方式,这都将提供完全缓存。