WordPress Performance Strategy

WordPress Performance exemplified by fishes swimming
Table of Contents

At this point in time, you likely came across countless articles on WordPress performance optimizations, many of which with the same old tips. It can be frustrating to continuously stumble on the same ineffective recommendations without making any progress.

If you’re feeling overwhelmed and out of options, the following steps can provide a way out. These are the same strategies we implement by default on every site we host, encompassing our comprehensive approach to performance optimization. While we delve into the specifics of our infrastructure, these principles can be adapted to suit virtually any hosting environment.

One rule that we tend to follow is that things do not need to start optimized. For example, with Google Fonts, if you need to do so much work to make them performant, perhaps you should consider whether you really need them in the first place.

In this spirit, we’ll start by disabling several WordPress features that hold its true potential.

0. WordPress Reset:

1. Disable WP Cron.

WordPress doesn’t feature a proper cron – like the one you have on your Linux server – instead it uses a function that gets triggered every time there’s a hit on the webserver.

A much better solution is using an external service to trigger cron for your WordPress installation. Here at Raybeam we use the amazing cron-job.org service, firing jobs every 5 minutes. Process triggered by cron may need some time to conclude, so there should be a reasonable gap between them.

Disabling WP Cron is done by inserting the following constant in wp-config.php file:

define( 'DISABLE_WP_CRON', true );

It’s important to check if your external cron is really running and a good plugin to do that is Cron Logger.

2. Disable or limit Post Revisions

Post Revisions saves every change you do to every post on your WordPress, and this can clearly accumulate on your database. Set it to a value you can comfortably work or disable with the following constant in wp-config.php file:

define( 'WP_POST_REVISIONS', '0' );

You can also set unlimited revisions with “-1” and set them – with the help of a plugin – to be automatically removed after a set time, something we’ll cover later.

3. Disable Trackbacks and Pingbacks

Pingbacks are an annoyance and create unnecessary clutter on your installation. You can disable them in Dashboard’s Discussion settings and also adding the following code to a functions.php file in your theme or a custom mu-plugin to disable self pingbacks:

function wpsites_disable_self_pingbacks( &$links ) {
  foreach ( $links as $l => $link )
        if ( 0 === strpos( $link, get_option( 'home' ) ) )
            unset($links[$l]);
}

add_action( 'pre_ping', 'wpsites_disable_self_pingbacks' );

Code snippet provided by Kinsta.

4. Disable Capital P

There’s a curious – to say the least – filter in WordPress that prevents you from writing the word WordPress without a capital P, like so: WordPress

You can remove it with the following function:

remove_filter( 'the_content', 'capital_P_dangit', 11 );
remove_filter( 'the_title', 'capital_P_dangit', 11 );
remove_filter( 'wp_title', 'capital_P_dangit', 11 );
remove_filter( 'comment_text', 'capital_P_dangit', 31 );
remove_filter( 'widget_text_content', 'capital_P_dangit', 11 );

Code snippet provided by ClassicPress.

And you can replace the function by just writing WordPress correctly.

5. Disable XML-RPC

XML-RPC is a mostly obsolete feature in WordPress and is often recommended to be disabled as it can improve your site’s performance, and more importantly, security, since it can be a potential attack vector for brute-force attempts. Unless you specifically need the functionality provided, such as for mobile apps or remote publishing, you can safely disable it.

There are several ways of disabling it, via Apache, Nginx or PHP, and most security and login related plugins deal with it. The simplest method is with this one-liner provided by Jeff Star from Perishable Press:

add_filter('xmlrpc_enabled', '__return_false');

The article also goes on detail on how XML-RPC actually is loaded and more ways of disabling it, so I recommend you to read it. It’s also recommended to disable X-Pingbacks:

// Disable X-Pingback header
function shapeSpace_disable_x_pingback($headers) {

	unset ($headers['X-Pingback']);
	return $headers;

}
add_filter('wp_headers', 'shapeSpace_disable_x_pingback');

Code snippets provided by Perishable Press.

6. Disable Dashicons

Dashicons are the icon fonts used by WordPress Dashboard, and they load on the frontend even when they aren’t used. Disable them with the following:

