This morning, the Wordfence Threat Intelligence team began tracking exploit attempts targeting CVE-2022-40684 on our network of over 4 million protected websites. CVE-2022-40684 is a critical authentication bypass vulnerability in the administrative interface of Fortinet’s FortiGate firewalls, FortiProxy web proxies, and FortiSwitch Manager, and is being actively exploited in the wild¹,².
At the time of publishing, we have recorded several exploit attempts and requests originating from the following IP addresses:
Most of the requests we have observed are GET requests presumably trying to determine whether a Fortinet appliance is in place:
GET /api/v2/cmdb/system/admin/admin HTTP/1.1 Accept-Encoding: gzip User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36 Connection: close X-Forwarded-Proto: https X-Forwarded-Ssl: on X-Forwarded-For: 22.214.171.124 Host: <redacted> Content-Type: application/x-www-form-urlencoded
However, we also found that a number of these IPs are also sending out PUT requests matching the recently released proof of concept, referenced at the end of this advisory, which attempts to update the public SSH key of the admin user:
PUT /api/v2/cmdb/system/admin/admin HTTP/1.1 X-Forwarded-For: 126.96.36.199 Accept-Encoding: gzip Forwarded: for=[127.0.0.1]:8000;by=[127.0.0.1]:9000; Connection: close User-Agent: Report Runner Host: <redacted> Content-Type: application/json Content-Length: 610
While some requests are using a fake public key, which may indicate a benign vulnerability scanner, all of the requests using a valid public key are using the same public key, indicating that these requests are all the work of the same actor. An attacker able to update or add a valid public SSH key to a user’s account on a system can then typically gain access to that system as that user if they have the corresponding private key. In this case the attacker is attempting to add their own public key to the admin user’s account.
The SSH key has the following fingerprint: SHA256:GBl4Pytt+W2yEZ3zlOkAZkgtqmTPBcEZlqK4hoNOqBU dev@devs-MacBook-Pro.local (RSA)
All of the PUT exploit attempts we have seen are using the “Report Runner” User-Agent as this is a requirement of the exploit, though the exploit may also be viable with the User-Agent set to “Node.js”.
New IP Addresses attacking CVE-2022-40684 will appear on the Wordfence Intelligence IP Threat Feed in the “auth_bypass” category as the feed is updated every 60 minutes.
1. Fortinet released an advisory with additional information, including affected products and workarounds for users unable to patch. 2. Horizon3.ai initially discovered that the vulnerability was being exploited in the wild and released a proof of concept earlier today.
The WordPress 6.0.3 Security Update contains patches for a large number of vulnerabilities, most of which are low in severity or require a highly privileged user account or additional vulnerable code in order to exploit.
As with every WordPress core release containing security fixes, the Wordfence Threat Intelligence team analyzed the code changes in detail to evaluate the impact of these vulnerabilities on our customers, and to ensure our customers remain protected.
The Wordfence Firewall provides protection from the majority of these vulnerabilities, and most sites should have been updated to the patched version automatically. Nonetheless, we strongly recommend updating your site as soon as possible, if it has not automatically been updated.
We have determined that these vulnerabilities are unlikely to be seen as mass exploits but several of them could offer a way for skilled attackers to exploit high-value sites using targeted attacks.
WordPress allows any user that can edit posts, such as Contributors, to add a block linking to an RSS feed. While the contents of any feed imported this way are escaped, errors in retrieving the feed would be displayed on the page containing the feed. These included the error status code and content-type header. This means that a contributor-level attacker could create a page on a site they controlled that returned an error code and a malicious script in the Content-Type response header. They could then add a post containing an RSS block linking to their malicious “feed” and submit it for review. When an administrator previewed the post, the malicious script in the Content-Type header would be executed in their browser.
Unfortunately it is not possible to write a firewall rule to protect against this vulnerability as it could potentially be exploited without sending any requests to the victim site. A motivated attacker could look for existing RSS feeds on a site and attempt to compromise one of the sites those feeds were generated from. Such an attacker could potentially take over multiple sites using a single malicious RSS feed.
The sanitize_query function used in the WP_Date_Query class failed to sanitize all relations where it was expecting “AND” or “OR” in the query. It is possible that a third-party plugin or theme might perform a date query in an unsafe way that resulted in SQL injection, though WordPress core is not vulnerable itself. This is similar to the fixes released back in version 5.8.3.
Similar to the above XSS via wp-mail.php, the Trackback functionality of WordPress did not explicitly state the intended user identity which means that any request to wp-trackback.php would assume the identity of the user whose cookies are sent with the request. This would make it possible for an unauthenticated user to trigger a trackback assuming the identity of another user, granted they could trick that other user into performing the action. In new versions of WordPress, the identity will always be a non-existent user with the ID of 0, which represents an unauthenticated user.
This fix appears to have been necessary to safely use the wp_set_current_user( 0 ); method to patch the previously mentioned XSS and CSRF in wp-mail.php and wp-trackback.php vulnerabilities. The previous functionality may have resulted in third party plugins or themes using the wp_set_current_user function in a way that could lead to privilege escalation and users being able to perform more actions than originally intended. We may update our assessment if a proof of concept becomes available.
The post by email functionality has the ability to enable logging. This can contain a post author’s email address which can be considered sensitive information and has the potential to be publicly accessible. This feature is disabled by default, so most installations likely are not vulnerable.
The REST API endpoint for terms and tags did not perform enough validation on the user requesting information about terms and tags for a given post. This made it possible for users with access to terms and tags, such as a contributor, to determine those details on all posts not belonging to them, even when in a private status. This does not reveal critical information, and as such it is not likely to be exploited.
In cases where wp-mail was used to send multiple emails or multi-part emails within a single request, the email altBody (frequently used to provide a text alternative to HTML-formatted emails) was not cleared between messages, which could result in users receiving message contents intended for other recipients. While this would require a plugin configured to send multiple messages with altBody text and would be almost impossible to exploit on purpose, it could still lead to exposure of highly sensitive information.
It was possible to generate a link with an invalid nonce and the _wp_http_referer query string parameter set to an external site. If an attacker was able to trick a logged-in user into clicking on the crafted link, they would be redirected to the external site.
The WordPress 6.0.3 Security update contains a much larger number of security patches than usual. Most of these are not easy to exploit without an existing proof of concept and require an authenticated user. Additionally, the Wordfence firewall should protect all Wordfence users, including Wordfence Free, Wordfence Premium, Wordfence Care, and Wordfence Response, against most of these vulnerabilities. We urge you to verify that your site has been updated to a patched version immediately as there are vulnerabilities in this update that the Wordfence firewall cannot practically block. These vulnerabilities should be taken seriously as a skilled and lucky attacker could potentially use several of them for site takeover.
Special thanks to Wordfence Threat Intelligence Lead Chloe Chamberland for collaborating on this article. Props to Toshitsugu Yoneyama, devrayn, Ben Bidner, Simon Scannell, Marc Montpas, Alex Concha, Than Taintor, Thomas Kräftner, and Michael Mazzolini for discovering and responsibly disclosing these vulnerabilities.
Welcome to the most complete guide on WordPress speed optimization!
This is my attempt to sum up WordPress speed + core web vitals in 1 post (it’s loooong).
I’ve constantly updated it to reflect new changes ever since I first published this 10 years ago. You have updates to things like core web vitals, plugin changelogs, and Cloudflare Enterprise happening every day. While site speed has gotten complex, the basics have stayed the same: use lightweight themes/plugins on fast servers (ideally with a performant cache plugin/CDN).
Why this tutorial is different:
First, my recommendations on tools/plugins/services are arguably better than what other people tell you to use. I’m very transparent about SiteGround’s slow TTFB and cache plugin, Kinsta’s overpriced service + lack of resources, NitroPack being blackhat, RocketCDN’s poor performance, and Elementor/Divi being slow. I’ve also written extensive reviews/tutorials on nearly every major host, cache plugin, CDN, and core web vital you can find in my nav menu.
Chrome Dev Tools – the coverage report shows your largest CSS/JS files and where they’re loaded from (plugins + third-party code are common culprits). So many parts of speed and web vitals are related to CSS/JS and it’s best to tackle it at the source. Removing things you don’t need is better than trying to optimize it.
KeyCDN Performance Test – measure TTFB in 10 global locations. This is mainly improved with better hosting and using a performant CDN with full page caching (like APO or FlyingProxy). It also shows DNS lookup times and TLS which can be improved with a fast DNS (i.e. Cloudflare) and configuring their SSL/TLS settings.
PageSpeed Insights – most items come down to reducing or optimizing CSS, JS, fonts, images, TTFB, and above the fold content. For example, preload your LCP image and exclude it from lazy load, then move large plugins/elements below the fold so they can be delayed. Focus on recommendations in PSI’s opportunities + diagnostics sections, and monitor your core web vitals report in Search Console.
CLS Debugger – see your website’s layout shifts (CLS) on mobile/desktop in a GIF.
WP Hive – Chrome extension that lets you search the WordPress plugin repository and see whether a plugin impacts memory usage and PageSpeed scores, but only measures “out of the box settings” and not when content is added to the frontend.
Wordfence Live Traffic Report – see bots hitting your site in real-time. AhrefsBot, SemrushBot, compute.amazonaws.com and other bots can be blocked if you’re using their service. Since most bot protection services don’t block these service’s bots, you’ll need to do this manually with something like Cloudflare firewall rules.
WP-Optimize – see which plugins add database overhead and remove old tables left behind by plugins/themes you deleted. Does a better than job cache plugins with scheduled cleanups because it can keep a certain number of post revisions while removing junk (cache plugins delete them all, leaving you with no backups).
cdnperf.com + dnsperf.com – you can these as baseline for choosing a DNS/CDN provider, but it doesn’t include StackPath’s CDN (removed from cdnperf and used by RocketCDN), QUIC.cloud’s CDN or CDN (used on LiteSpeed), and other services.
Waterfall Charts – testing “scores” isn’t nearly as effective as measuring things in a Waterfall chart. Google’s video on optimizing LCP is a great resource and shows you the basics. You can find one in WebPageTest, Chrome Dev Tools, and GTmetrix.
Diagnostic Plugins – the speed plugins section lists all plugins mentioned in the guide. It includes diagnostic plugins like Query Monitor (this is probably best for finding bottlenecks), WP Server Stats, WP Hosting Benchmark, and WP Crontrol.
A slow DNS causes latency which is part of TTFB (and TTFB is part of LCP).
Whoever you registered your domain through is who you’re using for a DNS. GoDaddy, NameCheap, and even Amazon Route 53 (used on Kinsta) don’t perform well on dnsperf.com. Better options include Cloudflare, QUIC.cloud, or Google (if using Google Domains). I usually recommend Cloudflare since it’s free and can be used on any setup by changing nameservers.
Combining a good host/CDN is arguably the best way to improve TTFB (using a host with improved specs on top of Cloudflare Enterprise hits 2 birds with 1 stone).
Mainstream hosts (like SiteGround, Hostinger, and WPX) don’t have a lot of CPU/RAM, use slower SATA SSDs, and are shared hosting with strict CPU limits which force you to upgrade plans. Cloud hosting is faster, but Kinsta still uses SATA SSDs with low CPU/RAM, PHP workers, and monthly visits (Redis also costs $100/month). Cloudways Vultr HF is who I previously used, but again, they start with only 1 CPU + 1GB RAM on slower Apache servers, PHP-FPM, and GZIP.
Here are Rocket.net’s:
All plans use 32 CPU cores + 128GB RAM with NVMe (faster than SATA), Redis (better than memcached), LiteSpeed’s PHP, and Brotli (smaller compression than GZIP). They have no PHP worker limits since only about 10% of traffic hits your origin due to their Cloudflare Enterprise.
Cloudways Vultr HF
.768 – 1.536
Low PHP workers
Why you need Cloudflare Enterprise
Because you get Enterprise features like 270+ PoPs, prioritized routing, full page caching, HTTP/3, WAF, and image optimization. 3 problems with most CDNs are their small network (PoPs) and no full page caching or image optimization. For example, WP Rocket’s RocketCDN uses StackPath which was removed from cdnperf.com and doesn’t include image optimization with a mediocre Tbps speed of 65+. SiteGround’s CDN only has 14 PoPs. QUIC.cloud CDN (for LiteSpeed) and BunnyCDN are good, but they still don’t beat Cloudflare Enterprise. Sure, you can pay $5/mo for Cloudflare’s APO, but you’re still missing out on all other Enterprise features.
3 popular hosts with Cloudflare Enterprise
Rocket.net’s Cloudflare Enterprise is free, setup automatically, and uses full page caching (unlike Cloudways). And unlike Kinsta’s, Rocket.net has Argo Smart Routing (specifically good for WooCommerce sites), load balancing, and image optimization. Rocket.net CEO Ben Gabler also used to be StackPath’s Chief Product Officer and went as far as building Rocket.net’s data centers in the same locations as Cloudflare’s. And unlike both hosts, Rocket.net doesn’t limit PHP workers (there’s no CPU limits) and monthly visit limits are 10-25 times more than Kinsta’s.
Cloudflare Enterprise (Kinsta)
Cloudflare Enterprise (Cloudways)
Cloudflare Enterprise (Rocket.net)
Full page caching
Argo smart routing
$5/mo (1 domain)
Problems with mainstream hosts
I’ve written some pretty bad reviews about SiteGround’s slow TTFB, CPU limits, and why SG Optimizer does a poor job with core web vitals (they also control several Facebook Groups and threaten to sue people who write bad reviews). Hostinger writes fake reviews and is only cheap because you get less resources like CPU/RAM. Kinsta and WP Engine are way too expensive for how many resources, PHP workers, and monthly visits you get. Along with major incidents like WPX’s worldwide outage and SiteGround’s DNS getting blocked by Google for 4 days (both WPX and SiteGround denied responsibility). One thing is clear: most mainstream hosts appear to be more interested in profits than performance. Please do your own research before getting advice.
Getting started on Rocket.net
Step 1: Create a Rocket.net account and you’ll be prompted to add a coupon. Sign up with coupon OMM1 to get your first month for $1 (renews at $30/mo or $25/mo when paying yearly). If you sign up with my coupon or affiliate links, I get a commission which I seriously appreciate.
Step 2: Request a free migration. They did this the same day and let me review my website before it was launched with no downtime. For the record, their support is better than Kinsta’s and you can reach out to Ben Gabler or his team (via phone/chat/email) if you have questions.
Step 3: Upgrade to PHP 8.1 and ask support to install Redis (they use Redis Object Cache). These are the only things I did since Cloudflare Enterprise and backups are both automatic.
Step 4: Retest your TTFB in SpeedVitals and click through your pages to see the difference. You can also search their TrustPilot profile for people mentioning “TTFB” where they’re rated 4.9/5.
I was previously on Cloudways Vultr HF which was great, but their Cloudflare Enterprise doesn’t use full page caching (yet) and is $5/mo with annoying challenge pages. Even if their Cloudflare Enterprise was identical, Rocket.net still outperforms them with better specs like more CPU/RAM, Brotli, and LiteSpeed’s PHP (plus better support, easier to use, and usually pricing). While Cloudways is a big improvement than most hosts, you’re already spending $18/mo for Vultr HF’s lowest 1 CPU plan with Cloudflare Enterprise. At that point, the extra $7/mo you’d be spending at Rocket.net is worth it. Rocket.net’s dashboard is also much easier.
For small sites on a budget, NameHero’s Turbo Cloud plan is similar to Hostinger between LiteSpeed, cPanel, and pricing. However, NameHero’s Turbo Cloud plan has about 1.5x more resources (3 CPU + 3GB RAM) with NVMe storage. NameHero’s support/uptimes are also better shown in TrustPilot reviews. This is one the fastest setups on a budget… you get a LiteSpeed server + LiteSpeed Cache + QUIC.cloud CDN, and email hosting. The main con is their data centers are only in the US and Netherlands. If these aren’t close to your visitors, make sure to setup QUIC.cloud’s CDN which has HTML caching (ideally the paid plan which uses all 70 PoPs).
4. Page Builders
Elementor/Divi are slower than Gutenberg/Oxygen.
Since multiple PSI items are related to CSS/JS/fonts, many people are replacing them with lightweight alternatives. The last thing you want to do is use a slow page builder then install a bunch of “extra functionality plugins” which add even more CSS/JS. Don’t fall into this trap. If you don’t want to ditch your page builder completely, there are still ways you can optimize it.
Divi/Elementor add extra CSS/JS/fonts to your site.
Adding more page builder plugins can slow it down more.
If using Elementor, try the settings under Elementor → Experiments.
Same thing with Divi (Divi → Theme Options → General → Performance).
If using Astra Starter Sites, use a template built in Gutenberg (not Elementor).
Use CSS for your header/footer/sidebar (instead of bloated page builder code).
Elementor has a theme customizer setting to host fonts locally + preload them.
If you don’t use Elementor font icons, disable them or use custom icons instead.
If you don’t use elementor-dialog.js for popups, disable it (i.e. using Perfmatters).
Many page builder plugins are module-based, so disable modules you don’t use.
Simplify your design by using less widgets/columns (here’s a YouTube video on it).
If you preload critical images in FlyingPress or Perfmatters, this excludes above the fold images from lazy load and preloads them to improve LCP. However, it doesn’t work with Elementor image widgets (go through your page builder + cache plugin documentation).
Background images aren’t lazy loaded by default because they’re loaded from a separate CSS file. Some cache plugins support a lazy-bg class you can use to lazy load backgrounds.
A performant CDN with HTML caching (and other CDN features) can be the difference maker. While cdnperf.com is a good baseline, there are other things to consider.
Start by looking at their network page (you’ll see BunnyCDN’s network has more PoPs and faster a Tbps than StackPath). Also look at the features (for example, RocketCDN only serves files from the CDN and nothing else while other CDNs do a lot more than just “serving files.” Cloudflare’s dashboard has hundreds of optimizations to improve speed, security, and CPU usage. Aside from choosing a good CDN, make sure to also take advantage of everything it offers. Or just use a service like FlyingProxy/Rocket.net that integrates Cloudflare Enterprise.
Cloudflare – it’s hard to beat Cloudflare with 270+ data centers and all the robust features. Open your Cloudflare dashboard and use the recommendations below to configure settings.
Free Cloudflare Features I Recommend Using
CDN – in your DNS settings, find your domain and change the proxy status to Proxied (orange cloud). This is needed for several Cloudflare features to work.
TLS version – set minimum TLS version to 1.2 and make sure TLS 1.3 is enabled.
Firewall rules – often used to block access to wp-login, XML-RPC, and “hacky” countries. Firewalls block attacks along with unwanted requests to the server.
Bot protection – block spammy bots from hitting your server. I would also check your Wordfence live traffic report to see bots hitting your website in real time and manually block bots like AhrefsBot + SemrushBot if you don’t use them. Bot fight mode can add a JS file to your site (invisible.js) and cause PSI errors (so test this).
Brotli – this only works if your host supports Brotli, otherwise GZIP will be used.
Early hints – while the server is waiting for a response, preload/preconnect hints are sent to the browser so resources load sooner, reducing your server think time.
Browser cache TTL – 1 year is good for static sites (my blog is mostly static so this is what I use) or use 1 month for dynamic sites. This is recommended by Google and can fix serve static assets with an efficient cache policy in PageSpeed Insights.
Crawler hints – helps search engines efficiently time crawling and save resources.
Cache reserve – improves cache hit ratio by making sure specific content is being served from Cloudflare even when the content hasn’t been requested for months.
Workers – deploy code on Cloudflare’s edge servers (try the playground). Workers are serverless with automatic scaling + load balancing. Obviously involves coding knowledge and can reduce LCP by 80%. It can also be used for external cron jobs.
HTTP/3 – not true HTTP/3 but still a nice feature (test your site using HTTP/3 test).
0-RTT connection resumption – good for repeat visitors, latency, mobile speed.
Hotlink protection – saves bandwidth by stopping people from copying your images and using them on their own website while they’re hosted on your server.
Zaraz – offload third-party scripts to Cloudflare like Google Analytics, Facebook Pixel, chatbots, and custom HTML. But test your results against delaying these.
Monitor bandwidth/analytics – the more bandwidth you offload to Cloudflare the better. This should lighten the load on your server while reducing CPU usage.
Paid Cloudflare Features
APO – caches HTML which can improve TTFB in multiple global locations.
WAF – block unwanted requests, improve security, and reduce CPU usage.
Argo + Tiered Cache – route traffic using efficient paths with Tiered Cache.
Image optimizations – I prefer these over plugins. Between all 3 (image resizing, Mirage, Polish), you don’t have to use a bloated image optimization plugin and they usually do a better job. You have features like compression/WebP and they also have mobile optimizations like serving smaller images to reduce mobile LCP.
Signed Exchanges – improves LCP when people click links in Google’s search results via prefetching which Google says can lead to a substantial improvement.
Load Balancing – creates a failover so your traffic is re-routed from unhealthy origins to healthy origins. Can reduce things like latency, TLS, and general errors.
Cloudflare Enterprise – majors benefits include prioritized routing, more PoPs, Argo + Tiered Cache, full page caching, image optimization, and other features depending where you get it from. The easiest/cheapest way is to use a host with Cloudflare Enterprise or FlyingProxy (I recommend Rocket.net’s who even built their data centers in the same locations as Cloudflare). It’s just more thought out than Cloudways/Kinsta. You could also consider using Cloudflare Pro which has some of these features. It requires more configuration but gives you more control.
BunnyCDN – Gijo suggests Cloudflare + BunnyCDN which is what I’ve used for a long time. If you’re using FlyingPress, FlyingCDN is powered by BunnyCDN with Bunny Optimizer + geo-replication. It’s also cheaper than buying these directly through BunnyCDN and easy to setup.
QUIC.cloud – use this if you’re on LiteSpeed. You’ll want to use the standard (paid) plan since the free plan only uses 6 PoPs and doesn’t have DDoS protection. It has HTML caching which is similar to Cloudflare’s full page caching and is also needed for LSC’s image/page optimizations.
RocketCDN – uses StackPath which was removed from cdnsperf.com and has less PoPs, slower Tbps, no image optimization, no HTML caching, and no other features besides serving files from a CDN. Also isn’t “unlimited” like WP Rocket advertises since they will cut you off at some point.
SiteGround CDN – not a lot of PoPs/features and you have to use their DNS to use it (which if you remember, was blocked by Google for 4 days). I personally wouldn’t trust this with my site.
6. Cache Plugins
Let’s summarize 5 popular cache plugins in 10 lines or less.
FlyingPress – optimizes for core web vitals and real-world browsing better than the last 3. When a new core web vital update comes out (like fetchpriority resource hints), Gijo is almost always first to add it. Awesome features not found in most cache plugins: preloading critical images lets you set the number of images usually shown above the fold to exclude them from lazy load while preloading them. FlyingPress can also lazy render HTML elements, self-host YouTube placeholders, and it has a lazy-bg helper class for lazy loading background images. FlyingCDN uses BunnyCDN with Bunny Optimizer + geo-replication (great choice). The remove unused CSS feature is faster than WP Rocket’s since it loads used CSS in a separate file (instead of inline) which Perfmatters agrees is faster for visitors. Really, the main thing it doesn’t have is server-level caching. I moved from WP Rocket to FlyingPress and saw a big difference in speed.
Remove unused CSS
Preload critical images
Exclude above the fold images
Lazy load background images
Fetchpriority resource hint
Lazy render HTML elements
Add missing image dimensions
YouTube iframe preview image
Self-host YouTube placeholder
Host fonts locally
CDN (beyond Cloudflare)
CDN image optimization
CDN image resizing for mobile
Documented APO compatibility
LiteSpeed Cache – also does a great job optimizing for web vitals and real users, but different than FlyingPress. Mainly because it should only be used on LiteSpeed, it’s free, and it has faster server-side caching. However, the settings can be complicated. While some settings are similar to FlyingPress like loading used CSS in a separate file and lazy loading HTML elements, it has its own unique features such as localizing third-party resources, ESI, guest mode, LQIP, and HTML caching through QUIC. Use LSC if you’re on a LiteSpeed host. Anything else, I’d use FlyingPress.
SiteGround Optimizer – great for caching, not for web vitals. Lacks way too many features and has a history of compatibility issues the developers blame on third-party plugins/themes if you check support threads. My advice is to only use it for caching, disable everything else, then use FlyingPress or WP Rocket (just make sure page caching is only enabled in 1 plugin and disabled in the other). Of course, SiteGround will glorify their cache plugin even when it’s clearly inferior.
NitroPack – don’t use this! The only reason you get better “scores” is because it moves elements off the main-thread so they can’t be detected in speed testing tools. This leads to great (but false) scores and it doesn’t actually do a good job making your website load faster compared to other plugins. Google “NitroPack blackhat” and you’ll find plenty of articles on it.
7. Other Caching
Cache plugins are just 1 layer.
Check whether your host supports object cache (Redis/memcached), OPcache, and HTTP accelerators like Varnish/FastCGI. Most do but they need to be enabled or set up manually.
You also have CDN caching which is its own layer. All these are meant for different things and you should ideally use most (if not all) them. People get scared they’re using too much caching, but as long as you’re only using 1 type of layer (not both Redis + memcached), it’s a good thing.
OPcache – enable in your host (can help reduce CPU usage).
Browser cache – enable in your cache plugin (stores files in browsers).
HTTP accelerators – enable in your host (probably Varnish or FastCGI).
Object cache – Redis generally uses memory more efficiently than memcached and is good for large/eCommerce sites. Once it’s enabled in your host, you’ll connect it your site using a plugin (i.e. LiteSpeed Cache, W3 Total Cache, SG Optimizer, WP Redis). Check your host’s documentation/support on which plugin is best. For example, Rocket.net requires you to install the WP Redis plugin while Cloudways requires you to install the Redis addon.
CDN cache – APO is not the same as a cache everything page rule or the Super Page Cache plugin. QUIC also does HTML caching, then there are services that include Cloudflare’s full page cache like Rocket.net’s Cloudflare Enterprise, FlyingProxy, and SiteGround Optimizer. The key thing is that you’re caching HTML somewhere as it can significantly improve TTFB.
Watch out for plugins that:
Increase CPU usage – common with plugins that collect “statistics” like Wordfence’s live traffic report, Query Monitor, and Broken Link Checker. But can really be from any plugin. WP Hive tells you if a plugin increases memory usage when browsing the WP plugin repo.
Add database bloat – use WP-Optimize to see which plugins (or specific plugin modules) add the most database overhead. This is explained more in this guide’s database section.
Load above the fold – slow plugins are bad enough, but loading them above the fold is even worse. When plugins load below the fold, you can delay them (i.e. comment plugins).
Security – no security plugin (Cloudflare, firewall, etc).
Sliders – Soliloquy or MetaSlider (but ideally no sliders).
Analytics – call me crazy but I only use Google Search Console.
SEO – Rank Math or SEOPress (but most SEO plugins use jQuery).
CSS – need custom styling or even a table of contents? Just use CSS.
Backups – hosting backups or a lightweight alternative like UpdraftPlus.
In Query Monitor, the “queries by component” section shows your slow plugins. You can also use my list of 75+ common slow plugins. Finally, delete all plugins you’re not using (as well as their database tables in WP-Optimize), and disable plugin features/modules you’re not using.
All In One SEO
Broken Link Checker
Elementor Premium Addons
Elementor Ultimate Addons
Site Kit by Google
Social Media Share Buttons
Probably the #1 reason for poor core web vitals.
Remove unused CSS – WP Rocket’s method of loading used CSS inline is slower for visitors but better for scores. You should ideally use FlyingPress, LiteSpeed Cache, or Perfmatters for this which loads used CSS in a separate file so it can be cached and doesn’t increase HTML size. You should only be using 1 plugin for this. If you’re not using an optimization plugin that does this, try DeBloat or PurifyCSS.
Remove Gutenberg CSS – if you don’t use Gutenberg’s block library (i.e. you’re using classic editor), you can remove Gutenberg’s CSS which is loaded by default.
Asset unloading plugins – remove CSS/JS (or entire plugins) from specific pages/posts where they don’t need to load. Common examples are only loading contact forms on the contact page, only loading social sharing plugins on posts, and disabling WooCommerce plugins where they’re not used. You can also disable specific files like jQuery and elementor-dialog if you don’t use them. I recommend Perfmatters especially if you’re using WP Rocket or SiteGround Optimizer because it has many optimizations not found in these plugins. Be sure to use test mode and dependencies in your script manager settings. For a free plugin, try Asset CleanUp.
Critical CSS – loads above the fold CSS immediately which improves LCP. Most cache plugins do this while others (like SG Optimizer) don’t. If you make changes to stylesheets or custom CSS, regenerate critical CSS so it’s current with your site.
Page builders – Elementor/Divi add extra CSS/JS which can be optimized with their built-in performance settings, coding your header/footer/sidebar in CSS, disabling Elementor fonts/dialog, lazy loading background images in CSS, etc.
Plugins – just look at the screenshot below (plugins are obviously a major factor).
Font Icons – disable these if you don’t use them or use Elementor’s custom icons.
WooCommerce – disable scripts/styles on non-eCommerce content and disable Woo plugins where they don’t need to load (many load across the entire website).
10. Third-Party Code
This is anything on your site that has to pull info from a third-party domain (like Google Fonts, Google Analytics tracking code, or an embedded YouTube video). It’s a common reason for JS-related errors in PSI. Luckily, most of it can be optimized especially if it’s shown below the fold.
Step 1: Host files locally – some third-party code can be hosted locally (see the table below). LiteSpeed Cache can localize resources, FlyingPress can host fonts/YouTube thumbnails locally, Perfmatters does fonts and analytics, and WP Rocket does nothing.
Plugins To Host It Locally
Most optimization plugins, Elementor, OMGF
Flying Analytics, Perfmatters
Simple Local Avatar
FlyingPress, WP YouTube Lyte
Step 3: Prefetch or preconnect everything else – for all third-party code that can’t be hosted locally or delayed, add a DNS prefetch resource hint. Preconnect is usually only used for CDN URLs (not needed for Cloudflare), and third-party fonts (should be hosted locally). Or YouTube if you can’t eliminate requests using video optimizations in step #13.
Google Analytics – Perfmatters + Flying Analytics can use a minimal analytics tracking code that’s just 1.5 KB. Perfmatters can also prevent a Doubleclick request by disabling display features, but both these should only be used if you don’t need certain data in GA.
Avoid overtracking – one of the most common “mistakes” I see is sites using too many tracking tools: Analytics, Tag Manager, Heatmaps, Pixel, etc. Do you really need them all?
Probably your largest files after CSS/JS.
Your GTmetrix Waterfall chart shows font load times, number of requests, and whether they’re served locally or from a third-party domain like fonts.gstatic.com or use.fontawesome.com. Be sure to keep tabs on your Waterfall chart as you make optimizations. Fonts can also cause FOIT and FOUT which cause layout shifts. A few simple tweaks can make your fonts load much faster.
Reduce font families, weights, icons – try to only use 1 font family and only load the weights you actually use. Disable Font Awesome and Eicons if you don’t use them (Elementor has a tutorial on this). Some fonts also have larger file sizes than others.
Use WOFF2 – the most lightweight/universal format which is faster than .ttf and .otf.
Host locally – if your fonts are being served from fonts.gstatic.com, host them locally.
Preload – fonts should be preloaded when they load above the fold or used in CSS files. Most cache/optimization plugins require you to manually add font files (and if there’s a crossorigin option like in Perfmatters, it should be used for fonts). Elementor hosts fonts locally and preloads them under Theme Customizer → Performance. PSI used to tell you which fonts to preload in “preload key requests” but I don’t think they do this anymore.
Add font-display: optional – if you need to “ensure text remains visible during webfont load,” add font-display: optional to your font’s CSS. This is recommended by Google for the fastest performance while preventing layout shifts. It delays loading text up to 100ms. As of writing this, most plugins only support swap found in Elementor, Perfmatters, and most cache plugins. To use optional, you need to add it manually to your font’s CSS, use WP Foft Loader, or use swap until your optimization plugin supports optional. Preloading fonts that use font-display: optional completely eliminates layout shifts (FOIT) from fonts.
System fonts – system fonts generate 0 requests and are obviously best for speed, but even for someone who obsesses over performance, I’d rather have a better looking font.
Use custom Icons for Elementor – replace Font Awesome and Eicons with custom icons.
Serve Google Fonts from Cloudflare Workers – I’ll leave this here if you want to dive in.
There are 7 PSI items related to image optimization, and that doesn’t even cover everything.
Preload critical images and exclude them from lazy load – above the fold content should load immediately which is a big factor of LCP. Instead of delaying images with lazy load, you want the browser to download them immediately by using preload. The easiest way to do this (by far) is “preload critical images” in FlyingPress or Perfmatters. Instead of manually excluding/preloading above the fold images on every single page/post (because they’re usually different), you will set the number of images usually shown above the fold. In my case, it’s 3. This will preload your top 3 images while excluding them from lazy load. Currently, FlyingPress is the only cache plugin I know that supports fetchpriority which is recommended by Google to set things like your LCP image to “high priority.” Props to Gijo.
LCP image – your most important image to optimize for lower LCP (shown in PSI).
Background images – page builders serve background images in their CSS and won’t be lazy loaded, leading to ‘defer offscreen images’ errors. Some cache plugins have a lazy-bg helper class, Perfmatters has a CSS background images setting, and WP Rocket makes you move them to inline HTML. Check the documentation in your cache/image optimization plugin on how to lazy load them. You can also use Optimal or add a helper class yourself.
Image CDNs – I use Cloudflare for image optimization but Bunny Optimizer and QUIC are good too. They usually do a better job than plugins (and it’s 1 less plugin on your website).
Resize images for mobile – make sure your image optimization plugin (or image CDN) serves smaller images to mobile which should also improve your LCP on mobile. This is the “image resizing” feature in Cloudflare, or you could use ShortPixel Adaptive Images.
Properly size images – resize large images to be smaller. My blog is 765px width so I crop/resize blog images to that size (the Zoom Chrome Extension is handy for getting the perfect dimensions when taking screenshots). I always recommend creating an “image dimensions cheat sheet” so you know the size of your blog, featured, sidebar images, etc.
WebP – faster than JPEG/PNG and most image optimization plugins or CDNs can do this.
Compression – Lighthouse test images at 85% so that’s usually a good compression level.
CSS sprites – combines multiple small/decorative images into 1 image so it only creates 1 request. My old homepage used a CSS sprite and it was very fast. You can do it for sections like “featured on” where you show a bunch of logos. You would use a CSS sprite generator.
Specify dimensions – most cache plugins can “add missing dimensions” otherwise you would need to add a width/height to the image’s HTML or CSS. This prevents layout shifts.
Downgrade quality on slow connections – services like Cloudflare Mirage + Optimole serve low quality images on slow connections until a faster connection can be accessed.
Hotlink protection – stops people from using your images when they’re hosted on your server and saves bandwidth. Common with sites using high quality images or if people copy your content. Can be enabled in your host or by using Cloudflare’s hotlink protection.
Low quality images placeholders (LQIP) – if you’re using QUIC.cloud on LiteSpeed, these can prevent layout shifts but you need to make sure you’re doing it right or it will look bad.
Unless videos are optimized, they will probably be the slowest thing on a page.
While most cache plugins lazy load videos and replace iframes with a preview image, FlyingPress and WP YouTube Lyte are some of the only plugins that optimize placeholders.
Lazy load videos – done in cache plugins, Perfmatters, or try WP YouTube Lyte.
Replace YouTube iframes with preview images – the iframe (which is the heaviest element of the video) is only loaded once your visitors actually click the play button.
Self-host YouTube placeholders – FlyingPress and WP YouTube Lyte can self-host placeholders to prevent i.ytimg.com requests shown in your “third-party code” report.
Preconnect – if you’re not able to make the optimizations above and you still have third-party domains loading from YouTube, you can preconnect domains from youtube.com, i.ytimg.com, and Roboto which is currently being used as the font in the YouTube player.
Third-party comment plugins, Gravatars, or just lots of comments can slow down WordPress.
Most LCP recommendations are scattered in this guide, so I’ll just go over them briefly.
Exclude above the fold images from lazy load – you should never lazy load, delay, or defer anything that loads above the fold because this content should load immediately, which is why you should also use preload hints to help browsers download them faster.
Prioritize above the fold images – preload above the fold images (or use fetchpriority). PSI shows your largest contentful paint image which is the most important to optimize.
Reduce CSS, JS, font sizes – a big part of reducing load time is reducing their file sizes.
Reduce TTFB – 40% of LCP can usually be improved with a better hosting + CDN setup.
Eliminate render-blocking CSS/JS – render-blocking resources add delay (see video).
Use font-display: optional – if fonts aren’t loaded properly, they can also add delay.
Lazy render HTML elements – allows browsers to focus on the above the fold content.
Preload, preconnect, prefetch – hints browsers to download specific resources faster.
Increase cache expiration – also mentioned by Google (Cloudflare browser cache TTL).
Choose the right cache plugin/settings – some have better optimizations than others.
Enable Signed Exchanges (SXGs) – this is found in Cloudflare (Speed → Optimization).
Use Cloudflare Workers – Google Engineer used Workers to improve LCP by about 80%.
Move plugin content, ads, animations below the fold – that way, they can be delayed.
Layout shifts happen when things jump around while the page is loading.
You can use Google’s layout shift debugger to see these in a GIF. PSI also has an “avoid large layout shifts” item showing you which sections on your website contribute the most to CLS. Even with these recommendations, it’s hard to know why the section is causing a layout shift.
Change font-display to swap or optional – do this if you see “ensure text remains visible during webfont load.” As shown in section #11, font-display: optional is the best method.
Problems with loading CSS asynchronously – this is a setting in cache plugins that can add layout shifts caused by FOUC (flash of unstyled content). Ideally use the “remove unused CSS” method instead. If this breaks your site and you default back to loading CSS asynchronously, make sure you exclude problematic files causing FOUC, ensure critical CSS is working, and always regenerate critical CSS after updating stylesheets/custom CSS.
Preload fonts – preloading fonts eliminates layout shifts when they use display: optional.
Specify dimensions of images, videos, iframes, ads – the first 3 are easy (make sure a width and height are specified in images). Ads and other dynamic content should have reserved space by placing it in a div code. The width/height should be the ad’s largest size.
Use CSS transform in animations – not a fan of animations but here’s documentation.
Use separate mobile cache (when it makes sense) – if your mobile site is different than desktop and you’re not using a separate mobile cache, it can cause layout shifts. However, you’ll need to check your cache plugin’s documentation on when to use (and not use) this.
These help browsers download high priority resources faster.
They prioritize above the fold content (preload + fetchpriority). Preload is also used in Cloudflare’s Early Hints and for downloading internal pages in the background so they load faster when visitors click them (link preloading + Flying Pages). Prefetch + preconnect help establish early connections to third-party domains if resources aren’t already being delayed.
Preload – commonly used for above the fold images (this can also be a WebP image) but can also be used for CSS/JS (i.e. the block library), videos, audio, Cloudflare workers, and other files.
Fetchpriority – similar to preload only assigns a priority (low, high, auto). For example, if you have a large LCP image, you would assign that image’s priority to “high.” But if you have an image carousel that’s loading above the fold, you could assign the images with a low priority. FlyingPress is the only plugin I know currently supporting fetchpriority shown in the changelog.
<img src="lcp-image.webp" fetchpriority="high">
Link preloading – there’s 2 main types: preloading links in the viewport so internal links in the immediate content load faster when clicked (supported by Flying Pages and FlyingPress). And “link preloading” where users hover over any internal link (or touch it on mobile), and the page will download in the background so by the time they actually click it, it appears to load instantly (found in cache plugins like WP Rocket). While neither improves scores, both improve perceived load time. Just be careful… preloading too many pages in the background will increase CPU usage especially if you have something like a WooCommerce store with internal links in images. If visitors are hovering over product images, this will cause lots of pages to download. Not good!
DNS Prefetch – this helps browsers anticipate third-party domains by performing a DNS lookup, but usually not needed since third-party domains should be hosted locally or delayed.
Preconnect – establishes early connections to important third-party domains. Common with CDN URLs and third-party fonts like fonts.gstatic.com, use.fontawesome.com, and use.typekit. Most cache plugins add preconnect automatically when you add a CDN URL or when enabling “Google Font Optimization” (or a similar setting), but you’ll want to check their documentation.
There’s usually 3 problems with using your cache plugin to clean your database:
It can’t take database backups.
It can’t remove database tables left behind by old plugins.
It deletes all post revisions, but you may want to keep a few.
That’s why I recommend WP Optimize for database cleanups. Go through your database tables and look for tables that are not installed or inactive. You can delete these if you don’t plan on using the plugin (or theme) again since they will usually store info in the database for future use.
Certain plugin modules/features can also add lots of overhead especially if they collect data. Rank Math’s Google Analytics module adds lots of overhead, so consider disabling this Rank Math module and getting your analytics data directly from the Google Analytics website instead.
For ongoing database cleanup, WP-Optimize removes everything most cache plugins do, but it lets you keep a certain amount of post revisions so you have backups (I recommend 5-10). You can also connect UpdraftPlus which takes a database backup before scheduled optimizations.
19. Background Tasks
Background tasks can bog down your server and increase CPU usage.
These are common with cache plugins (preloading + automatic cache clearing), plugins that collect stats or create autoloads, and even WordPress core (Heartbeat, autosaves, pingbacks). Many of these can be disabled, limited, or scheduled during non-peak hours using a cron job.
Control Preloading – the preloading in cache plugins is infamous for increasing CPU usage (WP Rocket’s preloading, LSC crawler, SG Optimizer’s preheat cache, etc). The first step is changing settings to only preload important sitemap URLs (i.e. page-sitemap.com + post-sitemap.com) instead of the full sitemap. Next, you can increase the preload interval.
Automatic cache clearing – there are specific actions that trigger your entire cache to be cleared (and when the cache lifespan expires). Instead of constantly clearing cache with these actions, disable automatic cache clearing and use a cron job to clear it at a specific time (once at night). It’s best to use a cron job for both cache clearing + cache preloading.
Disable WP-Cron – using an external cron to schedule tasks like the 2 items above helps reduce CPU usage. The first step is to add the code below your wp-config.php file. Next, setup a real cron job in your host, Cloudflare, or using a third-party service like EasyCron. Some hosts have specific instructions for adding a cron job, so check their documentation.
Remove unused CSS – decrease WP Rocket’s batch size and increase the cron interval.
Link preloading – some cache plugins can “preload links” which sounds like a good idea because when users hover over a link, that page downloads in the background to make it load faster by the time users actually click it. But if your website has lots of links (such as a WooCommerce store with links in the product images), you’ll want to leave this setting off.
Plugins – think of Query Monitor, Wordfence’s live traffic report, and backup/statistic plugins (they all run background tasks). You might be able schedule these, disable specific features in plugins, or delete the plugin completely. Plugins/themes can also leave behind autoloaded data when you delete them which can be cleaned up in the wp_options table.
Autosaves – when you’re editing a post, WordPress autosaves a draft every minute. You can use a simple line of code (or Perfmatters) to increase this to something like 5 minutes.
define('AUTOSAVE_INTERVAL', 300); // seconds
Heartbeat – called every 15s and can usually be disabled in the frontend/backend, then limited in the post editor since you probably want to keep features there (like autosaves).
Pingbacks – disable pingbacks since you don’t want a notification every time you add an internal link. You may want to leave trackbacks on to help notify blogs you linked to them.
Post revisions – stored every time you hit save, publish, or update and accumulate over time. You can limit revisions in some optimization plugins, manually with code, or use WP-Optimize to run scheduled database cleanups while keeping a certain number of revisions.
define( 'WP_POST_REVISIONS', 10 );
Plugin data sharing – disable in plugins to save a little resources, sorry plugin developers!
Bots – blocking spam bots and using Cloudflare’s crawler hints saves resources from bots.
Remove unused CSS/JS – Perfmatters can disable unused CSS/JS by device type.
Don’t use AMP – lots of challenges and most WordPress users agree not to use it.
Fix mobile layout shifts – Google’s layout shift debugger tests mobile layout shifts.
Use mobile caching – enable this in your cache plugin or use one that supports this.
Know when to use separate mobile cache – check your cache plugin documentation.
Downgrade image quality on slow connections – try Cloudflare Mirage or Optimole.
Check your responsiveness – even if you use a responsive theme, check this manually.
Add a “load more comments” button on mobile – helps if you have lots of comments.
WooCommerce sites often have more plugins, scripts, styles, and are more resource-hungry than static sites. You will need to optimize your website even more if you want good results.
Hosting – wphostingbenchmarks.com ran tests for multiple WooCommerce hosts, although I think there are much better options than the ones tested (I would personally lean towards something like Rocket.net, GridPane, RunCloud). Obviously very important.
Remove WooCommerce admin bloat – Disable WooCommerce Bloat is good for this.
Cloudflare Argo + Tiered Cache – specifically good for speeding up dynamic requests.
Redis – also specifically good for WooCommerce (especially Redis Object Cache Pro).
Go easy on WooCommerce Extensions – just like other plugins, be minimal with these.
Unload WooCommerce plugins – Woo plugins are infamously bad with loading across your entire site. Use your asset unloading plugin to disable them where they’re not used.
Use Cloudflare firewall rules (i.e. only access wp-login from your IP).
Disable file editing to prevent hackers from editing theme/plugin files.
Follow security-related social media accounts like Cloudflare/Wordfence.
Check for known vulnerabilities before updating things (especially plugins).
23. PHP Version
Only 7% of websites use PHP 8.
Come on y’all, you already know higher PHP versions are faster and more secure. Google “update PHP version [your host]” and you’ll find instructions. If updating breaks your site, just revert back to your older version (or remove incompatible plugins that aren’t maintained well).
24. Make Sure Optimizations Are Working
You set things up, but are they working? Make sure they are.
Caching – cache plugins should have documentation to check if the caching is working.
Redis/memcached – LiteSpeed Cache’s connection test and most Redis plugins tell you.
CDN Analytics – how many requests are you blocking from bots, hotlink protection, and WAF? What is your cache hit ratio (hopefully around 90%)? CDN analytics are very useful.
Dr. Flare – Chrome Extension to view tons of Cloudflare stats like your cache hit ratio, uncached requests, non-Cloudflare requests, how much % was reduced by Polish/Minify.
CDN rewrites – are your files actually being served from your CDN? Check your CDN Analytics, Dr. Flare, or view your source code to make sure files are being served from the CDN when using a CDN URL, like this: cdn.mywebsite.com/wp-content/uploads/logo.png. If you’re using BunnyCDN, you may be able to serve more files from BunnyCDN by adding your CDN URL to your cache plugin on top of using BunnyCDN’s plugin. It worked for me.
APO – verify Cloudflare’s APO is working by testing your website in uptrends.com then making sure headers exactly match with what Cloudflare shows in the documentation.
Asynchronous CSS – if you’re using this, cache plugins should also have documentation.
External cron jobs – check the logs in your hosting account to make sure these are firing.
Waterfall charts – after each optimization, you should ideally check its impact using a Waterfall chart (better than running another PageSpeed Insights test and testing scores).
Clear cache – you may need to clear cache or regenerate critical CSS to see your changes.
Plugins like Perfmatters have great documentation.
Gijo Varghese and WP Johnny also put on quality articles.
My other articles (if you liked this one, I have plenty more).
BDKamol – Pronaya mainly works with Gutenberg, WooCommerce, and Genesis. He’s been helping me for over 10 years even when I launched my first website and had no visitors. He points me in the right direction and was a key part in launching my new blog, helping me with things like custom coding, CSS styling, theme/plugin recommendations, etc. Pronaya lives in Bangladesh and his communication (and my trust in him) are 100%.
WP Johnny – he’s a busy guy but you can try hiring him and his team. I was lucky enough to have him help me remove my page builder (which I regret using in the first place and should have known better). While the work is great, it can take awhile to get things done.
WP Fix It – hired them once to improve issues related to core web vitals. While I was very happy with the work, they closed my tickets without notice saying the project was done, even when I told them I would pay more since truly fixing the issues required more work.
27. My Setup
This will cost about $500/year.
It assumes you already have a lightweight theme (i.e. GeneratePress/Kadence) and pay yearly for Rocket.net since you get 2 months free. It also assumes you’re using Rocket.net’s lower $25/mo plan (I pay $50/mo for the Business plan). For my site, this is the best setup I’ve found.
My blog costs around $800/year which is a lot cheaper than I was paying (mainly because hosting gets expensive as you scale). Scaling on Rocket.net is reasonable since monthly visits and RAM are both 10x Kinsta’s and there’s no PHP worker limits since only about 10% of traffic hits the origin (due to Ben Gabler’s Cloudflare Enterprise setup who I suggest reaching out to).
LiteSpeed is also solid and can be cheaper since LiteSpeed Cache is free and email hosting is often included. Check out NameHero, ChemiCloud, and Scala (they seem to have good specs and TrustPilot reviews). RunCloud, GridPane, and JohnnyVPS are probably best for larger sites.
Cloudways is who I was using. I still think they’re better than most hosts but it gets expensive with all the add-ons, they use Apache servers, and Cloudflare Enterprise + Breeze need work.
This is flagged when you have a short cache expiration for images, fonts, media, scripts, and stylesheets. Google fails the audit if the cache expiration is under 180 days (259200 minutes). This simply means you need to adjust your cache expiration for those files to 180 days or over.
In most cases, you will login to your hosting account and adjust the static cache expiry (or similar) to 180 days. However, this can be quite a long time that visitors won’t see an updated version of those files. If you change these files frequently, a longer cache lifespan may not be best and you may want to make it shorter (even if it’s flagged). Google warns you about this.
I’ll cover a few other ways to serve static assets with an efficient cache policy in WordPress specifically for Cloudflare, other CDNs, Google Analytics, WP Rocket, and third-party scripts.
Most other CDNs let you change the browser cache expiration.
For example, in BunnyCDN, go to Pullzone → Your Website → Cache → Browser Cache Expiration. In this case, there is no option for 180 days. You can either set it for 1 year or “match server cache expiration.” You’ll need to make sure your server uses the correct cache expiration.
This code is automatically added to your .htaccess file when you activate WP Rocket. But you will notice the browser cache expiration for images, fonts, and other files is 4 months (about 2 months short of Google’s 180 day requirement). It means you’ll need to change it to 180 days.
# Expires headers (for better cache control)
ExpiresDefault "access plus 1 month"
# cache.appcache needs re-requests in FF 3.6 (~Introducing HTML5)
ExpiresByType text/cache-manifest "access plus 0 seconds"
# Your document html
ExpiresByType text/html "access plus 0 seconds"
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
ExpiresByType application/rss+xml "access plus 1 hour"
ExpiresByType application/atom+xml "access plus 1 hour"
# Favicon (cannot be renamed)
ExpiresByType image/x-icon "access plus 1 week"
# Media: images, video, audio
ExpiresByType image/gif "access plus 4 months"
ExpiresByType image/png "access plus 4 months"
ExpiresByType image/jpeg "access plus 4 months"
ExpiresByType image/webp "access plus 4 months"
ExpiresByType video/ogg "access plus 4 months"
ExpiresByType audio/ogg "access plus 4 months"
ExpiresByType video/mp4 "access plus 4 months"
ExpiresByType video/webm "access plus 4 months"
# HTC files (css3pie)
ExpiresByType text/x-component "access plus 1 month"
ExpiresByType font/ttf "access plus 4 months"
ExpiresByType font/otf "access plus 4 months"
ExpiresByType font/woff "access plus 4 months"
ExpiresByType font/woff2 "access plus 4 months"
ExpiresByType image/svg+xml "access plus 1 month"
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
ExpiresByType text/css "access plus 1 year"
Edit your .htaccess (you can use Htaccess File Editor if you don’t know how). Change the expiration from 4 months to 180 days. You may only want to do this for file types being flagged.
WP Rocket also suggests to check with your host to make sure they don’t block WP Rocket’s rules and that Mod_expires is enabled.
5. LiteSpeed Cache
To serve statics assets with an efficient cache policy using LiteSpeed Cache, go to LiteSpeed Cache Settings > Browser. Enable browser cache and the browser cache TTL should be left as default (31557600 seconds). If you still see errors, check if your host or CDN is overriding this.
6. W3 Total Cache
If you need to serve static assets with an efficient cache policy in W3 Total Cache, go your Browser Cache settings and change the Expires header lifetime to at least 15552000s (180 days). Make sure the cache expiration in your hosting and CDN settings aren’t overriding this.
7. Google Analytics
Google Analytics can also cause errors when serving static assets with an efficient cache policy.
Go to Settings → Optimize Google Analytics → Advanced Settings → Cookie Expiry Period.
Set it to 180 days.
I recommend checking out other features in the CAOS Analytics plugin. Using a minimal analytics tracking code and serving it from your CDN can be beneficial for WordPress speed.
8. Google Fonts
Just like you hosted Google Analytics locally to control the cache lifespan, you can do the same thing with Google Fonts.
But they need to be hosted locally on your server (not pulling from fonts.gtstatic.com). You can do this by downloading your fonts directly from the Google Fonts website (remember to be minimal with font families and weights), converting them to WOFF2 format using a tool like Transfonter, then adding them to your CSS. Alternatively, you can also try the the OMGF plugin.
Once fonts are hosting locally, follow step #4 to set the cache expiration to 180 days for fonts.
10. Purge Files And Retest
Once you’re done changing your cache expiration, remember to purge files and retest your WordPress site. Ideally you’ll have 100% for serve static assets with an efficient cache policy.
Frequently Asked Questions
How do I serve static assets with an efficient cache policy in WordPress?
Change your browser cache expiration to 180 days (or 259200 minutes). This is typically done in your hosting account, cache plugin, or CDN.
How do I serve static assets with an efficient cache policy using WP Rocket?
Edit your. htaccess file and locate the browser cache expiration code added by WP Rocket. Change the expiration from 4 months to 6 months for files flagged in Lighthouse, which are usually images or fonts.
How do I serve static assets with an efficient cache policy using Cloudflare?
Login to Cloudflare and go to Caching > Browser Cache TTL and change it to 6 months.
How do I serve static assets with an efficient cache policy using W3 Total Cache?
In your W3 Total Cache settings, go to Browser Cache and change Expires header lifetime to 180 days (15552000 seconds). Check your server and CDN to make sure they’re not overriding this setting.
Wordfence 7.7.0 has just been released and as usual, it includes several awesome enhancements and updates for our security conscious WordPress publishers and e-commerce websites. This post goes into a little more detail on each change we’ve included. We don’t usually post additional detail like this, and we thought we’d give it a try, and make it a routine if the community approves.
This is based on the official Wordfence 7.7.0 changelog, which is included below. The format I’ve used here is the changelog entry as a heading and some detail on what the entry means and some background where applicable.
Improvement: Added configurable scan resume functionality to prevent scan failures on sites with intermittent connectivity issues
We’ve added “scan resume” functionality which is configurable and will prevent security scan failures on sites that might have intermittent connectivity issues. As you know Wordfence runs on over 4 million websites on over 12,000 unique networks, and to say that we run in a range of environments and configurations is an understatement. Our quality assurance team has an oversized influence on the product, and this is one more way they have made Wordfence even more robust in version 7.7.0.
Improvement: Added new scan result for vulnerabilities found in plugins that do not have patched versions available via WordPress.org
This adds a scan result for plugins that have a vulnerability and are still present in the official WordPress plugin repository, and where there is no fix available. The usual course of action is that the plugin team will disable a plugin in the repository that has a known vulnerability, where the vulnerability has not been fixed yet. In some cases, this doesn’t happen, and this scan result is designed to deal with this unusual case. This change will also allow plugins that are not provided through wordpress.org to be flagged as vulnerable if there is no update available.
Improvement: Implemented stand-alone MMDB reader for IP address lookups to prevent plugin conflicts and support additional PHP versions
We use the Maxmind database internally for location lookups. Our code was using the Maxmind PHP library to perform these lookups. Maxmind stopped supporting older PHP versions a while ago, but many of our customers are still on those old versions. We have also found that other WordPress plugins may use a different version of the Maxmind library, which can lead to conflicts. So we’ve rolled our own stand-alone MMDB reader to resolve both of these issues. We now support older PHP versions than the official Maxmind library, and you won’t see any conflicts if another plugin is using the Maxmind library.
Improvement: Added option to disable looking up IP address locations via the Wordfence API
By default Wordfence contacts our servers to perform an IP address location lookup. This is just the way the plugin was originally engineered (by me actually) to try to move as much processing to our own servers and reduce resource usage on our customer websites. Some of our customers prefer that lookup to happen locally, so we’ve provided that option. The default is still to do the lookup on our servers, but you have the option to enable local lookups. The one downside of enabling this feature is that you’ll only get country-level lookups.
Improvement: Prevented successful logins from resetting brute force counters
Another design decision I made early on is that a successful login on a WordPress website would reset our brute-force login counters to zero. This made sense because if a real user makes multiple login failures and then succeeds, clearly they’re the real user and we should reset our counters so that their next failure doesn’t lock them out. Well, an unintended side effect of this is that a threat actor can register an account on WordPress websites with open registration, and sign in, and that would reset brute force counters to zero, so they can keep trying to guess that admin account’s password. We’ve fixed this by removing the reset that occurs on successful login.
Improvement: Clarified IPv6 diagnostic
We found that a message on our diagnostics page caused users to think they need to fix something related to IPv6. So we clarified the message to prevent our customers from going on wild goose chases trying to fix something that doesn’t need fixing.
Improvement: Included maximum number of days in live traffic option text
This is also a clarification. The maximum amount of data in live traffic that we store is 30 days. This wasn’t clear and some users would enter a larger number of days, expecting to see more than 30 days of data. We’ve fixed this user interface issue to make it clear.
Fix: Made timezones consistent on firewall page
When the page showing firewall activity loaded more results, they’d be in UTC time instead of your correct timezone. Oops! We fixed that little issue.
Fix: Added “Use only IPv4 to start scans” option to search
We have the ability to search your Wordfence options page which is super useful. This option was not included in the search, so we fixed that.
Fix: Prevented deprecation notices on PHP 8.1 when emailing the activity log
PHP 8.1 provides notices that a function has been deprecated if a developer (like us) is using an older function call. We were in this case, and PHP 8.1 was rightfully complaining about it. So we switched to a more modern version of the same code.
Fix: Prevented warning on PHP 8 related to process owner diagnostic
On our diagnostics page, if a hosting provider has restricted an account from seeing its own username, our customers would see a warning that you can’t access an array offset on a boolean. We fixed that.
Fix: Prevented PHP Code Sniffer false positive related to T_BAD_CHARACTER
We use PHP code sniffer to look for things that are incompatible between versions. We were getting a false positive when using this internal tool, so we fixed that. This change is really for the benefit of our engineering team.
Fix: Removed unsupported beta feed option
A long time ago when there was fire in the sky and the seas were boiling, we launched the first version of the Wordfence firewall. Because we wanted to test out new rules, and some of our users were brave enough to try the new stuff, we included this option. We would release beta firewall rules and malware signatures, and our brave testing community would try them out first by enabling this option. We do all our testing internally now and the firewall code and rule syntax has become extremely robust, so we don’t do these kinds of releases anymore. So we removed this configuration option.
Below I’ve included the short version of the changelog that you’ll see on WordPress.org. You’re most welcome to post your comments and questions below. Keep in mind that support questions are best posted via our official support channels, but if you’d like to chat about this post, comment below and a member of the team or I will reply if needed.
Mark Maunder – Wordfence Founder & CEO
Wordfence 7.7.0 – OCTOBER 3, 2022
Improvement: Added configurable scan resume functionality to prevent scan failures on sites with intermittent connectivity issues
Improvement: Added new scan result for vulnerabilities found in plugins that do not have patched versions available via WordPress.org
Improvement: Implemented stand-alone MMDB reader for IP address lookups to prevent plugin conflicts and support additional PHP versions
Improvement: Added option to disable looking up IP address locations via the Wordfence API
Improvement: Prevented successful logins from resetting brute force counters
Improvement: Clarified IPv6 diagnostic
Improvement: Included maximum number of days in live traffic option text
Fix: Made timezones consistent on firewall page
Fix: Added “Use only IPv4 to start scans” option to search
Fix: Prevented deprecation notices on PHP 8.1 when emailing the activity log
Fix: Prevented warning on PHP 8 related to process owner diagnostic
Fix: Prevented PHP Code Sniffer false positive related to T_BAD_CHARACTER
Considered one of the most beginner-friendly programming languages, PHP continues to introduce tremendous changes with each of its updates. Embracing the change, this blog is focused on the steps to upgrade to PHP 8.0 on a WordPress website.
Previously, PHP 7’s speed optimization update helped a lot with gaining higher rankings on the SERPs. Carrying the legacy forward, PHP surprised its enthusiasts with a release of PHP 8.0 back in November 2020, which brought a list of new features that revolutionized the way programmers worked.
PHP 8 lets you write concise code and build more exemplary applications with exciting changes and improvements to the earlier RFCs. Considering the new improvements, it would be a crime not to upgrade your current PHP version to PHP 8.0 on your WordPress site.
Before we jump towards the steps to upgrade your PHP version to PHP 8 on WordPress, we will give a brief PHP 8.0 overview to help you get acquainted with the update.
PHP 8.0 – An Overview
PHP (an acronym for Hypertext Preprocessor) is a popular open-source scripting language used by coders worldwide for web and application development. This high-level programming language is easy to learn, hence preferred by starters and novice coders. Still, it is also complex enough to cater to the needs of a professional programmer.
PHP 8.0 is the latest update of PHP and has come up with new features, functions, and methods to facilitate the developers and provide the best user experience.
Previously, PHP had released 7.4 in November 2019, ending the support of PHP 7.1. The later version, 7.2, was also discontinued with the release of 8.0. Currently, PHP supports only 7.3, 7.4, and 8.0 versions.
Managed WordPress Hosting Starting From $10/Month
Experience Faster WordPress Themes’ Performance & Constant Availability on Cloudways.
With every update come compatibility issues. If you want to have a hassle-free PHP 8.0 experience, we recommend opting for the latest WordPress version or going with at least 5.6 or any later versions.
Are you running your website on an older WordPress version but are skeptical about upgrading in fear of getting errors? Don’t worry; you can test your website via a staging environment and proceed with upgrading your live website safely to a newer WordPress version.
If you get any errors in the staging environment, then we’d recommend getting the help of a professional WordPress developer to diagnose and debug the errors before you move ahead with the update.
PHP 8 – Themes & Plugins Compatibility
Discomforts accompany every change; similar is the case with PHP 8. While PHP 8 offers extensive features to support its users and provide them with an ideal user experience, it brings the themes and plugins incompatibility issues.
PHP isn’t the player to be blamed here, as the themes and plugins should be updated to work with the latest software versions. If your favorite and irreplaceable plugin or theme is making problems with PHP 8, then try out the following solutions.
Rollback to the previous PHP version. (A boring option)
Contact the theme or plugin’s support team and inform them about the compatibility issues to boost the optimal user experience with the latest versions of both.
PHP 8 on WordPress: Installation Prerequisites
Before upgrading to PHP 8.0, it’s wise to check the current PHP version that your WordPress site is running.
Using an older version? You can upgrade the PHP version to enjoy the new features and improvements. But not so fast! Remember, safety always comes first. When we talk about security, we consider the “what ifs.”
What if your site is not compatible with the latest version, and you end up losing or corrupting your data in the process. Nope, you don’t want that.
If the clone website works smoothly after upgrading to PHP 8.0, you can move ahead with updating your actual site. This portion will list out the steps to create a clone website to test it under PHP 8.
Clone a Website via Your Web Hosting Provider
Fortunately, managed WordPress hosting solutions like Cloudways allow the users to create their site’s duplicate without dealing with any complexities. Follow the steps below to create your website’s clone via Cloudways.
Log in to Cloudways with your credentials.
Select your server, and click the application that you want to clone.
Navigate to the bottom, and you will see an orange circle, click it.
Click Clone App/Create Staging from the pop-up.
Select your preferred server, then click Continue.
You will be asked to wait for a few minutes, during which Cloudways will copy your entire website. Now, you are good to experiment on the clone.
Note:Clone App and Create as Staging are different functionalities. Clicking Clone App will only clone your website. Whereas, Create as Staging will sync the live and staged applications to allow you to perform Push/Pull actions on both the replica and live versions.
How to Update PHP in WordPress to PHP 8.0 on Cloudways
Cloudways announced its availability of PHP 8 earlier this year, maintaining its reputation of being the early bird to accept the latest updates. Want to update your PHP version on Cloudways? Follow the easy steps below to upgrade your current PHP version to PHP 8.0.
Note:Cloudways recommends keeping a backup of your server before upgrading to a newer PHP version. Keeping a backup will help you restore your application if you feel the need to revert to your previous PHP version anytime in the future.
Log in with Cloudways
Signup on Cloudways. Already have a Cloudways account? Log in with your credentials.
Click on Servers. Select, and click the server of your choice.
Select Settings & Packages
Click on Settings & Packages on the left side.
Click on the Packages tab.
Upgrade your PHP version
Click the edit sign next to your current PHP version.
Select PHP 8.0 from the drop-down, and click Save.
The setup will prompt you with a warning to ensure if your application is compatible with the selected PHP version. If yes, then click OK.
The setup will take a few minutes to finish, and it will notify you once the update is done. After getting the notification, you can enjoy working with PHP 8.
PHP Supported Versions on WordPress
WordPress supports the following seven PHP versions ranging from PHP 5.6 to the latest version 8.0.
Note:Keep in mind that you won’t receive any PHP security updates if you are not using the latest PHP version. We recommend using the 8.0 PHP version.
What Is Holding Back Users From Updating to PHP 8.0?
The major reason that’s holding back users from upgrading to PHP 8 is the incompatibility of their favorite themes and plugins with PHP 8.
That said, every savvy user would like to enjoy the latest PHP features and RFC improvements. Anyone who wants to stay back and keep working with the legacy software would abstain from upgrading their PHP version.
Using the latest PHP versions allows for better and easier development of new features and also facilitates maintenance. Even if some of the themes and plugins are not working on PHP 8.0, they will eventually be updated.
Why Should You Upgrade to PHP 8?
Imagine using an outdated image editing tool for making logos or editing photos. While the world has moved to the latest version and is saving time and getting better quality and performance with the latest edition, you are still doing it the old way. Not really a smart decision, right?
Similarly, why would anyone abstain from upgrading to a newer PHP version when the new upgrade is specifically introduced to bring ease to the user’s end. You should definitely upgrade to PHP 8 if you want to benefit from the latest features, get better error handling, improved RFCs, and optimizations.
PHP 8 will remain in support till November 2022, and its security support will extend till November 2023. This longevity makes this newest version a lot more trustworthy and secure than the previous versions.
Most of the popular WordPress plugins and themes have accepted PHP 8 and are now compatible with it.
We ran a loader test to check PHP 8’s performance on the Cloudways server, and deduced the following results:
The average response time for the same WordPress website is 164 ms, and total success response counts are 3836.
Sadly, only 1.3% of the WordPress sites are using PHP 8.0. As per our experience, WordPress delivers the best performance with PHP 8.0 and gives better speeds than the previous PHP versions. It’s a good practice to use the latest versions, so the number of people migrating from 7.4 to 8.0 is gradually increasing with time.
PHP has worked on the issues reported by the users in the previous versions, and the latest version is free from many recurring problems and has introduced new features.
To enjoy the services at their full potential, you will have to upgrade to the newest WordPress PHP version, as the older versions may eventually fade out or will be declined by most themes and plugins.
Disadvantages of Using Older PHP Versions on WordPress
All PHP versions before 7.3 have reached their end of life, and it is advised to upgrade to the latest version if you are using any of the older versions, as it will make you vulnerable to unpatched security errors. Even 7.4 will reach the end of life on 28 Nov 2022.
Why would you risk your website to security vulnerabilities when you can easily upgrade to the latest version and enjoy the new improvements and features?
Also, ensure that you opt for a secure WordPress hosting provider to safeguard your sites from malicious traffic, DDoS attacks, and malware.
Using older PHP versions won’t only provide security issues but also will affect your website’s performance.
Which sane person compromises performance in this competitive era, where everyone is following the best practices to boost their site’s performance and gain their user’s attention?
Improve your website’s performance and security by halting the usage of older PHP versions, and upgrade your WordPress website’s PHP version to 8.0 to maximize safety and performance.
This blog covers PHP 8’s compatibility with WordPress and the steps to upgrade your PHP version to 8.0. The information shared in this guide will help you make the right decision to upgrade to PHP 8.0 on your WordPress site and enjoy the benefits of the newest update.
Ranging from the supported versions, disadvantages of using the old PHP version, and the reasons to upgrade to 8.0; we have tried to cover it all. Still, if any questions are popping up in your head, please feel free to comment with your queries; and we will answer all of them ASAP.
Yes, WordPress can use PHP 8, and it is recommended to use PHP 8.0 with WordPress 5.6 or higher version for compatibility and better performance. If you are using an older WordPress version, you can test your site with WordPress 5.6 in a staging environment. If you don’t experience any issues, then upgrade your live WordPress site to enjoy using PHP 8.0 on WordPress.
Is WordPress compatible with PHP 8?
Yes, WordPress is compatible with PHP 8.0. However, only WordPress 5.6 or higher versions are compatible with PHP 8. If you are using an older WordPress version, you can upgrade it to at least 5.6 to enjoy using PHP 8.
Should I upgrade to PHP 8?
Yes, if you want to benefit from the latest features, better error handling, improved RFCs, and optimizations, you should upgrade your PHP version to PHP 8.
What version of PHP should I use for WordPress?
We recommend using PHP 8.0 with WordPress if you are using at least WordPress 5.6. The oldest PHP version that we recommend using with WordPress is PHP 7.3.
If your website’s PHP version Because PHP is not the same as the PHP version in your backup, it may cause issues with the proper operation of your website and with some applications. This is more common when migrating from PHP 5 to PHP 7.
We recommend that users regularly backup their WordPress sites or network of sites. You can also use the All-in-One WP Migration plugin extensions to set up automatic backups. Make sure your plugin version is always up to date. In most cases, the PHP update will have no effect on WordPress or popular plugins or themes. However, it is possible that some plugins, themes, or other functionalities will cease to function.
Set the WP_DEBUG constant to true in your wp-config.php file to see all errors, warnings, and notes generated by the website during execution. This will assist you in locating any problems.
If your install is stuck at “restoring X% files,” “restoring database,” or “activating mu-plugins”
1. Leave the plugin running for another 15 minutes while it is on “Restoring database.” 2. After 15 minutes, open another tab and attempt to login to wp-admin using the exported site’s WP Admin username and password. 3. Save the permalinks structure twice by going to settings -> permalinks. Your website should now be successfully migrated.
If it isn’t and you receive a 500 error, please edit your wp-config.php file and set WP_DEBUG to true, then refresh the page to see an error. This may assist you in determining the problem, or you can share the error with the Servmask support team for assistance.
Could it be my server settings?
Memory limit needs to be at 256M, max_execution_time to 500, and mysql.connect_timeout to 400. You can find these settings by uploading this file. (https://www.dropbox.com/s/ize8t2k4nww5iq7/phpinfo.php?dl=0) in wp-content of your imported site and then open http://YOURDOMAINNAME.COM/wp-content/phpinfo.php. (tip – use Ctr F search the data that you get)
A simple guide to connecting web apps with webhooks
By Matthew Guay · September 20, 2022
You might have seen webhooks mentioned in your apps’ settings and wondered if they’re something you should use. The answer, in a nutshell, is probably yes.
Webhooks are one way that apps can send automated messages or information to other apps. It’s how PayPal tells your accounting app when your clients pay you, how Twilio routes phone calls to your number, and how WooCommerce can notify you about new orders in Slack.
They’re a simple way your online accounts can “speak” to each other and get notified automatically when something new happens. In many cases, you’ll need to know how to use webhooks if you want to automatically push data from one app to another.
Let’s break it down, learn how to speak webhook, and get your favorite apps to talk to each other.
There are two ways your apps can communicate with each other to share information: polling and webhooks. As one of our customer champion’s friends has explained it: polling is like knocking on your friend’s door and asking if they have any sugar (aka information), but you have to go and ask for it every time you want it. Webhooks are like someone tossing a bag of sugar at your house whenever they buy some. You don’t have to ask—they just automatically punt it over every time it’s available.
Webhooks are automated messages sent from apps when something happens. They have a message—or payload—and are sent to a unique URL—essentially the app’s phone number or address. Webhooks are almost always faster than polling, and require less work on your end.
They’re much like SMS notifications. Say your bank sends you an SMS when you make a new purchase. You already told the bank your phone number, so they knew where to send the message. They type out “You just spent $10 at NewStore” and send it to your phone number +1-234-567-8900. Something happened at your bank, and you got a message about it. All is well.
Webhooks work the same way.
Take another look at our example message about a new order. Bob opened your store’s website, added $10 of paper to his shopping cart, and checked out. Boom, something happened, and the app needs to tell you. Time for the webhook.
Wait: who’s the app gonna call? Just like you need to tell the bank your phone number before they can text you, for webhooks, you need to tell the originating app—your eCommerce store, in this case—the webhook URL of the receiving app, the app where you want the data to be sent.
Say you want to make an invoice for this new order. The app that creates this invoice is on the receiving end—it’s the app that needs the order data.
Automate workflows that drive success
Learn from expert Zapier users, receive personalized support, and find ways to scale your impact at our free user conference.
You’d first open your invoice app, make an invoice template, and copy its webhook URL—something like yourapp.com/data/12345. Then open your eCommerce store app, and add that URL to its webhook settings. That URL is your invoice app’s phone number, essentially. If another app pings that URL (or if you enter the URL in your browser’s address bar), the app will notice that someone is trying to send it data.
Ok. Back to the order. Your eCommerce store got the order and knows it needs to send the details to yourapp.com/data/12345. It then writes the order in a serialization format. The simplest of those formats is called “form-encoded”, and means your customer’s order would look something like this:
Now your eCommerce store needs to send the message. The simplest way to send data to a webhooks URL is with an HTTP GET request. Literally, that means to add the data to the URL and ping the URL (or enter it in your browser’s address bar). The same way you can open Zapier’s about page by typing /about after zapier.com, your apps can send messages to each other by tagging extra text with a question mark on the end of a website address. Here’s the full GET request for our order:
Deep inside your invoice app, something dings and says “You’ve got mail!” and the app gets to work, making a new invoice for Bob’s $10 paper order. That’s webhooks in action.
Remember when you had to check your email to see if you had new messages—and how freeing push email (“You’ve got mail!”) was? That’s what webhooks are for your apps. They don’t have to check for new info anymore. Instead, when something happens, they can push the data to each other and not waste their time checking and waiting.
→ Ready to start using webhooks? Jump ahead to skip the geeky details—or keep reading to learn more about the terms you’ll often see used with webhooks.
That’s the simple version. Technically, webhooks are “user-defined callbacks made with HTTP” according to Jeff Lindsay, one of the first people to conceptualize webhooks. Webhooks are data and executable commands sent from one app to another over HTTP instead of through the command line in your computer, formatted in XML, JSON, or form-encoded serialization. They’re called webhooks since they’re software hooks—or functions that run when something happens—that work over the web. And they’re typically secured through obscurity—each user of an application gets a unique, random URL to send webhook data to—though they can optionally be secured with a key or signature.
Webhooks typically are used to connect two different applications. When an event happens on the trigger application, it serializes data about that event and sends it to a webhook URL from the action application—the one you want to do something based on the data from the first application. The action application can then send a callback message, often with an HTTP status code like 302 to let the trigger application know if the data was received successfully or 404 if not.
Webhooks are similar to APIs—but simpler. An API is a full language for an app with functions or calls to add, edit, and retrieve data. The difference is, with an API, you have to do the work yourself. If you build an application that connects to another with an API, your application will need to have ways to ask the other app for new data when it needs it. Webhooks, on the other hand, are for one specific part of an app, and they’re automated. You might have a webhook just for new contacts—and whenever a new contact is added, the application will push the data to the other application’s webhooks URL automatically. It’s a simple, one-to-one connection that runs automatically.
How to use webhooks
You know the lingo, understand how apps can message each other with webhooks, and can even figure out what the serialized data means. You speak webhook.
It’s time to use it. The best way to make sure you understand how webhooks work is to test it out, try making your own webhooks, and see if they work. Or, you can jump ahead and just drop your webhook URL into an app to share data—after all, you don’t have to know how to make webhooks to use them.
Here are the resources you need:
Test webhooks with RequestBin and Postman
The quickest way to learn is to experiment—and it’s best to experiment with something you can’t break. With webhooks, there are two great tools for that: RequestBin (owned by Pipedream) and Postman.
How data appears in Requestbin
RequestBin lets you create a webhooks URL and send data to it to see how it’s recognized. Go to RequestBin, click Create a RequestBin, then copy the URL it gives you.You’ll need to have a Pipedream account (created with Google or GitHub) before you can view and use a URL.
Now, serialize some data in form encoded style—or copy our example form copy above. Open a new tab, paste your RequestBin URL in the URL bar, add a ? to the end, then paste your serialized data. You’ll end up with something like this:
Press enter in your browser’s address bar, and you’ll get a simple message back: success:true. Refresh your RequestBin tab, and you’ll see the data listed at the bottom as in the screenshot above.
Click REST under INTEGRATIONS to see the data.
You can then try sending POST requests in Terminal or from your own app’s code, if you’d like, using RequestBin’s sample code. That’s a bit more complex—but gives you a way to play with JSON or XML encoding, too.
The setup in Postman
Or, use another app for that. The app Postman lets you make custom HTTP requests for an easy way to send customized data to a webhooks URL. Enter the URL, then choose the HTTP request method you want to use (GET, POST, PUT, etc), and add the body data. That’ll let you send far more detailed requests to your webhook URL without having to use more code.
Add webhooks to your apps
Testing webhooks and serializing data by hand is tricky—as is copying and pasting data from your apps. Let’s skip both, and just get our apps talking to each other.
We’re using WordPress-powered form tool Gravity Forms and document template-builder app WebMerge as the examples here—but the same general idea works in most other apps that support webhooks. Here’s essentially what you need to do:
Open your form’s Webhook settings in Gravity Forms
First, enable webhooks in your app if they’re not already and open the webhooks settings (in Gravity Forms, for instance, you need to install an add-on; in Active Campaign or WooCommerce, you’ll find webhooks under the app’s default settings). Your app might have one set of webhook settings for the entire app—or, often, it’ll have a specific webhook for each form, document, or other items the app maintains.
We want the data to come from Gravity Forms, so we’ll open the Webhooks settings under the form we want to use. That gives us a URL field (this lets us tell Gravity Forms where we want to send the data) and options to specify the webhook HTTP request method (how to send the data).
Each WebMerge document template has a unique webhook URL.
Now let’s get that URL from the app that will receive the data—WebMerge, in this case. In WebMerge, each document has its own “merge URL”—and it wants the data in form encoded serialization, as you can tell from the ampersands in the example data. Copy the merge URL—or whatever URL your app offers, as it may have a different name.
Tip: You’ll often find webhook URLs and related settings under the “integration”, “webhook”, or “workflow” settings, depending on your app.
Add the webhooks URL to your trigger app so it can share data when something happens
Finally, go back to your trigger app—Gravity Forms in our case—and paste the webhook URL in Gravity Forms’ URL field. You may also be able to set the correct request method and the specific field values to ensure only the data you want is sent, and is shared with the same variable names as the receiving app uses. Save the settings, and you’re good to go.
The next time someone fills out our form that Bob ordered 10.00 of paper, Gravity Forms will send the data to WebMerge’s URL as https://www.webmerge.me/merge/149933/gxszxg?Name=Bob&Item=Paper&Value=10.00 and WebMerge will turn that into a complete invoice.
PayPal IPN is very similar to webhooks—and you can add a webhook URL to PayPal to get payment notifications
Once you start using webhooks, you’ll notice them (or similar links) everywhere, in places you never thought they’d show up. PayPal, for instance, uses Instant Payment Notifications or IPNs to send notifications whenever you receive a payment. Have an app that you’d like to do something whenever you get a PayPal payment? Add its webhooks URL to PayPal’s IPN settings and that app will get a message the next time you get money.
Or take Twimlets, Twilio‘s simple apps to forward calls, record voicemail messages, start a conference call, and more. To, say, forward a call, you’ll add a familiar, webhook-style Twimlet address like http://twimlets.com/forward?PhoneNumber=415-555-1212 to your Twilio phone number settings. Want to build your own phone-powered app, or notify another app when a new call comes in? Put your webhook URL in Twilio’s settings instead.
They might go by different names, but once you notice places where apps offer to send notifications to a unique link, you’ll often have found somewhere else webhooks can work. Now that you know how to use webhooks, you can use them to make software do whatever you want.
Use webhooks in any app with Zapier
Many apps on Zapier use webhooks behind the scenes already. You may not realize it, since Zapier apps generally handle all the actual setup for you. If you come across an app that offers webhooks as an option, you can use a webhooks step in a Zap to set that up yourself using what you’ve learned about webhooks. Note: Webhooks by Zapier is a built-in tool only available to Zapier users on a paid plan or during their trial period.
Say you have an app that can send data to a webhooks URL. To connect it to other apps, you’ll make a new Zap—what we call Zapier’s automated app workflows—and choose Webhooks by Zapier as the trigger app. Select Catch Hook, which can receive a GET, POST, or PUT request from another app. Zapier will give you a unique webhooks URL—copy that, then add it to your app’s webhooks URL field in its settings.
GET requests ask the server for data. POST requests send data to a computer. PUSH requests ask the server for specific data, typically to update it.
Zapier will parse each serialized item from your webhook data
Then have your app test the URL, or perhaps just add a new item (a new form entry, contact, or whatever thing your app makes) to have your app send the data to the webhook. Test the webhook step in Zapier, and you’ll see data from the webhook listed in Zapier.
You can add each data item from your webhook to another app in Zapier
Now you can use that data in another app. Select the action app—the app you want to send data to. You’ll see form fields to add data to that app. Click in the field where you want to add webhooks data and select it from the dropdown. Test your Zap and it’s now ready to use. Now the next time your trigger app sends data to the webhook, Zapier will automatically add it to the action app you selected.
Zapier can send any data you want to a webhooks URL
The reverse works as well. Want to send data from one app to another via webhooks? Zapier can turn the data from the trigger app into a serialized list and send it to any webhooks URL you want.
First, select the trigger app you want to send data from, and set it up in Zapier as normal. Then select Webhooks as the action app, and choose how you want to send the data (POST is typically the best option for most webhook integrations).
Finally, paste the webhooks URL from the app you want to receive the data into the URL field in Zapier’s webhook settings. You can choose how to serialize the data (form or JSON are typically best). Zapier will then automatically send all of the data from your trigger app to the webhook—or you can set the specific data variables from the Data fields below.
You can specify how Zapier serializes your data and choose the specific data it sends to your webhook
You’re now ready to use your Zap. Now whenever something new happens in your trigger app, Zapier will copy the data and send it to your other app’s webhooks URL.
Webhooks are one of the best ways to connect apps that wouldn’t otherwise work with Zapier. Have a Mac or iPhone app that doesn’t connect with Zapier? Using Alfred or Siri Shortcuts—plus a Zapier Webhooks URL—you can connect them to your Zapier workflows. Here’s how:
Ok, you’ve got this. Armed with your newfound knowledge about webhooks and their confusing terminology, you’re ready to start using them in your work. Poke around your favorite web apps’ advanced settings and see if any of them support webhooks. Think through how you could use them—then give it a shot.
And bookmark this article. Next time you read something about a GET request needing to make an HTTP callback, or see a URL with ?name=bob&value=10 and such at the end, you’ll know what it actually means.
The global cybersecurity market is flourishing. Experts at Gartner predict that the end-user spending for the information security and risk management market will grow from $172.5 billion in 2022 to $267.3 billion in 2026.
One big area of spending includes the art of putting cybersecurity defenses under pressure, commonly known as security testing. MarketsandMarkets forecasts the global penetration testing (pentesting) market size is expected to grow at a Compound Annual Growth Rate (CAGR) of 13.7% from 2022 to 2027. However, the costs and limitations involved in carrying out a penetration test are already hindering the market growth, and consequently, many cybersecurity professionals are making moves to find an alternative solution.
Pentests aren’t solving cybersecurity pain points
Pentesting can serve specific and important purposes for businesses. For example, prospective customers may ask for the results of one as proof of compliance. However, for certain challenges, this type of security testing methodology isn’t always the best fit.
1 — Continuously changing environments
Securing constantly changing environments within rapidly evolving threat landscapes is particularly difficult. This challenge becomes even more complicated when aligning and managing the business risk of new projects or releases. Since penetration tests focus on one moment in time, the result won’t necessarily be the same the next time you make an update.
2 — Rapid growth
It would be unusual for fast-growing businesses not to experience growing pains. For CISOs, maintaining visibility of their organization’s expanding attack surface can be particularly painful.
According to HelpNetSecurity, 45% of respondents conduct pentests only once or twice per year and 27% do it once per quarter, which is woefully insufficient given how quickly infrastructure and applications change.
3 — Cybersecurity skills shortages
As well as limitations in budgets and resources, finding the available skillsets for internal cybersecurity teams is an ongoing battle. As a result, organizations don’t have the dexterity to spot and promptly remediate specific security vulnerabilities.
While pentests can offer an outsider perspective, often it is just one person performing the test. For some organizations, there is also an issue on trust when relying on the work of just one or two people. Sándor Incze, CISO at CM.com, gives his perspective:
“Not all pentesters are equal. It’s very hard to determine if the pentester you’re hiring is good.”
4 — Cyber threats are evolving
The constant struggle to stay up to date with the latest cyberattack techniques and trends puts media organizations at risk. Hiring specialist skills for every new cyber threat type would be unrealistic and unsustainable.
HelpNetSecurity reported that it takes 71 percent of pentesters one week to one month to conduct a pentest. Then, more than 26 percent of organizations must wait between one to two weeks to get the test results, and 13 percent wait even longer than that. Given the fast pace of threat evolution, this waiting period can leave companies unaware of potential security issues and open to exploitation.
5 — Poor-fitting security testing solutions for agile environments
Continuous development lifecycles don’t align with penetration testing cycles (often performed annually.) Therefore, vulnerabilities mistakenly created during long security testing gaps can remain undiscovered for some time.
Bringing security testing into the 21st-century Impact
A proven solution to these challenges is to utilize ethical hacker communities in addition to a standard penetration test. Businesses can rely on the power of these crowds to assist them in their security testing on a continuous basis. A bug bounty program is one of the most common ways to work with ethical hacker communities.
What is a bug bounty program?
Bug bounty programs allow businesses to proactively work with independent security researchers to report bugs through incentivization. Often companies will launch and manage their program through a bug bounty platform, such as Intigriti.
Organizations with high-security maturity may leave their bug bounty program open for all ethical hackers in the platform’s community to contribute to (known as a public program.) However, most businesses begin by working with a smaller pool of security talent through a private program.
How bug bounty programs support continuous security testing structures
While you’ll receive a certificate to say you’re secure at the end of a penetration test, it won’t necessarily mean that’s still the case the next time you make an update. This is where bug bounty programs work well as a follow-up to pentests and enable a continuous security testing program.
The impact of bug bounty program on cybersecurity
By launching a bug bounty program, organizations experience:
More robust protection: Company data, brand, and reputation have additional protection through continuous security testing.
Enabled business goals: Enhanced security posture, leading to a more secure platform for innovation and growth.
Improved productivity: Increased workflow with fewer disruptions to the availability of services. More strategic IT projects that executives have prioritized, with fewer security “fires” to put out.
Increased skills availability: Internal security team’s time is freed by using a community for security testing and triage.
Clearer budget justification: Ability to provide more significant insights into the organization’s security posture to justify and motivate for an adequate security budget.
Improved relationships: Project delays significantly decrease without the reliance on traditional pentests.
Want to know more about setting up and launching a bug bounty program?
Intigriti is the leading European-based platform for bug bounty and ethical hacking. The platform enables organizations to reduce the risk of a cyberattack by allowing Intigriti’s network of security researchers to test their digital assets for vulnerabilities continuously.
If you’re intrigued by what you’ve read and want to know about bug bounty programs, simply schedule a meeting today with one of our experts.
Cybersecurity company Imperva has disclosed that it mitigated a distributed denial-of-service (DDoS) attack with a total of over 25.3 billion requests on June 27, 2022.
The “strong attack,” which targeted an unnamed Chinese telecommunications company, is said to have lasted for four hours and peaked at 3.9 million requests per second (RPS).
“Attackers used HTTP/2 multiplexing, or combining multiple packets into one, to send multiple requests at once over individual connections,” Imperva said in a report published on September 19.
The attack was launched from a botnet that comprised nearly 170,000 different IP addresses spanning routers, security cameras, and compromised servers located in more than 180 countries, primarily the U.S., Indonesia, and Brazil.
The disclosure also comes as web infrastructure provider Akamai said it fielded a new DDoS assault aimed at a customer based in Eastern Europe on September 12, with attack traffic spiking at 704.8 million packets per second (pps).
The same victim was previously targeted on July 21, 2022, in a similar fashion in which the attack volume ramped up to 853.7 gigabits per second (Gbps) and 659.6 million pps over a period of 14 hours.
Akamai’s Craig Sparling said the company has been “bombarded relentlessly with sophisticated distributed denial-of-service (DDoS) attacks,” indicating that the offensives could be politically motivated in the face of Russia’s ongoing war against Ukraine.
Both the disruptive attempts were UDP flood attacks where the attacker targets and overwhelms arbitrary ports on the target host with User Datagram Protocol (UDP) packets.
UDP, being both connectionless and session-less, makes it an ideal networking protocol for handling VoIP traffic. But these same traits can also render it more susceptible to exploitation.
“Without an initial handshake to ensure a legitimate connection, UDP channels can be used to send a large volume of traffic to any host,” NETSCOUT says.
“There are no internal protections that can limit the rate of a UDP flood. As a result, UDP flood DoS attacks are exceptionally dangerous because they can be executed with a limited amount of resources.”