WordPress完全性能优化指南

Wordpress 完全性能优化指南

WordPress 是一个内容管理系统 (CMS),可让您使用可视化工具构建网站。WordPress 有许多第三方开发的免费的模板和插件,安装方式简单易用,无限的扩展能力也让Wordpress能实现各种各样的效果,论坛,商城,社交,社区等等。

但是凡事皆有代价,无限的扩展能力所换来的是性能效率极其低下,面对同为 CMS 的Typecho、Z-Blog,Wordpress显得非常臃肿。

明白了Wordpress的性能上限,就可以在上限内设定优化目标了。

效果

先看效果

阿里云 ECS 经济型e实例99计划 2核2G,3M固定带宽

测试环境:

  • openresty:1.21
  • php:8.2
  • redis:7.2
  • mysql:8.2

使用docker部署

PageSpeed Insights

谷歌基准测试

itdog网站测速

缓慢测试(大约三并发)

广州移动访问响应计时

数据库缓存

首当其冲就是数据库缓存了,php在执行函数最消耗时间的就是查询SQL数据库了,一般来讲一个页面的数据库查询大概在120到260次左右,使用Redis或者Memcached缓存,原理就是将php查询过的数据库缓存下来,下一次相同内容就不再查询数据库了,直接从缓存获取,极大的提高php执行效率。

Redis 为什么这么快?