// remove dashicons
function wpdocs_dequeue_dashicon() {
	if (current_user_can( 'update_core' )) {
	    return;
	}
	wp_deregister_style('dashicons');
}
add_action( 'wp_enqueue_scripts', 'wpdocs_dequeue_dashicon' );

Code snippet provided by Fatlab.

7. Disable Emojis

Although emojis only add a negligible load to page sizes, we choose to remove them as a matter of principle.

/**
 * Disable the emoji's
 */
function disable_emojis() {
 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( 'tiny_mce_plugins', 'disable_emojis_tinymce' );
 add_filter( 'wp_resource_hints', 'disable_emojis_remove_dns_prefetch', 10, 2 );
}
add_action( 'init', 'disable_emojis' );

/**
 * Filter function used to remove the tinymce emoji plugin.
 * 
 * @param array $plugins 
 * @return array Difference betwen the two arrays
 */
function disable_emojis_tinymce( $plugins ) {
 if ( is_array( $plugins ) ) {
 return array_diff( $plugins, array( 'wpemoji' ) );
 } else {
 return array();
 }
}

/**
 * Remove emoji CDN hostname from DNS prefetching hints.
 *
 * @param array $urls URLs to print for resource hints.
 * @param string $relation_type The relation type the URLs are printed for.
 * @return array Difference betwen the two arrays.
 */
function disable_emojis_remove_dns_prefetch( $urls, $relation_type ) {
 if ( 'dns-prefetch' == $relation_type ) {
 /** This filter is documented in wp-includes/formatting.php */
 $emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/2/svg/' );

$urls = array_diff( $urls, array( $emoji_svg_url ) );
 }

return $urls;
}

Code snippet provided by Kinsta.

8. Disable Embeds

Automatic embeds can be useful, but there are several more performant alternatives available. Remove them using the following:

function disable_embeds_code_init() {

 // Remove the REST API endpoint.
 remove_action( 'rest_api_init', 'wp_oembed_register_route' );

 // Turn off oEmbed auto discovery.
 add_filter( 'embed_oembed_discover', '__return_false' );

 // Don't filter oEmbed results.
 remove_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10 );

 // Remove oEmbed discovery links.
 remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );

 // Remove oEmbed-specific JavaScript from the front-end and back-end.
 remove_action( 'wp_head', 'wp_oembed_add_host_js' );
 add_filter( 'tiny_mce_plugins', 'disable_embeds_tiny_mce_plugin' );

 // Remove all embeds rewrite rules.
 add_filter( 'rewrite_rules_array', 'disable_embeds_rewrites' );

 // Remove filter of the oEmbed result before any HTTP requests are made.
 remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10 );
}

add_action( 'init', 'disable_embeds_code_init', 9999 );

function disable_embeds_tiny_mce_plugin($plugins) {
    return array_diff($plugins, array('wpembed'));
}

function disable_embeds_rewrites($rules) {
    foreach($rules as $rule => $rewrite) {
        if(false !== strpos($rewrite, 'embed=true')) {
            unset($rules[$rule]);
        }
    }
    return $rules;
}

Code snippet provided by Kinsta

9. Control Heartbeat

Heartbeat provides important functionalities to WordPress, like post autosaves and edit locking. Limiting it to 5 minutes – or 300 seconds – may have a similar impact to disabling the functionality:

function wb_set_heartbeat_time_interval($settings) {
 $settings['interval']=300;
 return $settings;
}
add_filter('heartbeat_settings', 'wb_set_heartbeat_time_interval');

Apply the same interval to autosaves with this constant:

define( 'AUTOSAVE_INTERVAL', 300 );

Code snippets provided by SolidWP

10. Restart with a cleaner header

WordPress have accumulated a lot of stuff along the years, trying to embrace every new technology, and some of them have became obsolete or rarely used. But they still load on every page, on the most important spot.

This is a complete and safe list.

// Remove rsd link.
remove_action( 'wp_head', 'rsd_link' );

// Remove the WordPress generator tag.
remove_action( 'wp_head', 'wp_generator' );

