作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.
Martín Di Felice
验证专家 在工程
18 的经验

Martin是一个拥有9年Wordpress和后端开发项目经验的全栈开发人员.

专业知识

分享

今天,WordPress功能强大 超过30%的互联网. It’s easy to use, incredibly popular, and not going anywhere anytime soon.

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

的re are loads of articles about how to tune and optimize WordPress. 事实上,WordPress本身提供了一个 健壮的指南 关于WordPress优化.

在很大程度上, these articles and tutorials cover pretty basic yet useful concepts, 比如使用缓存插件, 与内容交付网络(cdn)集成, 尽量减少请求. While these tips are highly effective and even necessary, 最后, 他们没有解决根本的问题:大多数慢的WordPress站点都是糟糕或低效的代码造成的.

的 Advanced Guide to Optimizing WordPress 表演

WordPress可能很慢,但它不必如此.

的refore, this article is mainly aimed at providing developers and WordPress开发公司 有一些指导方针,可以帮助他们解决许多WordPress性能问题的根本原因.

WordPress提供了许多经常被开发人员忽视的性能导向特性. Code that doesn’t leverage these features can slow down the simplest of tasks , 比如取柱子. 本文详细介绍了四种可能的解决方案, 如何解决WordPress性能缓慢背后的一些潜在问题.

抓取文章

WordPress提供了从数据库中获取任何类型文章的可能性. 有三种基本方法:

  • 使用 查询_posts () 功能: This is a very direct approach, but the problem is that it overrides the main 查询,这可能会导致不便. 例如, 这可能是一个问题,如果我们想确定, at some point after f等hing the posts (such as inside footer.php),我们正在处理的是哪种页面. 事实上, 官方文档有一个说明,建议不要使用这个函数,因为您需要调用一个额外的函数来恢复原始查询. Moreover, replacing the main 查询 will negatively impact page loading times.

  • 使用 get_posts () 功能: 这就像 查询_posts (),但它不会修改主查询. 另一方面, get_posts () 属性执行查询 suppress_filters 参数设置为 真正的. 这可能导致不一致, especially if we use 查询-related filters in our code, as posts that you are not expecting in a page may be returned by this function.

  • 使用 WP_Query 类: In my opinion, this is the best way to retrieve posts from the database. 它不会改变主查询, 它以标准的方式执行, 就像任何其他WordPress查询一样.

但 whichever method we use to interact with the database, 我们还需要考虑其他事情.

限制查询

We should always specify how many posts our 查询 must f等h.

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

WordPress lets us indicate -1 as a possible value for that 参数, 在这种情况下,系统将尝试获取满足定义条件的所有帖子.

这不是一个好的做法, even if we are certain that we’ll only get a few results back as the response.

For one, we rarely can be certain about only getting a few results back. 即使我们可以, 不设置限制将要求数据库引擎扫描整个数据库查找匹配项.

相反, 限制结果通常使数据库引擎只能部分扫描数据, which translates into less processing time and faster response.

WordPress默认做的另一件事, 哪些会对性能产生负面影响, 它是否试图带来粘性帖子并计算在查询中发现了多少行.

Often, though, we don’t really need that information. 添加这两个参数将禁用这些功能并加快查询速度:

$查询 = new WP_Query(数组)
	“ignore_sticky_posts”	=> 真正的,
	“no_found_rows”		=> 真正的
	)
); 

从查询中排除帖子

从查询中排除帖子

有时 we want to exclude certain posts from the 查询. WordPress offers a pretty direct way of achieving it: using the post__not_in 参数. 例如:

posts_to_exclude美元 	= 数组(1,2,3);
posts_per_page美元	= 10;


$查询 = new WP_Query(数组)
	“posts_per_page”	=> posts_per_page美元,
	“post__not_in”		=> posts_to_exclude美元
	)
);


for ( $i = 0; $i < count( $查询->posts ); $i++ ) {
	//do stuff with $查询->posts[ $i ]
}

但是,虽然这非常简单,但它不是最优的,因为它在内部生成一个子查询. Especially in large installations, this can lead to slow responses. 让PHP解释器通过一些简单的修改来完成这个处理会更快:

posts_to_exclude美元 	= 数组(1,2,3);
posts_per_page美元	= 10;


$查询 = new WP_Query(数组)
	“posts_per_page”	=> posts_per_page美元 + count( posts_to_exclude美元 )
	)
);


for ( $i = 0; $i < count( $查询->posts ) && $i < posts_per_page美元; $i++ ) {
	if ( ! in_数组( $查询->posts[ $i ]->ID, posts_to_exclude美元 ) ) {
		//do stuff with $查询->posts[ $i ]
	}
}

我在那里做了什么?

基本上, 我从数据库引擎中卸下了一些工作,把它留给了PHP引擎, 在内存中做同样的事情, 这样更快.

如何?

首先,我去掉了 post__not_in 参数。.

由于查询可能会给我们带来一些我们不想要的帖子,所以我增加了 posts_per_page 参数. 这样我就可以确保,即使我的回复中有一些不喜欢的帖子,我至少会 posts_per_page美元 期望职位.

的n, when I loop over the posts I only process those which are not inside the posts_to_exclude美元 数组.

避免复杂的参数化

所有这些 查询方法 offer a wide variety of possibilities for f等hing posts: by categories, 通过元键或值, 按日期, 作者, 等.

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

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

最大限度地利用WordPress选项

WordPress Options API provides a series of tools to easily load or save data. It’s useful for handling small pieces of information, WordPress提供的其他机制(如帖子或分类法)过于复杂.

Wordpress选项优化

例如, 如果我们想要存储身份验证密钥或网站标题的背景颜色, 选择是我们所要寻找的.

WordPress not only gives us the functions to handle them, but it also enables us to do so in the most efficient way.

Some of the options are even loaded directly when the 系统启动, thus providing us with faster access (when creating a new option, we need to consider whether we want to autoload it or not).

考虑, 例如, 一个网站上,我们有一个旋转木马显示突发新闻指定后端. Our first instinct would be to use a meta key for that as follows:

/ /函数.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
	//它不是一个修订或自动保存,等等.
	$post_id, 'is_breaking_news', ! empty ($_POST['is_breaking_news']));
} );


/ /头版.php
$查询 = new WP_Query(数组)
	“posts_per_page”	=> 1,
	“meta_key”		=> 'is_breaking_news'
	)
);
$breaking_news = $查询->posts[0] ?:空;

As you can see, this approach is very simple, but it is not optimal. 它将执行数据库查询,试图找到具有特定元键的帖子. 我们可以使用一个选项来实现类似的结果:

/ /函数.php
Add_action ('save_post', function ($post_id) {
	//与post验证相同
	if ( ! empty ($_POST['is_breaking_news']))
		Update_option ('breaking_news_id', $post_id);
} );


/ /头版.php
if ( $breaking_news_id = get_option( 'breaking_news_id' ) )
	$breaking_news = get_post($breaking_news_id);
其他的
	$breaking_news = NULL;

的 functionality slightly varies from one example to another.

在第一段代码中, 我们将永远得到最新的突发新闻, 就这篇文章的发布日期而言.

在第二个例子中, 每次有新帖子被设为突发新闻, 它将覆盖之前的突发新闻.

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

And, 最后, we changed a heavy database 查询 (using WP_Query with meta keys) into a simple and direct 查询 (calling get_post ()),这是一种更好、更高效的方法.

We could also make a small change, and use transients instead of options.

Transients work similarly but allow us to specify an expiration time.

例如, 突发新闻, it fits like a glove because we don’t want an old post as breaking news, 如果我们把改变或消除突发新闻的任务留给管理员, 他可能会忘记做这件事. So, with two simple changes, we add an expiration date:

/ /函数.php
Add_action ('save_post', function ($post_id) {
	//与post验证相同
	
	// Let's say we want that breaking news for one hour
	//(3600 =一小时内的秒数).
	if ( ! empty ($_POST['is_breaking_news']))
		set_transient( 'breaking_news_id', $post_id, 3600 ); 
} );


/ /头版.php
if ( $breaking_news_id = get_transient( 'breaking_news_id' ) )
	$breaking_news = get_post($breaking_news_id);
其他的
	$breaking_news = NULL;

启用持久缓存

WordPress本身就有 对象缓存机制.

Options, 例如, are cached using that mechanism.

但, 默认情况下, 缓存不是持久化的, meaning that it only lives for the duration of a single request. 所有数据都缓存在内存中,以便更快地访问,但仅在该请求期间可用.

持久缓存说明

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

一些全页缓存插件附带了持久缓存插件(例如W3 Total cache)。, 但其他人则不然, 我们需要单独安装.

这将取决于我们平台的架构, 我们是否会使用文件, Memcached or some other mechanism to store cached data, 但是我们应该利用这个惊人的特性.

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

主要原因是, 这取决于我们平台的架构, 有些缓存技术可以工作,有些则不行.

如果我们将网站托管在分布式服务器上, 例如, 我们应该使用外部缓存系统, (例如 Memcached 服务器), 但如果我们的网站驻留在一台服务器上, we could save some money by simply using the file system to cache.

One thing that we need to take into account is cache expiration. This is the most common pitfall of working with persistent caching.

如果我们不能正确处理这个问题, 我们的用户会抱怨他们看不到他们所做的更改,或者他们的更改花了太长时间才应用.

有时我们会发现自己在性能和动态之间做出权衡, 但即使有这些障碍, 持久缓存实际上是每个WordPress安装都应该利用的功能.

最快的方式

If we need to communicate via AJAX with our website, WordPress 提供了一些抽象 at the time of processing the request on the server side.

尽管这些技术可以在编程后端工具或从前端提交表单时使用, they should be avoided if it is not strictly necessary.

的 reason for this is that in order to use those mechanisms, we are obligated to make a post request to some file located inside the wp-admin 文件夹. 大多数(如果不是全部的话)WordPress全页缓存插件既不缓存帖子请求,也不缓存对管理员文件的调用.

例如, if we dynamically load more posts when the user is scrolling our homepage, it would be better to directly call to some other front-end page, 哪一个将获得缓存的好处.

We could then parse the results via JavaScript in the browser.

是的, 我们发送的数据比我们需要的要多, but we are winning in terms of processing speed and response time.

不要认为WordPress太慢了

这些只是开发者在编写代码时应该考虑的一些建议 WordPress.

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

我们只关注插件应该如何工作,而不是它如何处理该功能,或者 如何有效地做到这一点.

从上面看, 很明显,WordPress表现不佳的根本原因是糟糕和低效的代码. 然而, WordPress通过各种api提供了所有必要的功能,这些api可以帮助我们 构建性能更高的插件和主题 without compromising the speed of the overall platform.

聘请Toptal这方面的专家.
现在雇佣
Martín Di Felice

Martín Di Felice

验证专家 在工程
18 的经验

阿根廷布宜诺斯艾利斯省Villa Ballester

2016年4月4日成为会员

作者简介

Martin是一个拥有9年Wordpress和后端开发项目经验的全栈开发人员.

作者都是各自领域经过审查的专家,并撰写他们有经验的主题. 我们所有的内容都经过同行评审,并由同一领域的Toptal专家验证.

专业知识

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

世界级的文章,每周发一次.

订阅意味着同意我们的 隐私政策

Toptal开发者

加入总冠军® 社区.