为 PIX 主题添加 Redis 缓存支持

前言

前面的文章【WP提升页面切换速度(bfcache) 】讲了如何将admin-ajax.php的请求缓存到用户本地,并且通过链接预取Instant.page实现无缝切换页面,但是无法对首次加载进行提速,这篇文章以PIX主题为例,将请求通过Redis缓存,真正的提升访问速度。

像文章列表和片刻列表这些不需要频繁刷新的内容,缓存当然没有任何影响。本文仅展示缓存这两个,其他请求可以让AI改。

步骤

前提条件

  • PHP必须安装Redis扩展
  • wp必须安装并启用Redis Object Cache插件

修改前先备份主题代码,修改后有什么bug可以评论区交流,可以只学习思路自己动手。

通用缓存函数

将以下代码添加到主题根目录下的function.php

function wp_ajax_redis_cache($callback, $ttl = 600){

    if (is_user_logged_in()) {
        $result = $callback();
        wp_send_json($result);
    }

    $version = wp_cache_get('ajax_cache_version', 'ajax');

    if(!$version){
        $version = 1;
        wp_cache_set('ajax_cache_version', $version, 'ajax');
    }

    $key_data = [
        'v' => $version,
        'action' => $_REQUEST['action'] ?? '',
        'cat' => $_REQUEST['cat'] ?? '',
        'paged' => $_REQUEST['paged'] ?? ''
    ];

    $cache_key = 'ajax_cache_' . md5(json_encode($key_data));

    $cached = wp_cache_get($cache_key, 'ajax');

    if($cached !== false){
        wp_send_json($cached);
    }

    $result = $callback();

    if(!empty($result['content'])){
        wp_cache_set($cache_key, $result, 'ajax', $ttl);
    }

    wp_send_json($result);
}

增加了用户登录校验,不会对登录用户进行缓存或读取缓存。

修改文章列表加载函数

代码位置:pix/inc/pix-post.php : 查找到blog_mod_loop()函数,替换为以下代码。

function blog_mod_loop(){

    wp_ajax_redis_cache(function(){

        global $wp_query;

        $sticky_html = '';
        $cat = !empty($_REQUEST['cat']) ? intval($_REQUEST['cat']) : '';

        $sticky = get_option('sticky_posts');

        $args = array(
            'post_type' => 'post',
            'cat' => $cat,
            'post_status' => 'publish',
        );

        if(empty($cat)){
            $args['post__not_in'] = $sticky;
            $sticky_html = posts_sticky_loop();
        }

        query_posts($args);

        if(have_posts()):

            ob_start();

            while(have_posts()): the_post();
                post_show_type();
            endwhile;

            $posts_html = ob_get_clean();

        else:

            $posts_html = '<p class="no_posts"><img class="s_nodata" src="'.THEME_URL.'/img/nodata.png"></p>';

        endif;

        if(get_op('qiniu_cdn')) {
            $posts_html = ajax_qiniu_cdn_replace($posts_html);
        }

        return [
            'posts' => json_encode($wp_query->query_vars),
            'max_page' => $wp_query->max_num_pages,
            'found_posts' => $wp_query->found_posts,
            'content' => $sticky_html.$posts_html
        ];

    }, 600); 

}

代码里的600指的是缓存600秒,可以自己调整,像文章列表,每天刷新一次缓存都没问题,毕竟如果只有你一个人发布文章,可以手动通过Redis插件刷新缓存。我建议设置为21600(6小时)。

修改片刻列表加载函数

代码位置: pix/inc/pix-moment.php : 查找函数moment_cat_filter(),替换。

function moment_cat_filter(){

    wp_ajax_redis_cache(function(){

        if (session_id()) {
            session_write_close();
        }

        global $wp_query;

        $sticky_html = '';
        $cat = !empty($_REQUEST['cat']) ? intval($_REQUEST['cat']) : get_all_topics_id();

        $sticky = get_option('sticky_posts');

        $args = array(
            'post_type' => 'moment',
            'tax_query' => array(
                array(
                    'taxonomy' => 'moments',
                    'field'    => 'term_id',
                    'terms'    => $cat,
                ),
            ),
            'post_status' => 'publish',
        );

        // 只在全部分类显示置顶
        if(empty($_REQUEST['cat'])){
            $args['post__not_in'] = $sticky;
            $sticky_html = moment_sticky_loop();
        }

        query_posts($args);

        if(have_posts()):

            ob_start();

            while(have_posts()): the_post();
                get_template_part('tpl/content', 'moment');
            endwhile;

            $posts_html = ob_get_clean();

        else:

            $posts_html = '<p class="no_posts"><img class="s_nodata" src="'.THEME_URL.'/img/nodata.png"></p>';

        endif;

        $output = array();
        $post_list = $wp_query->posts;

        foreach($post_list as $list){

            $pid = $list->ID;

            $data = array(
                'content' => $list->post_content,
                'pid' => $pid
            );

            $output[] = $data;

        }

        if(get_op('qiniu_cdn')){
            $posts_html = ajax_qiniu_cdn_replace($posts_html);
            $sticky_html = ajax_qiniu_cdn_replace($sticky_html);
        }

        return array(
            'posts' => json_encode($wp_query->query_vars),
            'max_page' => $wp_query->max_num_pages,
            'found_posts' => $wp_query->found_posts,
            'content' => $sticky_html.$posts_html,
            'post_data' => $output,
        );

    }, 600);
}

修改后,文章和片刻列表的请求都会被缓存到Redis,用户端可以直接获取结果,不需要经过复杂处理。

自动刷新缓存

以下代码同样添加到function.php

function bump_ajax_cache_version($post_id){

    if (wp_is_post_revision($post_id)) {
        return;
    }

    $version = wp_cache_get('ajax_cache_version', 'ajax');

    if(!$version){
        $version = 1;
    }

    wp_cache_set('ajax_cache_version', $version + 1, 'ajax');

}

add_action('save_post', 'bump_ajax_cache_version');
add_action('deleted_post', 'bump_ajax_cache_version');
add_action('trash_post', 'bump_ajax_cache_version');

发布/更新/删除文章时自动刷新Redis缓存。

总结

如果你追求极致速度,可以了解Nginx microcache,毕竟Redis缓存仍然通过WP实现。

有bug麻烦在评论反馈一下,谢谢[偷笑]。

摸鱼小屋」 (atmoyu.com)版权所有,引用、转载时必须标明原文出处!

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息