优化 WordPress 性能的高级指南

已发表: 2022-03-11

今天,WordPress 为超过 30% 的互联网提供支持。 它易于使用,非常受欢迎,而且不会很快出现在任何地方。

但是 WordPress 可能很慢。 那么如何优化呢?

有大量关于如何调整和优化 WordPress 的文章。 事实上,WordPress 本身提供了一个强大的 WordPress 优化指南。

在大多数情况下,这些文章和教程涵盖了非常基本但有用的概念,例如使用缓存插件、与内容交付网络 (CDN) 集成以及最小化请求。 虽然这些技巧非常有效,甚至是必要的,但最终,它们并没有解决根本问题:大多数缓慢的 WordPress 网站都是由糟糕或低效的代码造成的。

优化 WordPress 性能的高级指南

WordPress 可能很慢,但并非必须如此。
鸣叫

因此,本文主要旨在为开发人员和 WordPress 开发公司提供一些指导方针,以帮助他们解决许多 WordPress 性能问题的根本原因。

WordPress 提供了许多开发人员经常忽略的面向性能的功能。 不利用这些功能的代码可能会减慢最简单的任务,例如获取帖子。 本文详细介绍了四种可能的解决方案,它们解决了 WordPress 性能缓慢背后的一些潜在问题。

获取帖子

WordPress 提供了从数据库中获取任何类型帖子的可能性。 有以下三种基本方法:

  • 使用query_posts()函数:这是一种非常直接的方法,但问题是它会覆盖主查询,这可能会导致不便。 例如,如果我们想在获取帖子后的某个时间点(例如在footer.php )确定我们正在处理的页面类型,这可能是一个问题。 事实上,官方文档有一个注释建议不要使用此函数,因为您需要调用一个附加函数来恢复原始查询。 此外,替换主查询将对页面加载时间产生负面影响。

  • 使用get_posts()函数:这几乎与query_posts()一样工作,但它不会修改主查询。 另一方面, get_posts()默认情况下执行查询时将suppress_filters参数设置为true 。 这可能会导致不一致,特别是如果我们在代码中使用与查询相关的过滤器,因为此函数可能会返回您不希望出现在页面中的帖子。

  • 使用WP_Query类:在我看来,这是从数据库中检索帖子的最佳方式。 它不会改变主查询,并以标准方式执行,就像任何其他 WordPress 查询一样。

但是无论我们使用哪种方法与数据库交互,我们都需要考虑其他一些事情。

限制查询

我们应该始终指定我们的查询必须获取多少帖子。

为了实现这一点,我们使用了posts_per_page参数。

WordPress 让我们将 -1 指示为该参数的可能值,在这种情况下,系统将尝试获取满足定义条件的所有帖子。

这不是一个好的做法,即使我们确信我们只会得到一些结果作为响应。

一方面,我们很少能确定只能得到一些结果。 即使我们可以,设置不限制将要求数据库引擎扫描整个数据库以查找匹配项。

相反,限制结果通常会使数据库引擎只扫描部分数据,这意味着更少的处理时间和更快的响应。

WordPress 默认做的另一件事可能会对性能产生不利影响,它会尝试引入粘性帖子并计算在查询中找到了多少行。

但是,我们通常并不真正需要这些信息。 添加这两个参数将禁用这些功能并加快我们的查询:

 $query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );

从查询中排除帖子

Wordpress 从查询中排除帖子

有时我们想从查询中排除某些帖子。 WordPress 提供了一种非常直接的实现方式:使用post__not_in参数。 例如:

 $posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }

但是虽然这很简单,但它并不是最优的,因为它在内部会生成一个子查询。 尤其是在大型安装中,这可能会导致响应缓慢。 通过一些简单的修改让 PHP 解释器完成该处理会更快:

 $posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }

我在那里做了什么?

基本上,我从数据库引擎中删除了一些工作,并将其留给 PHP 引擎,它做同样的事情,但在内存中,这要快得多。

如何?

首先,我从查询中删除了post__not_in参数。

由于查询可能会给我们带来一些我们不想要的帖子,因此我增加了posts_per_page参数。 这样我就可以确保,即使我的回复中有一些不受欢迎的帖子,我也会在那里至少有$posts_per_page所需的帖子。

然后,当我遍历帖子时,我只处理那些不在$posts_to_exclude数组中的帖子。

避免复杂的参数化

所有这些查询方法都为获取帖子提供了多种可能性:按类别、按元键或值、按日期、按作者等。

虽然这种灵活性是一项强大的功能,但应谨慎使用,因为参数化可能会转化为复杂的表连接和昂贵的数据库操作。

在下一节中,我们将概述一种在不影响性能的情况下仍能实现类似功能的优雅方法。

充分利用 WordPress 选项