// Remove RSS feed links.
remove_action( 'wp_head', 'feed_links', 2 );
remove_action( 'wp_head', 'feed_links_extra', 3 );

// Remove the link to the Windows Live Writer manifest file.
remove_action( 'wp_head', 'wlwmanifest_link' );

// Removes the adjacent post links.
remove_action( 'wp_head', 'adjacent_posts_rel_link', 10, 0 );
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );

// Removes the WordPress shortlink for your post.
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 );

Code snippets provided by WPExplorer

0.5: Improving WordPress

1. Don’t be afraid of plugins

At Raybeam, we’re not afraid of plugins. They’re the easiest way to add advanced features to WordPress compared to other CMS platforms. The number of plugins you use isn’t necessarily the problem, but their quality is.

Plugins should be focused, ideally doing just one thing and doing it exceptionally well. Avoid ‘all-in-one’ plugins that promise to do everything, as they often fall short and can clutter your installation.

Regarding performance, there’s no magic plugin that can instantly fix all of WordPress’s speed issues. Instead, you need to understand the common causes of slowdowns, both on the frontend and in the admin dashboard, and address them individually. Fortunately, we’ve identified some common culprits.

2. Teach your plugins some manner, preventing them from filling Options Autoload

This is probably the number one reason for a poor dashboard performance. Plugins have settings and they like them to load fast, so they fill the ‘wp_options’ table with data and set it to load on every single page. It can get worse when the plugin in question is disable/deleted and still leave data behind.

The plugin Advanced Database Cleaner gives us a good bird’s eye view of what’s happening on our database and tools to fix it. Options tab has info on every plugins data and if they autoload by default or not. General clean-up provides more fine tuned controls over Revisions and Auto-draft, a better approach than setting hard-coded limits.

3. CSS/JS concatenation is obsolete

In the past, minifying and combining files was essential for speeding up websites, especially before we had effective compression methods like Brotli and Gzip. While minification still helps by reducing file sizes, its importance has decreased with the rise of these advanced compression techniques that do a better job of shrinking files at the webserver level.

What really matters now is how we load resources on a page and whether they block the display of content. If scripts or stylesheets delay the loading of page content, it can negatively impact user perception and search engine rankings. Plugins like Debloat or Autoptimize can help by optimizing assets, making sure that important elements load first while deferring less critical ones.

4. Image handling is a very complicated matter

Images need to be high-quality and future-proof. This means they should be captured and stored at a high resolution, so they can be displayed clearly on a wide range of devices, from old smartphones to 4K screens. However, high-resolution images can also lead to large file sizes, which can slow down website loading times. WordPress automatically generate multiple copies of uploaded images at different file sizes, meaning storing multiple versions of the same image.

Lossy and lossless compressions can achieve significant reductions in file size, but the original high-quality files still need to be retained, as the compressed versions may not be suitable for all use cases, and better compression methods may appear in the future.

WebP and AVIF are cutting-edge compression formats, but their adoption has been mixed, and their benefits compared to traditional formats aren’t instantly clear. Moreover, search engines has indicated that they may penalize websites that don’t use these modern formats.

You won’t be able to handle all this by yourself without a plugin or an external service. After testing every available option for WordPress, we came to the conclusion that, while there’s no perfect option, EWWW Image Optimizer is still the best one.

EWWW IO compresses your images using an external API service, offloading the processing burden from your server. It delivers the exact image size for each device, leveraging its own CDN. And for the ultimate performance boost, it automatically provides WebP/AVIF versions of your images where supported. The premium version of this plugin is included in our humble but generous Goodies package.

5. All page builders are a burden to performance

Don’t get me wrong, page builders, including Gutenberg, Elementor, Bricks, and Breakdance, are revolutionizing WordPress for the better. Gutenberg, block themes and FSE themes had a rough start but are definitely the future of WordPress.

Elementor is often criticized within the WordPress community, but its popularity and powerful features are rivaling platforms like Wix, Squarespace, and Webflow, while being free, open-source, inside your server and working as simple as any other plugin.