Redis的操作都是基于内存的,CPU不是 Redis性能瓶颈,,Redis的瓶颈是机器内存和网络带宽。因为Redis的瓶颈不是cpu的运行速度,而往往是网络带宽和机器的内存大小。再说了,单线程切换开销小,容易实现既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了
  • 安装Redis程序
  • 为PHP环境安装redis扩展(安装完成之后,记得重启一下php服务)
  • 安装WP插件(Redis Object Cache
  • 配置Redis链接,启用 Redis Object Cache 插件
为Wordprss安装redis扩展

配置Redis链接,在网站根目录中修改 wp-config.php 文件

require_once ABSPATH . 'wp-settings.php'; 前添加以下内容。

define( 'WP_REDIS_HOST', 'redis' );
define( 'WP_REDIS_PORT', 6379 );
define( 'WP_REDIS_PASSWORD', 'zheshimima' );

define( 'WP_REDIS_PREFIX', 'k_' );
define( 'WP_REDIS_DATABASE', 1 ); // 0-15

define( 'WP_REDIS_TIMEOUT', 1 );
define( 'WP_REDIS_READ_TIMEOUT', 1 );

配置参数如下,具体参考Redis Object Cache文档:

https://github.com/rhubarbgroup/redis-cache/#configuration

配置常量默认描述
WP_REDIS_HOST127.0.0.1Redis 服务器的主机名
WP_REDIS_PORT6379Redis 服务器的端口
WP_REDIS_SCHEMEtcp用于连接的方案:或tcpunix
WP_REDIS_DATABASE0缓存使用的数据库:0-15
WP_REDIS_PASSWORDRedis 服务器的密码,支持 Redis ACLs 数组:['user', 'password']
WP_REDIS_TIMEOUT1连接超时(以秒为单位)
WP_REDIS_READ_TIMEOUT1读取/写入时的超时(以秒为单位)

注意,如果你使用的是1panel面板搭建的Redis容器,请跟我一样把HOST设置成”redis”。

最后进入插件设置,开启缓存

Wordpress Redis使用状况

可以看到Redis成功缓存了17万条数据,从而节省大量SQL查询。


OPcache

OPcache(Opcode Cache)是 PHP 的一个内置扩展,用于缓存 PHP 脚本的解释代码(opcode),从而提高 PHP 应用程序的性能。当 PHP 脚本首次被解释执行时,PHP 将脚本编译成一组中间代码(opcode),并在运行时执行这些 opcode。OPcache 的作用是缓存这些 opcode,避免在每次请求时都重新解释和执行相同的脚本。

同时,PHP 8 在PHP的内核中添加了 JIT 编译器,可以极大地提高性能。更强的cpu密集处理,或许以后php也可以适当做复杂协议解析。

为PHP环境安装 opcache 扩展

开启JIT

如果你使用的是PHP8及以上版本,请在PHP配置文件中加入以下代码来启用JIT。

寻找 [opcache] ,在 [opcache] 下方加入内容。如果没有则直接在最底部加入。

[opcache]
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.jit=1205
opcache.jit_buffer_size=128M

保存后重启PHP服务

刷新便能看到效果,负载肉眼可见的降低了

具体详细配置可以看我之前的文章,PHP8 JIT 配置说明


页面缓存

为不会变化的页面建立缓存,避免每次访问页面都要从头执行PHP代码,这将能剩下非常多的执行时间。

安装WP Fastest Cache插件。

启用缓存系统

使用预加载 – 自动创建所有站点的缓存

Wordpress 页面缓存插件

如果你用的页面有动态数据,不适合生成缓存,可以为页面添加排除选项,排除符合规则的页面。

亦或者,让数据进行动静分离,所有动态数据用js单独请求接口。

如:评论、点赞、签到、购买等数据


优化图像

WebP是一种图片文件格式,他同时提供了有损压缩与无损压缩,它的优点就是同等画面质量下,体积比jpg、png这些少了25%以上。

大家都知道移动互联网时代,页面大小和用户留存息息相关,更快的加载页面才能让更多用户关注到你的内容,而图片一直都是页面体积的大头,拿我们的活动页面来说,图片占据了80%以上的页面大小。所以使用webp的话,可以瞬间让页面大小下降1/4,不得不说是一个极具性价比的优化点。

优化图片大小也能减少服务器宽带压力,增加利用率。

21 KB的webp图片

webp图片(21 KB)

 56 KB的jpg图片

jpg图片(56 KB)

首先,我们需要一个工具把图片转成webp格式,这里就使用google的官方工具即可。

也可以使用在线工具(谷歌维护)进行转换:https://squoosh.app/

当然,对于已经在Wordpress的媒体图片,怎么转换为webp才是问题。

可以在function.php中添加以下代码,为媒体库的jpg、png文件添加一键生成webp格式的按钮

注意,这是手动转化,会生成一个新的webp图片,不会影响旧图片文件

// 媒体库网格按钮
add_filter('attachment_fields_to_edit', function ($form_fields, $post) {
    $ext = pathinfo(get_attached_file($post->ID))['extension'];
    if (in_array($ext, ['jpg', 'jpeg', 'png'])) {
        $form_fields['custom-button'] = [
            'label' => '扩展功能',
            'input' => 'html',
            'html' => sprintf(
                '<a class="button" href="#the-webp" onclick="%s" >生成webp图片</a>',
                "if (!confirm('是否生成webp图片'))return; jQuery.post('admin-ajax.php',{action: 'krjojo_tool_webp',id:'" . $post->ID . "'},function() {location.reload()});"
            )
        ];
    }
    return $form_fields;
}, 10, 2);

// 媒体库列表按钮
add_filter('media_row_actions', function ($actions, $post) {
    $ext = pathinfo(get_attached_file($post->ID))['extension'];
    if (in_array($ext, ['jpg', 'jpeg', 'png'])) {
        $actions['webp'] = sprintf(
            '<a href="#the-webp" onclick="%s" >生成webp图片</a>',
            "if (!confirm('是否生成webp图片'))return; jQuery.post('admin-ajax.php',{action: 'krjojo_tool_webp',id:'" . $post->ID . "'},function() {location.reload()});"
        );
    }
    return $actions;
}, 10, 2);

// 接口
add_action('wp_ajax_krjojo_tool_webp', function () {
    if (!current_user_can('manage_options')) {
        return;
    }
    $id = $_POST['id'] ?? '';
    if ($id == '') return;
    // 获取媒体文件的物理文件路径;
    $inputFile = get_attached_file($id);
    // 获取图片后缀
    $ext = pathinfo($inputFile);
    // 设置保存的WebP文件名及路径
    $outputFileName = $ext['dirname'] . '/' . $ext['filename'] . '.webp';
    // 创建新的WebP图像对象
    switch ($ext['extension']) {
        case 'png':
            $outputImage = imagecreatefrompng($inputFile);
            break;
            // case 'gif':
            //     $outputImage = imagecreatefromgif($inputFile);
            //     break;
        case 'jpeg':
            $outputImage = imagecreatefromjpeg($inputFile);
            break;
        case 'jpg':
            $outputImage = imagecreatefromjpeg($inputFile);
            break;
        default:
            return;
            break;
    }

    // 调用imagick函数进行转换并保存
    imagewebp($outputImage, $outputFileName);
    // 清理
    imagedestroy($outputImage);
    // 导入
    require_once(ABSPATH . 'wp-admin/includes/image.php');
    require_once(ABSPATH . 'wp-admin/includes/file.php');
    require_once(ABSPATH . 'wp-admin/includes/media.php');
    $file_array = [
        'tmp_name' => $outputFileName,
        'name' => basename($outputFileName),
        // 'type' => wp_check_filetype(basename($outputFileName), null)['type']
    ];
    media_handle_sideload($file_array, 0, $ext['filename']);
    return 'ok';
    // Don't forget to stop execution afterward.
    // wp_die();
});

注意,该代码需要用到GD库,请为php安装GD扩展才能使用!


少装不必要的插件

一个6.4.3版本的Wordpress解压后大小才70M,而一个WooCommerce插件包就已经接近50M了,大量的插件会影响网站的速度,因为它们会创建更多的代码和资源,从而影响加载速度。

因为各种业务需要,我们没办法本末倒置,把WooCommerce这类插件去掉显然是不现实的,但是有些插件我们可以通过几行代码来代替它实现我们想要的功能。

在主题function.php中添加

SMTP邮件服务

add_action('phpmailer_init', function ($phpmailer) {
  $phpmailer->FromName = '手里有只毛毛虫'; //发件人名称
  $phpmailer->Host = 'smtp.exmail.qq.com'; //修改为你使用的邮箱SMTP服务器
  $phpmailer->Port = 465;                  //SMTP端口
  $phpmailer->Username = '123@krjojo.com';     //邮箱账户
  $phpmailer->Password = 'krjojocommima';  //邮箱授权码(此处填写QQ邮箱生成的授权码)
  $phpmailer->From = '123@krjojo.com'; //邮箱账户
  $phpmailer->SMTPAuth = true;
  $phpmailer->SMTPSecure = 'ssl';          //tls or ssl (port=25时->留空,465时->ssl)
  $phpmailer->IsSMTP();
});

允许上传svg图片

add_filter('upload_mimes', function ($mimes) {
  $mimes['svg'] = 'image/svg+xml';
  return $mimes;
});

添加head页头和footer页脚

// 页头
add_action('wp_head', function () {
?>
  <!-- 可以加入seo html代码  -->
  <meta name="baidu-site-verification" content="codeva-20iVBsSgaj" />
  <meta name="google-site-verification" content="vM6oiiN7UnrRb_QIO4d1wcSXoJY4RTPjZvZ0LDNDmo4" />
  <style>.wc-block-components-address-form__last_name{ display: none;}</style>
  <?php
});

// 页脚
add_action('wp_footer', function () {
?>
  <!-- 可以加入html代码  -->
  <script>
    console.log("你好,毛毛虫,Wordpress");
  </script>
<?php
});

中文评论过滤

add_filter('pre_comment_approved', function ($approved, $commentdata) {
    // https://developer.wordpress.org/reference/hooks/pre_comment_approved/
    $comment = $commentdata['comment_content'];
    if (!preg_match('/[一-龥]/u', $comment)) {
        return 'spam';
    }
    return $approved;
}, '99', 2);

调整WP不常用的功能

定时任务

众所周知,Wordpress并不是常驻内存的,只有当请求来了,才会触发运行,运行结束,请求才会停止,那么他的定时任务又是怎么实现的呢。

https://developer.wordpress.org/plugins/cron/hooking-wp-cron-into-the-system-task-scheduler/

从官方文档得知,WordPress 在每次页面加载时都会运行一次定时任务,这显然是不合理的,一旦任务长时间没被运行,堆积过多,那么当下个用户打开网站时,将会非常缓慢。

我们可以修改这种触发定时任务的方式,让用户触发改为VPS主机帮忙触发。

禁用 WordPress 内置的定时任务系统,在网站根目录 wp-config.php 里添加

define('DISABLE_WP_CRON', true);

在宝塔或者1Panel里添加计划任务,每分钟访问一次 https://www.你的域名.com/wp-cron.php 。

关闭后台自动更新

是否有过打开后台非常缓慢的情况,但是刷新后速度又正常了,这是Wodrpress在帮你检查更新,这是阻塞的,你需要等待wordpress跟WP官方完成通信后,才会向你返回页面。

同时,自动更新是存在风险的,在无人值守的情况,一旦更新出了问题,你将完全不知情,也不能第一时间修复,难道你会指望用户来通知你的网站崩了吗。

完全禁用后台更新,在主题文件 function.php 中添加以下内容

add_filter('automatic_updater_disabled', '__return_true');

此时,你的WP将完全禁用后台更新,同时也会禁用更新通知电子邮件。

禁用不需要的功能(可选)

根据个人实际需求,禁用不需要的选项

禁用WordPress的jQuery

禁用前请确保主题和插件没有依赖jQ,不然的话…..

add_action('wp_enqueue_scripts', function () {
  wp_deregister_script('jquery');
  wp_deregister_script('jquery-core');
  wp_deregister_script('jquery-migrate');
}, 100);

禁用WordPress的emjoy

这个的话,emmm,禁用的话可以少加载一个js文件 (还是css文件来着?忘了)

remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('wp_print_styles', 'print_emoji_styles');

移除 WordPress 的版本号信息

这玩意能让header头少一行代码,用处不大,用F12看站点加载的路径就知道用的什么主题什么插件了,

remove_action('wp_head', 'wp_generator');

更多不常用的功能

如果你不了解该功能是做什么,那么请忽略,不要动它!

add_action('admin_init', function () {
    remove_meta_box('trackbacksdiv', 'post', 'normal'); // 移除文章编辑页的引用模块
    remove_meta_box('trackbacksdiv', 'page', 'normal'); // 移除页面编辑页的引用模块
    remove_meta_box('dashboard_primary', 'dashboard', 'side'); // 移除仪表盘 WordPress 新闻模块
    remove_meta_box('dashboard_right_now', 'dashboard', 'normal'); // 移除仪表盘 WordPress 概述模块
    remove_meta_box('dashboard_site_health', 'dashboard', 'normal'); // 移除仪表盘 WordPress 健康模块
    remove_action('welcome_panel', 'wp_welcome_panel'); // 移除仪表盘欢迎模块
    wp_deregister_script('autosave'); // 移除文章自动保存脚本
});

// 在后台加载时移除帮助选项卡
add_action('admin_head', function () {
    get_current_screen()->remove_help_tabs();
}, PHP_INT_MAX);

// 在工具栏菜单中移除 WordPress 标志
add_action('admin_bar_menu', function ($bar) {
    $bar->remove_node('wp-logo');
}, PHP_INT_MAX);

// 移除后台底部的 WordPress 版权信息
add_filter('admin_footer_text', '__return_empty_string', PHP_INT_MAX);

// 移除后台底部的 WordPress 版本信息
add_filter('update_footer', '__return_empty_string', PHP_INT_MAX);

// 禁用 WordPress 核心版本的更新检查
add_filter('pre_site_transient_update_core', '__return_null');

// 重写后台标题以移除 WordPress 字样
add_filter('admin_title', function ($admin_title, $title) {
    return $title . ' &lsaquo; ' . get_bloginfo('name'); 
}, 10, 2);

add_action('wp_enqueue_scripts', function () {
    wp_dequeue_style('global-styles');
    wp_dequeue_style('classic-theme-styles'); // 移除主题的经典编辑器样式表
    wp_dequeue_style('wp-block-library'); // 移除 Gutenberg 编辑器所使用的 CSS 样式表
    wp_dequeue_style('wp-block-library-theme'); // 移除 Gutenberg 编辑器所使用的主题样式表
    wp_dequeue_style('wc-blocks-style'); // 移除 WooCommerce 商品展示所使用的 CSS 样式表
    // wp_deregister_script('jquery');
}, PHP_INT_MAX);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
add_filter('xmlrpc_enabled', '__return_false'); // 禁用 XML-RPC 协议
add_filter('xmlrpc_methods', '__return_empty_array'); // 禁用 XML-RPC 协议中的所有方法
add_filter('run_wptexturize', '__return_false'); // 禁用 wptexturize 功能
add_filter('rest_enabled', '__return_false'); // 禁用 REST API
add_filter('rest_jsonp_enabled', '__return_false'); // 禁用 REST API 的 JSONP 支持
add_filter('use_block_editor_for_post_type', '__return_false');
// 移除 WordPress 自带的 emoji 表情
remove_action('wp_head', 'print_emoji_detection_script', 7);
remove_action('admin_print_scripts', 'print_emoji_detection_script');
remove_action('wp_print_styles', 'print_emoji_styles');
remove_action('admin_print_styles', 'print_emoji_styles');
remove_filter('the_content_feed', 'wp_staticize_emoji');
remove_filter('comment_text_rss', 'wp_staticize_emoji');
remove_filter('wp_mail', 'wp_staticize_emoji_for_email');
add_filter('emoji_svg_url', '__return_false');
add_filter('tiny_mce_plugins', function ($plugins) {
    if (is_array($plugins)) {
        return array_diff($plugins, array('wpemoji')); // 移除 WordPress 自带的 emoji 插件
    } else {
        return array();
    }
});
// 重定向 Feed 到首页
add_action('do_feed', function () {
    wp_safe_redirect(home_url());
}, 1);
add_action('do_feed_rdf', function () {
    wp_safe_redirect(home_url());
}, 1);
add_action('do_feed_rss', function () {
    wp_safe_redirect(home_url());
}, 1);
add_action('do_feed_rss2', function () {
    wp_safe_redirect(home_url());
}, 1);
add_action('do_feed_atom', function () {
    wp_safe_redirect(home_url());
}, 1);
// 移除 CSS 和 JavaScript 文件的版本号
add_filter('script_loader_src', function ($src) {
    if (strpos($src, 'ver=')) $src = remove_query_arg('ver', $src);
    return $src;
}, 15, 1);
add_filter('style_loader_src', function ($src) {
    if (strpos($src, 'ver=')) $src = remove_query_arg('ver', $src);
    return $src;
}, 15, 1);
remove_action('wp_head', 'xfn');
remove_action('wp_head', 'feed_links', 2); // 移除前台页面的feed链接
remove_action('wp_head', 'feed_links_extra', 3); // 移除前台页面的额外feed链接
remove_action('wp_head', 'rel_canonical'); // 移除 head 中的 canonical
remove_action('wp_head', 'wlwmanifest_link'); // 移除 Windows Live Writer 的 manifest 文件
remove_action('wp_head', 'rsd_link'); // 移除 RSD (Really Simple Discovery) 的链接
remove_action('wp_head', 'wp_resource_hints', 2); // 移除 dns-prefetch 链接和 preconnect 链接
remove_action('wp_head', 'rest_output_link_wp_head'); // 移除 REST API 的链接
remove_action('wp_head', 'wp_oembed_add_discovery_links'); // 移除 oEmbed 发现链接
remove_action('wp_head', 'index_rel_link'); // 移除当前页面与站点首页的链接
remove_action('wp_head', 'parent_post_rel_link', 10, 0); // 移除当前文章的父篇文章链接
remove_action('wp_head', 'start_post_rel_link', 10, 0); // 移除开始篇文章链接
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0); // 移除相邻文章的链接
remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0); // 移除 shortlink 的链接
remove_action('wp_head', 'wp_generator'); // 移除 WordPress 的版本号信息
remove_action('template_redirect', 'wp_shortlink_header', 11, 0); // 移除 shortlink 的 header 输出
remove_action('do_pings', 'do_all_pings', 10); // 禁用 XML-RPC 协议中的 pingback.ping 方法
remove_action('publish_post', '_publish_post_hook', 5); // 禁用 XML-RPC 协议中的 wp.newPost 方法
remove_filter('the_content', array($GLOBALS['wp_embed'], 'autoembed'), 8); // 移除 WordPress 自带的自动嵌入媒体功能

最终效果

经过优化后,2核2G阿里云,在一万文章的压力下,首页拉取20篇文章,服务器响应时间也能控制在30毫秒左右

wordpress优化后实际效果
© 版权声明
分享是一种美德,转载请保留原链接
THE END
文章不错?点个赞呗
点赞 0 分享

发表评论

您的电子邮箱地址不会被公开。 必填项已用 * 标注

rebbit
滚动至顶部