WordPress 选项 API 提供了一系列工具来轻松加载或保存数据。 它对于处理少量信息很有用,因为 WordPress 提供的其他机制(如帖子或分类法)过于复杂。

WordPress 选项优化

例如,如果我们想要存储身份验证密钥或网站标题的背景颜色,则我们正在寻找选项。

WordPress 不仅为我们提供了处理它们的功能,而且还使我们能够以最有效的方式进行处理。

有些选项甚至在系统启动时直接加载,从而为我们提供了更快的访问速度(在创建新选项时,我们需要考虑是否要自动加载它)。

例如,考虑一个网站,我们有一个轮播显示后端指定的突发新闻。 我们的第一反应是使用元密钥,如下所示:

 // functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;

如您所见,这种方法非常简单,但不是最优的。 它将执行数据库查询,尝试查找具有特定元键的帖子。 我们可以使用一个选项来实现类似的结果:

 // functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;

功能从一个示例到另一个示例略有不同。

在第一段代码中,我们将始终获得最新的突发新闻,就帖子的发布日期而言。

在第二个中,每次将新帖子设置为突发新闻时,都会覆盖之前的突发新闻。

但是因为我们可能一次只想要一篇突发新闻,所以这应该不是问题。

最后,我们将繁重的数据库查询(使用带有元键的WP_Query )更改为简单直接的查询(调用get_post() ),这是一种更好、性能更高的方法。

我们也可以做一个小的改变,并使用瞬变代替选项。

瞬态的工作方式类似,但允许我们指定过期时间。

例如,对于突发新闻,它就像手套一样合适,因为我们不希望将旧帖子作为突发新闻,如果我们将更改或删除该突发新闻的任务留给管理员,[s]他可能会忘记做它。 因此,通过两个简单的更改,我们添加了一个到期日期:

 // functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;

启用持久缓存

WordPress 本机具有对象缓存机制。

例如,选项是使用该机制缓存的。

但是,默认情况下,缓存不是持久的,这意味着它只存在于单个请求的持续时间内。 所有数据都缓存在内存中,以便更快地访问,但它仅在该请求期间可用。

持久缓存的插图

支持持久缓存需要安装持久缓存插件。

一些整页缓存插件附带了一个持久缓存插件(例如 W3 Total Cache),但有些没有,我们需要单独安装它。

这将取决于我们平台的架构,我们是否会使用文件、Memcached 或其他一些机制来存储缓存数据,但我们应该利用这个惊人的特性。

有人可能会问:“如果这是一个很棒的功能,为什么 WordPress 不默认启用它”?

主要原因是,根据我们平台的架构,一些缓存技术会起作用,而另一些则不会。

例如,如果我们将网站托管在我们的分布式服务器中,我们应该使用外部缓存系统(例如 Memcached 服务器),但如果我们的网站驻留在单个服务器上,我们可以通过简单地使用文件系统来节省一些钱缓存。

我们需要考虑的一件事是缓存过期。 这是使用持久缓存最常见的缺陷。

如果我们没有正确解决这个问题,我们的用户会抱怨他们不会看到他们所做的更改,或者他们的更改需要太长时间才能应用。

有时我们会发现自己在性能和动态之间进行权衡,但即使有这些障碍,持久缓存也是几乎每个 WordPress 安装都应该利用的东西。

AJAXing 最快的方式

如果我们需要通过 AJAX 与我们的网站进行通信,WordPress 在服务器端处理请求时会提供一些抽象。

即使在编写后端工具或从前端提交表单时可以使用这些技术,但如果不是绝对必要的话,应该避免使用它们。

这样做的原因是为了使用这些机制,我们有义务向位于wp-admin文件夹中的某个文件发出 post 请求。 大多数(如果不是全部)WordPress 全页缓存插件既不缓存发布请求也不缓存对管理员文件的调用。

例如,如果我们在用户滚动我们的主页时动态加载更多帖子,那么最好直接调用其他一些前端页面,这样可以获得缓存的好处。

然后我们可以通过浏览器中的 JavaScript 解析结果。

是的,我们发送的数据比我们需要的多,但我们在处理速度和响应时间方面取得了胜利。

打破 WordPress 只是慢的观念

这些只是开发人员在为 WordPress 编码时应考虑的一些建议。

有时,我们忘记了我们的插件或主题可能需要与其他插件一起使用,或者我们的站点可能由托管公司提供服务,该托管公司为数百或数千个具有公共数据库的其他站点提供服务。

我们只关注插件应该如何运行,而不是它如何处理该功能,或者如何以有效的方式完成它。

从上面可以看出,WordPress 性能不佳的根本原因是糟糕且低效的代码。 但是,WordPress 通过其各种 API 提供了所有必要的功能,这些 API 可以帮助我们构建性能更高的插件和主题,而不会影响整个平台的速度。