However, if a classic theme (the ones that usually have a Customize menu entry) is enough for your project, prefer to use it instead of a block theme or a page builder. And if you don’t need to use any block functionality whatsoever, then consider disabling Gutenberg.

There are lots of ways to do that and restore the Classic Editor, globally or for specific users, but the best way is the plugin Disable Gutenberg.

6. WooCommerce and its plugins will drag your performance down

Installing any e-commerce solution on WordPress inevitably adds complexity and impacts its overall performance. WooCommerce – the most popular plugin for creating online stores – requires additional setup beyond its initial activation to meet real business needs. To bridge this functionality gap, store owners must rely on plugins and custom code, which can further slow down the site.

This performance impact becomes particularly noticeable as your store grows and receives more traffic and orders. While the optimization techniques we address in this article can help, there comes a point where scaling your server resources becomes necessary to maintain acceptable performance. It’s crucial to keep this scenario in mind when planning to power your online shop with WooCommerce.

7. Be always on guard

WordPress sites can grow complex over time, making regular performance checks crucial. To keep your site running smoothly, use plugins like Query Monitor to regularly check your site’s performance metrics such as page load times and memory usage. Additionally, employ WP Debugging to investigate and resolve any PHP errors or conflicts.

While Query Monitor focuses on performance monitoring, WP Debugging is primarily for error logging and troubleshooting. Using both tools provides a comprehensive approach to maintaining your site’s health.

1. DNS: Cloudflare

It all starts with DNS management and the fastest and most reliable provider is undeniably Cloudflare. Positioning itself in front of every access, it’s the first thing your users will interacting when they access your site, and it needs to be blazing fast.

We apply the following non-default settings:

Speed (Optimization)

  • Speed Brain: On
  • Rocket Loader™: On
  • Automatic Platform Optimization for WordPress (APO): On
  • 0-RTT Connection Resumption: On

Caching

  • Browser Cache TTL: Respect Existing Headers
  • Crawler Hints: On
  • Tiered Caching: Tiered Cache Topology

2. Hardware

You’ll need good specs to run WordPress, preferably a single machine – or VPS – for each installation, like we do here at Raybeam. Generic hosting companies or even “Managed WordPress Hosting” will clump your site with hundreds of others on the same server or in a containerized environment. This is usually done to cut costs and offer easy scalability, but open your site to performance and security issues.

All of our servers run on Contabo and they feature some impressive hardware that guarantees a great performance:

  • All AMD EPYC CPUs;
  • Only NMVe SSD storage;
  • 12 datacenters in 9 regions, with minimal latency;
  • 32TB traffic (10TB for Australia and Japan).

3. Server: Ubuntu + WordOps

Ubuntu 22.04 is our preferred Linux distribution for default installations. It is widely used on servers, has proven to be very reliable over the years, and boasts a strong community.

In addition, we leverage WordOps to manage our servers and WordPress sites. This tool comes packed with performance defaults, included tuned versions of MariaDB, PHP and Nginx.

A safeguard swap of at least 2GB and proportional to your available RAM is added to prevent expensive jobs, particularly from MySQL, from knocking down the server on rare occasions.

4. Caches:

Our caching system uses a layered architecture, where each cache layer applies its own specialized optimizations. This tiered approach allows the caching system to progressively enhance performance, with higher-level caches building upon the capabilities of the lower-level ones:

  • OPcache: Zend OPcache is enabled by default since PHP 5.5. Learn more what it is in this article provided by WP Rocket;
  • Object Cache: We enable Redis by default on all installations, using the free version of Redis Object Cache plugin. Wetopi provides an article about realistic expectations you should have when using Redis on WordPress;
  • Page Cache: WordOps provides a Redis page cache built with Nginx whenever Redis is enabled;
  • Browser Cache: Great browser cache defaults for Nginx comes packaged by default by WordOps, which also includes Brotli compression;
  • Edge Cache: The paid service Cloudflare APO is included in all plans as part of our Goodies package and acts as a hybrid between page and edge cache for WordPress, making static copies of your pages and sending them to all zones. Note that it doesn’t completely override Nginx’s browser cache, but can modify headers. The best article about it is this one provided by Brian Li.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *