Easy Optimizer — Documentation
Everything you need to install, configure and troubleshoot Easy Optimizer — the free all-in-one WordPress speed plugin. Every setting on every tab is explained, including what each exclusion box does. Written for people who have never touched a caching setting before.
Getting started
In a hurry? Do these three things.
This is the whole setup for most sites. Everything after it is detail.
- Install and activate the plugin Plugins → Add New → search "Easy Optimizer" → Install → Activate.
- Run the setup wizard It opens once on activation and applies a preset that is safe for nearly every site.
- Load your site in a private window and click around If everything looks normal, you are done. If not, jump to Troubleshooting — every change is reversible.
What Easy Optimizer does
Easy Optimizer speeds up WordPress by doing several separate jobs that normally need three to five different plugins. It saves a finished copy of each page so WordPress does not rebuild it on every visit (page caching), strips CSS your pages never use, delays JavaScript until a visitor interacts, loads images only as they scroll into view, converts images to smaller modern formats, and cleans up your database.
All of it is free. None of it permanently changes your content — every feature is a switch you can turn back off, and the next page load is built the old way.
Requirements
- WordPress 6.4 or newer
- PHP 7.4 or newer
- No account, credit card or licence key — those are only for the optional Cloud Optimization upgrade
Installing
- Go to Plugins → Add New
- Search for Easy Optimizer
- Click Install Now, then Activate
- Open it from Easy Optimizer in your admin sidebar
Your first 5 minutes
On activation you get a short setup wizard. It asks what kind of site you run, then applies a matching preset. If you skipped it, you can apply a preset by hand at any time.
The golden rule
How to check it worked
- Open your homepage in a private window
- Reload once, then reload again
- The second load should feel noticeably faster
For a real measurement, use the PageSpeed test built into the Dashboard rather than a stopwatch. It records a "before" score on first run so you have something to compare against.
Presets & Safe Mode
A preset sets a group of settings in one click. There are three, each building on the one before it.
| Preset | What it turns on |
|---|---|
| Safe | Page cache, cache preload, browser caching, Gzip/Brotli, font-display swap, LCP preload, lazy load (images, iframes, videos), page prefetching at Moderate eagerness. No Remove Unused CSS, no Delay JavaScript, no minification. |
| Balanced | Everything in Safe, plus Remove Unused CSS in Async mode, Delay JavaScript with jQuery excluded, and Add Missing Image Dimensions. |
| Maximum | Everything in Balanced, but Remove Unused CSS switches to Delayed and jQuery is no longer excluded from the delay queue. Best scores, most testing needed. |
Safe Mode
The Safe Mode button in the top bar is the emergency escape hatch. It backs up your current settings, then applies the Safe preset — which switches off the three modules that visibly break sites: Delay JavaScript, Remove Unused CSS and minification. Click it again to restore exactly what you had.
Use it when something is wrong and you need the site correct right now; then work back up one setting at a time.
The Dashboard
The first screen shows what is currently running and gives you four tools.
| Element | What it is |
|---|---|
| Speed test (Before / After) | Runs Google PageSpeed Insights against your site and shows two rings. The "Before" score is captured on the first run, before your optimizations settle, so you have an honest comparison. Three free tests per day without setup; add a free Google API key in Settings for unlimited. |
| Compatibility card | Lists other active plugins doing the same job, detected by reading their real settings. Two tiers: proven overlaps (we read the other plugin's own configuration) get an admin notice; soft matches are listed here only. |
| Debug Issues | A guided tool for finding which optimization is breaking a page. See Debug tools. |
| Debug Log | Errors and warnings Easy Optimizer recorded on its own. The badge shows how many entries are waiting. |
| Cache status pill | "Healthy" when the page cache is on, "Idle" when it is off, plus the current serving mode (PHP or .htaccess). |
Caching Safe to enable
What page caching actually is
Normally, every visit makes WordPress boot PHP, query the database, load your theme and render the HTML from scratch — even when the page has not changed. With caching on, the first visit generates the HTML normally and saves a static copy to disk. Every visitor after that gets the pre-built file, skipping the entire WordPress stack. This typically takes response time from 500ms+ down to under 10ms, and it is almost always the biggest single speed win available.
Enabling it
- Open the Caching tab
- Tick Enable Page Cache
- Save
Logged-in users and pages that must never be cached (cart, checkout, account) are excluded automatically. The rest of the tab only appears once caching is on.
Every field on this tab
| Field | What it does | Default |
|---|---|---|
| Enable Page Cache | The master switch. Saves fully-optimized HTML to disk and serves it on later visits. | On |
| Serving Mode | PHP works on every server but loads a tiny PHP bootstrap first. .htaccess rewrites serves the cached file before PHP starts at all — faster, Apache only, and greyed out if your server is not Apache. Both produce identical HTML. | Auto-detected |
| Cache Lifetime | How long a cached page is kept. "Until cleared manually" is recommended: the cache already clears itself when you publish or update content, so a timer only forces needless rebuilds. | Until cleared |
| Separate Mobile Cache | Stores a second copy of each page for phones. Needed when your theme outputs different HTML on mobile. | On |
| Cache for Logged-in Users | Creates role-based cache files — one per WordPress role. Only enable this if logged-in pages show identical content to everyone in the same role. Shopping carts, dashboards and "Hello, Username" can show another user's cached data. | Off |
| Browser Caching | Adds Expires and Cache-Control headers so returning visitors reuse CSS, JS, fonts and images they already downloaded. | On |
| Gzip / Brotli Compression | Compresses HTML, CSS, JS, JSON, SVG and fonts before sending. Smaller downloads, no visual change. | On |
| Preconnect to External Origins | Opens a connection early to external services like Google Fonts and CDNs, so their files start downloading sooner. | On |
| Preload Cache | Crawls your sitemap in the background so pages are already cached before a real visitor arrives — instead of the first visitor paying to build them. | On |
| Preload Speed | How many pages the preloader fetches at once. Gentle = one at a time (shared hosting), Balanced = up to 3 (recommended), Turbo = up to 5 (VPS/managed). Only shown when Preload Cache is on. | Gentle |
The four cache exclusion boxes
These are the fields people most often get wrong, so each one is explained in full. All four open in a popup editor and take one entry per line.
Excluded URLs
easyopt_cache_exclude_urlsPages that must never be served from the cache. Each line is matched as a substring of the URL — if the current URL contains the line anywhere, that page bypasses the cache and is rendered fresh every time.
Cart, checkout and account pages are already excluded automatically. Add your own for anything that shows per-visitor content: a booking form, a members area, a page with a live counter.
/cart
/checkout
/my-account
/booking-step-
Excluded Cookies
easyopt_cache_exclude_cookiesVisitors carrying any of these cookies bypass the cache entirely, on every page. Use this when a plugin marks a session that changes what the whole site shows — a wholesale price tier, a language override, an A/B test variant.
Match is on the cookie name, as a substring. One per line.
my_custom_session
wholesale_customer
Ignored Query Parameters
easyopt_cache_strip_query_paramsEvery value shares ONE cache file. /page/?utm_source=google and
/page/?utm_source=facebook are both served the cached copy of /page/.
This is what keeps campaign links fast. Without it, a single newsletter send would split one page into thousands of separate cache files and your disk would fill with near-identical copies.
Around 90 tracking parameters (utm_*, gclid, fbclid,
msclkid and friends) are already ignored by default — add your own here only if you
use a tracking parameter we do not know about.
my_tracking_param
partner_id
Cache Query String
easyopt_cache_query_stringsThe opposite of the box above: each value gets its OWN cache file. Use this
when your server actually renders the parameter into the page — a form that writes UTM values
into hidden fields, or a plugin that shows different content per ?ref=.
Listing a parameter here also stops it being ignored, so this is how you override one of the ~90 defaults.
Two rules worth taking seriously:
- List every parameter your page reads. Keying on
utm_sourcealone still leavesutm_campaignshowing the first visitor's value to everyone else. - Per-click IDs are refused.
gclid,fbclid,msclkidand_gahave a unique value per visitor, so each one would create a cache file per visit and fill your disk. The plugin will not accept them.
Empty by default. Add only what your pages genuinely vary on.
utm_source
utm_medium
utm_campaign
Clearing the cache
The cache clears itself when you publish or update content. Clear it by hand from the Clear cache button in the admin bar after you switch themes, change a setting in another plugin, or edit a template file directly over FTP.
Nginx servers
If you are on Nginx in PHP serving mode, an optional server-rules snippet appears at the bottom of the tab. It lets Nginx serve cached pages without starting PHP at all. It is not required — your cache already works. Many managed hosts do not allow server changes; if yours does not, ignore it. If yours does, send the snippet to them as a standard server-block change.
Optimization: JavaScript Test after enabling
Delay vs Defer — the difference
Delay until interaction rewrites scripts so they do not load at all until the visitor clicks, scrolls or presses a key. This gives the best PageSpeed scores because the browser can focus entirely on rendering. It can also break features that need JavaScript immediately — sliders, analytics, popups, payment gateways.
Defer adds the standard HTML defer attribute. Scripts download in
parallel with HTML parsing and run after the document is parsed, but before any interaction. Safer,
rarely breaks anything, smaller speed gain.
Recommendation: start with Defer. If the site is fine, switch to Delay for better scores. Always test checkout and contact forms after switching.
| Field | What it does | Default |
|---|---|---|
| Minify JavaScript | Strips whitespace and comments from local JavaScript files. Independent of the delay settings — you can use either without the other. Uses the same exclusion list as Exclude Scripts below. | Off |
| Delay JavaScript Execution | Master switch for the delay/defer engine. Nothing below appears until it is on. | Off |
| Method | delay = wait for interaction (best scores). defer = native browser defer (safer). | delay |
| Exclude jQuery | Keeps jQuery and WordPress core scripts out of the queue. Recommended for most sites — a great deal of theme and plugin code assumes jQuery is already there. Turning it off gives the best possible score and is what the Maximum preset does. | On |
The JavaScript exclusion boxes
Exclude Scripts
easyopt_delay_js_excludeKeywords for scripts that must keep running normally. Each line is matched as a
substring against both the script's src URL and its inline contents,
so a fragment of the filename is usually enough.
This is the field you use when something breaks. Right-click the broken element, choose Inspect, find the script that powers it, and add a distinctive piece of its filename here.
Also used by Minify JavaScript — anything listed here is left unminified too.
jquery.min.js
gtag/js
woocommerce
slider-pro
Exclude URLs
easyopt_delay_js_exclude_urlsWhole pages where JavaScript optimization should not run at all. Substring match against the URL, one per line. Use it for checkout, booking and any page where you would rather have correctness than a score.
/checkout/
/cart/
/book-appointment/
Include Inline Scripts
easyopt_delay_js_include_inlineThe reverse of an exclusion. Inline <script> blocks are normally left alone;
matching ones are converted into delayed external files instead.
Use it for tracking snippets pasted directly into your theme — Google Analytics, Meta Pixel — which are often the heaviest inline blocks on the page.
Only shown when Method is delay; native defer cannot apply to inline scripts.
gtag
fbq
Optimization: CSS Test after enabling
How unused-CSS removal works
Themes and plugins load CSS for every feature they offer, whether or not a given page uses it. A typical page loads 300–500 KB of CSS and actually uses 30–50 KB. This module analyses each page type, works out which selectors the HTML really uses, and generates a slim "used CSS" file with only those rules.
Because it decides by reading the server's HTML, styles that only apply to classes JavaScript adds after load can be missed. Three layers guard against that: a built-in safelist, an Elementor animation extractor, and a one-time visitor beacon that reports the live class list back and folds it into the next build. The Exclude Selectors box is your manual override.
| Field | What it does | Default |
|---|---|---|
| Minify CSS | Strips whitespace and comments from local stylesheets. Independent of unused-CSS removal. Uses the Exclude Stylesheets list below. | Off |
| Enable Remove Unused CSS | Master switch. Nothing below appears until it is on. | Off |
| CSS Delivery Method | Inline embeds the used CSS directly in the page — fastest for most sites. File saves it as a separate cacheable .css file — better when the used CSS exceeds roughly 500 KB, but can cause a flash of unstyled content. | Inline |
| Stylesheet Behavior | What happens to the original full stylesheets. Delay loads them on first interaction (safest fallback). Async loads them without blocking render. Remove strips them permanently — best scores, and the only option with no safety net. | Delayed |
| Process Post Types Only | Shares one generated stylesheet across all Posts, or all Products, or all entries of a custom post type, instead of building one per URL. Pages are skipped. Turn it on when you have many similar entries; it cuts generation work enormously. Forced off — and greyed out — when Behavior is Remove, because per-page processing is required once originals are stripped. | On |
The CSS exclusion boxes
Exclude Selectors
easyopt_unused_css_exclude_selectorsCSS selectors to keep regardless of whether they appear in the page HTML. This is the safelist, and it is the fix for "a section lost its styling".
When JavaScript adds a class after the page loads — .is-open on a menu,
.active on a tab, a slider's own generated classes — the plugin could not see it
when it built the used CSS. Add it here and its rules are always kept.
One selector per line. Class, id and attribute selectors all work.
.my-class
#my-id
.slick-active
.is-open
Exclude Stylesheets
easyopt_unused_css_exclude_stylesheetsWhole stylesheets to leave completely alone — not pruned, not minified, not touched. Match on
the WordPress stylesheet handle or any fragment of its src URL.
Use it for a stylesheet you know is fragile, or one whose selectors are all generated at runtime. Note this list is shared with Minify CSS.
dashicons.min.css
my-fragile-plugin
Exclude URLs
easyopt_unused_css_exclude_urlsWhole pages where unused-CSS processing should not run. Substring match against the URL, one per line. Checkout is the usual candidate.
/checkout/
Include Inline Styles
easyopt_unused_css_include_inlineConverts matching inline <style> blocks into external files so they can be
processed and cached like any other stylesheet. Match on the block's id or a fragment of its
content.
wp-custom-css — the CSS from the WordPress Customizer — is the common one.
wp-custom-css
Keep Whole Stylesheets
easyopt_unused_css_passthrough_stylesheetsPage-builder CSS that is already page-specific. These stylesheets are folded into the used CSS in full, minified but with no selectors removed.
Why this exists: Elementor and Divi generate a stylesheet per page containing only that page's rules. Pruning them by what appears in the HTML would strip the classes their JavaScript adds at runtime, and there is nothing to gain — the file is already minimal.
Divi's /et-cache/ is included by default. Add Elementor's path if you use it.
/uploads/elementor/css/post-
Clear Used CSS Cache
The button at the bottom of the tab deletes every generated stylesheet so they rebuild from scratch on the next visit. Use it after a theme update, a big design change, or after editing your safelist. The learned metadata — the JavaScript class list and above-the-fold fonts — deliberately survives this, so you do not lose the beacon's training.
Optimization: Lazy Load Safe to enable
By default browsers download every image, iframe and video on a page before displaying it — including images far below the fold that the visitor may never reach. Lazy loading tells the browser to fetch media only as it is about to enter the viewport. Less initial bandwidth, faster render, better LCP and Speed Index.
| Field | What it does | Default |
|---|---|---|
| Lazy Load Images | Defers offscreen images, including CSS background images. | Off |
| Browser-native lazy load | Uses the browser's own loading="lazy" instead of a JavaScript swap. Keeps the real src, srcset and sizes on the element so the browser's preload scanner can still find them, and drops the JS runtime from most pages. Turn it off only if your theme styles the .lazyload / .lazyloaded classes. | On |
| Lazy Load Iframes | Defers iframes — YouTube embeds, Google Maps, forms. | Off |
| Lazy Load Videos | Defers <video> elements. | Off |
| Exclude First N Images | How many images from the top of the page to load eagerly. This one matters. Your hero image and logo are needed for the first paint, so lazy-loading them makes LCP worse, not better. Set it to the number of images visible without scrolling — usually 1 to 3. | 1 |
| Add Missing Image Dimensions | Reads the actual image files to fill in missing width and height attributes. This reserves the right space before the image arrives, which is how you stop the page jumping around as it loads (Cumulative Layout Shift). | Off |
Exclude from Lazy Load
easyopt_lazyload_excludeImages that must always load immediately. Match on a CSS class name or any fragment of the image URL, one per line.
Use it for your logo, a hero image whose filename you know, or anything a script measures on load. If an image is missing on your live site but present when lazy loading is off, this is where the fix goes.
logo
hero-image
above-fold
Exclude from Missing Dimensions
easyopt_dims_excludeImages that should not have width/height added. Match on class name or src
fragment.
This exists mainly for SVGs and for images your CSS resizes responsively, where a hard-coded width and height can fight the stylesheet and distort the image.
logo
svg-icon
Optimization: Preload LCP Safe to enable
Largest Contentful Paint is the largest visible image or text block in the viewport, and one of Google's three Core Web Vitals. This module finds each page type's LCP image and tells the browser to fetch it first.
How detection works
- First visit — a lightweight JavaScript beacon (using
PerformanceObserver) watches the page and reports which image was the LCP element. This is the training visit; no optimization happens yet. - Later visits — a
<link rel="preload">withfetchpriority="high"is injected into the<head>for that image, and the matching<img>getsloading="eager".
Results are stored per URL type and per viewport (mobile and desktop separately) and refreshed every 30 days.
| Field | What it does | Default |
|---|---|---|
| Auto Preload Largest Image | Master switch for the detection and preload described above. | On |
| Clear all LCP data | Button. Forgets every detected LCP image so they are re-learned on the next visits. Use it after a redesign changes which image is biggest. | — |
Exclude URLs
easyopt_lcp_exclude_urlsPages where LCP detection should not run — neither the beacon nor the preload tag. Substring match against the URL, one per line.
Worth excluding pages where the largest image changes per visitor, since a preload for the wrong image is wasted bandwidth.
/checkout/
/cart/
Optimization: Prefetch Pages Safe to enable
Starts loading the next page while the visitor is still deciding, so the click feels instant.
How it works
Easy Optimizer writes a small set of speculation rules into the top of every page. The browser reads them while still parsing the HTML, then decides for itself when to start loading a link — including how many it can afford on this device and connection.
On top of that, the plugin makes its own predictions: once the page is idle it finds the destination your page links to most often (header, hero button, footer) and starts that one with no interaction at all. It also watches for a "Next page" link, a menu opening, the pointer coming to rest near a link, and — on phones, where there is no hover — scrolling stopping with a link mid-screen. Predictions are capped at four pages per visit.
No JavaScript scans your links and nothing is downloaded up front, so a page with 30 links costs what a page with 10 links costs.
| Field | What it does | Default |
|---|---|---|
| Enable Page Prefetching | Master switch. While on, Easy Optimizer replaces WordPress's own built-in speculative loading so a page never carries two competing rule sets. Turn it off and WordPress resumes handling it. | Off |
| Prerender | Goes further than prefetch: the browser builds the entire page in the background — scripts, subresources, paint — so the click is instant rather than merely fast. Much more expensive, and measurement showed it rarely completing in the window it gets. Chromium only; Safari and Firefox keep plain prefetching. Off by default; only turn it on if you have measured that it helps. | Off |
| Eagerness | How early the cheap prefetch starts. Conservative — only on pointer-down, just before the click; predictions off. Moderate — after a short hover or on keyboard focus, plus predictions. Eager — as soon as the browser sees the link; uses more bandwidth. | Moderate |
Footer links are always treated as low-intent and stay on pointer-down whichever setting you pick. Cart, checkout, account, feed, admin, download and query-string URLs are never speculated.
Exclude URLs
easyopt_instant_preload_exclude_urlsURLs never to prefetch, one per line. This box has wildcard support, unlike most of the
others. A line without * matches anywhere in the URL; * is a
wildcard.
Use it for anything with a side effect — a logout link, a "download" endpoint, a one-time token URL — where merely loading the page does something.
/cart
private/*
ref=
Exclude CSS Selectors
easyopt_instant_preload_exclude_selectorsCSS selectors matching links to skip, one per line. Use it when you can identify the links by markup rather than by URL — for example every link inside a widget, or every link you have tagged with a data attribute.
a.no-prefetch
[data-no-prefetch]
.widget-area a
Image Optimization Safe to enable
This tab has a two-way picker at the top: This server (free) and Smart Images (the Cloud upgrade). Both do the same job — optimize every image on your site — and differ only in where the work happens.
Your originals are never modified
This is the part worth understanding before you enable anything. Most image plugins convert
photo.jpg into a new file, then rewrite your post content, your custom fields and the
attachment GUID to point at it — so undoing it is a database migration.
Easy Optimizer writes siblings instead:
2026/09/photo.jpg ← untouched, still the canonical URL
2026/09/photo.jpg.webp
2026/09/photo.jpg.avif
The right file is chosen when the page renders, by wrapping the image in a
<picture> element. No stored URL changes and nothing is written to your database.
Restoring is deleting the extra files — it cannot half-fail.
The extension is appended rather than replaced, so photo.jpg.avif and
photo.png.avif can never collide.
Can your host do it?
A banner at the top of the tab states plainly what your server can encode. AVIF and WebP need
support compiled into your server's image library, and function_exists() is not proof —
so the plugin encodes a real test image, writes it, and reads the bytes back to check. If your host
cannot do modern formats it says so rather than silently doing nothing, and the master switch is
disabled. Your options then are to ask your host to enable it, or to use
Cloud Optimization, which encodes on our servers instead.
| Field | What it does | Default |
|---|---|---|
| Optimize images on this server | Master switch. Disabled entirely when the host cannot encode either format. | Off |
| Optimize new uploads automatically | Queues each image for conversion as it is uploaded, so you never need to run the bulk job again. | On |
| Generate AVIF | Smallest files, supported by every current browser. Greyed out if your image library was built without AVIF support. | On |
| Generate WebP | Broader support on older browsers. Keep both on: each browser gets the best format it can read. | On |
| Serve optimized images | Wraps images in <picture> so the browser picks the format. Turning this off keeps generating copies without serving them — useful for building the library first and switching delivery on once. | On |
| AVIF quality | 40–75. Lower is smaller. AVIF holds quality at a lower number than WebP, so 55 and 78 look comparable — not a typo. | 55 |
| WebP quality | 60–90. Lower is smaller. | 78 |
| Maximum image dimension | Under Advanced. Caps how large new uploads may be — 2560px for full-width heroes, 1920px for standard desktop, 1280px for smaller sites. "Don't resize" is recommended unless you know your contributors upload camera-original photos. | Don't resize |
| Also shrink existing oversized originals | Under Advanced. The only setting in the plugin that modifies your uploaded files. The original is copied to a backup folder first and the new file is validated before the swap, and "Restore all" puts every original back — but take your own backup anyway if your images are irreplaceable. | Off |
| Ask WordPress to save uploads as | Under Advanced. WordPress 7.1+ can convert uploads in the visitor's browser; this tells it which format to use. Applies to new uploads on supporting browsers only — everything else is handled by the server-side pipeline. "Leave WordPress alone" is recommended. | Leave alone |
Running the bulk job
Click Optimize N remaining. The progress bar updates on its own while the queue runs, and you can leave the page — it keeps going in the background. Work is done in small chunks with a memory check before each image, so a very large photo cannot exhaust your host's memory limit and kill the run.
Some images are skipped and reported as such: unsupported formats, animated GIFs, images too large to decode safely, and images already smaller than their converted version would be. That last case is normal — converting a tiny icon to AVIF often makes it bigger.
Restore all deletes every generated copy and puts your originals back. Since the originals were never modified, nothing is lost.
Exclude images (Image CDN)
easyopt_image_excludeApplies to the CDN/cloud engine. Images to leave on your own server, matched on a fragment of the image URL or a CSS class, one per line.
Use it for images that must be served from your own domain — a signature graphic, an image another service hot-links, or anything behind access control.
/uploads/private/
no-cdn
Fonts Safe to enable
What font-display: swap fixes
While a web font is still downloading, a browser either shows nothing (a flash of invisible text)
or shows a fallback system font (a flash of unstyled text). font-display: swap tells it
to show the fallback immediately and swap in the web font when ready. Google Lighthouse specifically
recommends it.
| Field | What it does | Default |
|---|---|---|
| Force Font Display Swap | Adds font-display: swap to every @font-face declaration. Safe on essentially every site. | On |
| Smart Preload Fonts | Uses a one-time visitor beacon to learn which fonts each page actually uses above the fold, then preloads exactly those. Requires Remove Unused CSS — it is built on the same engine, and the field is greyed out with a link to the CSS tab until that is on. | Off |
| Smart Lazyload Fonts | Defers below-the-fold fonts and keeps only above-the-fold ones in the critical CSS. Also requires Remove Unused CSS. Deliberately left out of all three presets: it can visibly delay icon fonts and FontAwesome glyphs above the fold, so enable it yourself and check. | Off |
| Clear fonts data | Button. Forgets the collected above-the-fold fonts so they are re-learned. Use after a font change. | — |
Exclude Fonts
easyopt_fonts_excludeFont families or font URLs to keep in the used CSS unconditionally, one per line. Only shown when Smart Lazyload Fonts is on.
This is the fix for icon fonts. FontAwesome and similar render through CSS
::before pseudo-elements, which the beacon cannot always attribute to above-the-fold
content — so they get deferred and your icons appear late as empty boxes. Listing them here keeps
them loading immediately.
font-awesome
icons
Material Icons
Exclude URLs (Fonts)
easyopt_fonts_exclude_urlsPages where font optimization should not run at all. Substring match against the URL, one per line. Useful for a landing page with a custom typeface you would rather not risk.
/my-custom-page/
/landing/
Object Cache Advanced
Object cache vs page cache
The page cache stores finished HTML. An object cache stores the ingredients — the results of individual database queries and option lookups — in memory, so repeat lookups never hit MySQL.
The page cache helps logged-out visitors. The object cache helps everything the page cache cannot serve: logged-in users, WooCommerce carts and checkout, the admin area, and any page excluded from caching. If your site is mostly logged-out brochure pages, you probably do not need this. If it is a shop or a membership site, it can be transformative.
Do you have Redis?
You need a Redis server on your hosting. Many managed hosts (Kinsta, Cloudways, WP Engine on some plans, SpinupWP) offer it; most cheap shared hosting does not. Use the Test Connection button — it tells you definitively rather than making you guess.
| Field | What it does | Default |
|---|---|---|
| Enable Object Cache | Installs Easy Optimizer's Redis drop-in at wp-content/object-cache.php. Turning it off removes the drop-in and reverts to WordPress's built-in non-persistent cache. | Off |
| Client | Auto tries Relay, then PhpRedis, then the bundled Predis. Relay and PhpRedis are PHP extensions and much faster; Predis is pure PHP and ships with the plugin, so it works with no extension at all. | Auto |
| Host / Port | Where Redis is listening. Defaults to 127.0.0.1:6379, which is correct on most hosts that offer Redis at all. | 127.0.0.1 / 6379 |
| Username / Password | Redis 6 ACL credentials. Leave blank unless your host gave you some. | Empty |
| TLS | Use an encrypted rediss:// connection. Needed only for a remote Redis; pointless for localhost. | Off |
| Database | Which numbered Redis database to use. Change it only if something else on the server is already using database 0. | 0 |
| Prefix | A string prepended to every key. Set it when several WordPress sites share one Redis instance, so they cannot read or flush each other's entries. Empty means auto. | Auto |
WP_REDIS_* constants or a WP_REDIS_CONFIG array (the Object Cache Pro
format, common on Cloudways), those take priority and the matching fields above are ignored. The
panel says which keys are locked and why, so you are never editing a field that has no effect.
Likewise, if another object-cache plugin already installed a drop-in, Easy Optimizer detects it, names it, and defers — it will not overwrite someone else's drop-in. You can still flush from here.
Cloudflare Advanced
Only relevant if your site is behind Cloudflare. It solves one specific problem: when Easy Optimizer clears its own page cache, Cloudflare is still holding an older copy at the edge, so visitors keep seeing the stale page. This tells Cloudflare to drop its copy at the same moment.
| Field | What it does | Default |
|---|---|---|
| Enable Cloudflare integration | Master switch. | Off |
| API Token | A Cloudflare token with permission to purge cache. Create it at My Profile → API Tokens → Create Token, using the "Edit zone DNS" template or a custom token with Zone → Cache Purge → Purge. Scope it to your specific zone, not all zones. Cloudflare shows the token once — copy it immediately. | Empty |
| Zone ID | Cloudflare dashboard → select your site → Overview → right sidebar, under API. Click to copy. | Empty |
| Purge Strategy | By cache tag purges only the affected pages, but tag-based purging is a Cloudflare Enterprise feature — on any other plan this falls back to purging everything. Purge everything works on all plans and is the honest choice for most sites. | By cache tag |
| Test Connection | Button. Verifies the token and zone before you rely on them. | — |
| Purge Cloudflare Now | Button. Manual full purge, with a confirmation prompt. | — |
Bloat Removal Advanced
Fourteen independent switches that strip optional WordPress features. Each is off by default and each does exactly one thing. Most are completely safe; two can break real functionality and are marked below.
| Toggle | What it removes, and when to use it |
|---|---|
| Disable Emojis | Removes the wp-emoji script and the emoji detection script. Modern browsers render emoji natively, so this is safe on essentially every site. |
| Disable WP Embeds | Removes wp-embed.min.js and oEmbed discovery. Affects only the ability of other WordPress sites to embed your posts as rich cards. Your own YouTube and Twitter embeds keep working. |
| Disable XML-RPC | Closes /xmlrpc.php and removes the X-Pingback header. Safe unless you use the WordPress mobile app, Jetpack's older features, or a remote publishing tool. |
| Remove jQuery Migrate | Strips jquery-migrate, a compatibility shim only old themes and plugins need. If something breaks after enabling this, that code was relying on deprecated jQuery — turn it back on and report it to the plugin's author. |
| Hide WordPress Version | Removes the generator meta tag and ?ver= query strings. A modest security-by-obscurity measure. Note that removing ?ver= can make some CDNs cache an asset past an update. |
| Remove RSD / WLW Manifest | Removes legacy links for Real Simple Discovery and Windows Live Writer from your page header. Almost no site still needs these. |
| Remove Shortlinks | Removes the wp-shortlink tag from the header. Cosmetic; no effect on SEO. |
| Disable RSS Feeds Breaks things | Returns 404 for all /feed/ URLs. This breaks podcast plugins, RSS readers, email-newsletter services that pull from your feed, and some social auto-posting tools. Only enable if you are certain nothing consumes your feed. |
| Disable Self Pingbacks | Stops your site pinging itself when you link between your own posts. Safe and genuinely useful — self-pingbacks are only ever noise. |
| Limit REST API to Logged-in Users Breaks things | Returns 401 to anonymous wp-json requests. This breaks many contact-form plugins, the WooCommerce Store API, block editor previews for logged-out flows, and any headless or app integration. Test every form on your site immediately after enabling. |
| Disable WooCommerce Cart Fragments | Removes the wc-cart-fragments AJAX script, which fires on every page load to keep a live cart count in the header. If your theme shows a cart counter, it will stop updating without a page refresh. A real speed win on WooCommerce sites that do not display one. |
| Disable Application Passwords | Hides the Application Passwords UI. Safe unless you connect external apps to your site that way. |
| Disable Dashicons (front-end) | Stops loading dashicons.css for logged-out visitors. Safe unless your theme uses Dashicons in its front-end design — check your icons after enabling. |
| Disable Block Library CSS | Removes wp-block-library CSS on the front end. Safe if you build with a page builder and use no Gutenberg blocks in your content. If you do use blocks, they will lose their styling. |
Database Optimization Back up first
Two sub-tabs: Database Cleanup and Autoload Health.
Database Cleanup
Each task shows a live count of how many rows it would affect before you run anything, so you always know the size of what you are about to delete. All tasks are off by default; tick the ones you want and press Run Cleanup Now.
| Task | What it deletes |
|---|---|
| Post Revisions | Old revision rows. WordPress keeps every saved draft of every post forever; on an old content site this is often the single largest cleanup. Your current published content is never touched. |
| Auto Drafts | Empty posts WordPress created when you clicked "Add New" and then navigated away. |
| Trashed Posts | Posts and pages sitting in the trash. They are gone permanently after this. |
| Spam Comments | Comments marked as spam. |
| Trashed Comments | Comments in the trash. |
| Expired Transients | Cached values whose expiry has passed. Always safe — they are cache, and anything still needed is regenerated. |
| All Transients | Every transient, expired or not. Also safe, but briefly slower afterwards while caches rebuild. |
| Optimize Tables | Runs a defragmentation pass on your tables to reclaim space freed by earlier deletions. Skipped automatically on tables above the configured size limit, since optimizing a very large table can lock it. |
Scheduled cleanup and snapshots
| Field | What it does | Default |
|---|---|---|
| Enable scheduled cleanup | Runs your selected tasks automatically on a schedule. | Off |
| Frequency | Daily, Weekly or Monthly. | Weekly |
| Enable automatic snapshots before cleanup | Turn this on before you run anything. Saves the rows a task is about to delete so you can put them back from the Snapshots table. This is your undo. | Off |
| Retention (days) | How long snapshots are kept before being deleted automatically. 1–90. | 14 |
Restoring a snapshot skips any row whose ID already exists, so a restore can never duplicate content you have since recreated.
Autoload Health
WordPress loads every "autoloaded" option into memory on every single page request. A bloated autoload table slows down the entire site, including pages that are otherwise fully cached.
Press Check Autoload Size for a total, a count, and a health verdict:
- Under 512 KB — Healthy
- 512 KB to 1 MB — Fair
- Over 1 MB — Needs attention
Below that is a table of the largest autoloaded options with a per-row toggle. Disabling autoload on an option does not delete it — the option still exists and still works, it just stops being loaded on requests that do not ask for it, and you can re-enable it any time.
Core WordPress options are marked with a padlock and cannot be disabled. For anything else, the usual culprits are abandoned plugins that left a large option behind. If you do not recognise the option name, search it before disabling.
Heartbeat & Cron Advanced
Heartbeat
The WordPress Heartbeat API is a background AJAX request that fires repeatedly while an admin page is open. It powers post autosave, the "someone else is editing this post" lock, and live updates in some plugins. On a busy site — or cheap shared hosting — it can be a surprising share of total server load.
| Field | What it does | Default |
|---|---|---|
| Enable Heartbeat Control | Master switch for the two fields below. | Off |
| Allowed Location | Everywhere — keep it on but change the frequency. Admin pages only — disable on the front end (recommended). Post editor only — disable everywhere else, keeping autosave and edit locks. Disabled everywhere — switches it off completely; you lose autosave and edit-lock warnings. | Admin pages only |
| Frequency | Seconds between beats: 15 (WordPress default), 30, 60, 120 or 300. 60 is a good balance. Hidden when Location is "Disabled everywhere". | 60 |
WP-Cron
WordPress has no real scheduler. Instead it checks for due scheduled tasks on page loads, which means a busy site checks constantly and a site with no visitors never runs its schedule at all.
| Field | What it does | Default |
|---|---|---|
| Enable WP-Cron Throttle | Limits how often WP-Cron may spawn. Recommended only if you have a real system cron hitting wp-cron.php — otherwise you are just delaying your scheduled tasks. | Off |
| Run WP-Cron at most every | 2, 5 or 10 minutes. | — |
Cron Events
Press View Cron Events for every scheduled task on your site: its hook name, schedule, and next run time, with overdue events highlighted in red. Each row has Run (fire it now) and Delete (remove this occurrence).
The panel also tells you whether DISABLE_WP_CRON is defined and, if so, whether a
background run has actually been observed. That second part matters: defining the constant without
setting up a real cron job silently stops every scheduled task on the site, and this is how you find
out.
Accessibility & SEO
These toggles patch common Lighthouse audit failures at render time. They are genuine fixes for the audit, but they are patches — the real fix is in your theme. Enable only what applies to your site, and treat a green score here as a floor, not a substitute for actual accessibility work.
| Toggle | What it fixes |
|---|---|
| Form elements do not have associated labels | Adds an accessible label to inputs that have none, so screen readers can announce what the field is for. |
| Links do not have a discernible name | Gives a name to links whose only content is an icon or an image with no alt text. |
| Buttons do not have an accessible name | The same for icon-only buttons — hamburger menus, close buttons, search toggles. |
| [user-scalable="no"] in viewport | Removes zoom-blocking from your viewport meta tag. Blocking pinch-zoom is a real accessibility failure for anyone with low vision. |
| button, link, menuitem elements without accessible names | Covers elements given a role but no readable name. |
| <frame>/<iframe> without a title | Adds a title to iframes, so a screen reader can say what the embed is. |
| ARIA progressbar without accessible name | Names progress bars. |
| Elements with [tabindex] greater than 0 | Normalises positive tabindex values, which otherwise scramble keyboard tab order across the whole page. |
| Make non-crawlable links crawlable | Any <a> with a missing, empty or javascript:void(0) href is rewritten to "#", so search engines stop reporting it as a broken link. |
| Add missing image alt attributes | Fills missing alt text from the image title or filename. A filename-derived alt is better than nothing for the audit, but write real alt text for images that carry meaning. |
Backend Analyzer
Everything else in this plugin makes the front end faster. This tool tells you why the server is slow in the first place — which is a different problem, and not one caching can fix.
It is off by default and arms only when you explicitly trigger a profile run, so it costs nothing the rest of the time.
| Field | What it does | Default |
|---|---|---|
| Find slow callbacks | Shows how much time each plugin and your theme adds while a page is being built. This is how you find the one plugin costing you 400ms on every request. | On |
| Find slow database queries | Catches database lookups that take too long and points at what is responsible. All saved queries have their values redacted — nothing private is stored. | On |
| Query threshold (ms) | How slow a query must be before it is recorded. Lower catches more and stores more. | 50 |
Enter a URL and run a profile. The results are grouped by component, so "which plugin" is answered directly rather than left as an exercise with a stack trace.
Cloud Optimization
The optional paid upgrade. It does two things: moves images, CSS, JavaScript and fonts onto a 119-location edge network, and sets every local optimization to its best-scoring configuration for you.
Connecting
- Start the 14-day trial from the Cloud Optimization tab (no card required)
- Your licence key arrives by email
- Paste it into the box on that tab and click Connect
What changes automatically on connect
Connecting is opting into the whole stack, so these are switched on for you every time a licence connects — including on a reconnect, so a site whose settings have drifted comes back correct:
- Image optimization, and edge delivery for CSS, JS and fonts
- Delay JavaScript, method
delay, with jQuery included in the queue - Remove Unused CSS, behaviour
delayed - Smart Lazyload Fonts
Your page cache is then cleared so the first visitor after connecting gets the optimized page rather than a stale one.
Disconnecting
Delivery stops and everything runs on your own server again, free, using the plugin's built-in optimizations. Nothing breaks and there is nothing to clean up. If a licence lapses or a bandwidth quota is spent, the same fallback happens automatically on the very next request.
Full detail and pricing: Cloud Optimization.
Settings
| Field | What it does | Default |
|---|---|---|
| Google API key | Optional. You get 3 free PageSpeed tests per day with no setup. For unlimited tests, get a free key from Google: visit console.cloud.google.com, enable "PageSpeed Insights API", create an API key, paste it here. Takes about two minutes. | Empty |
| Delete all plugin data on uninstall | When on, deleting the plugin removes all settings, custom tables, cache files and the advanced-cache.php helper. Leave it off if you might reinstall and want your configuration back. | Off |
| Log Errors | Records genuine failures: cache-write failures, background-task failures, .htaccess write failures. Recommended — leave on. | On |
| Log Warnings | Records early-warning signals: excessive cache purges, a stalled or looping preload queue, an unconfirmed Apache serving mode. Useful when diagnosing cache or preload problems. | Off |
Logging only happens on rare events, so neither toggle has a measurable performance cost.
Export and import settings
Export writes your configuration to a JSON file; import reads one back. Useful for rolling the same setup out across client sites.
Debug tools
Three tools, in escalating order. Something looks wrong → find out what (Debug Issues) → read the errors (Debug Log) → neutralise the settings (Safe Mode).
Query-string debug switches
Add one of these parameters to any front-end URL to disable a single feature for that one request only, without changing any settings. The switched request is never served from or written to the page cache, so you always see fresh output.
| Parameter | Disables |
|---|---|
?nooptimize | All optimizations for this request — minify, CSS, JS, images, fonts, the whole pipeline. If the page is still wrong with this on, the cause is your theme, another plugin, or the server — not Easy Optimizer. |
?nocache | The page cache. Forces a fresh render instead of the stored HTML. |
?nodelayjs | Delay/Defer JavaScript. The most common cause of broken sliders, menus and forms. |
?norucss | Remove Unused CSS. The most common cause of missing styles and layout shifts. |
Example: https://example.com/?nodelayjs. Use & instead of
? if the URL already has a query string — ?ver=2&nooptimize.
Debug Issues
The guided version of the above, in the top bar. You give it a URL, it shows you the same four switches as tick boxes, opens the page with them applied, and asks whether the problem went away. If it did, it names the responsible feature and offers a button straight to that feature's settings so you can add the exclusion.
Two details that save time: a feature already switched off is shown greyed out, because it cannot be the cause; and the generated links carry a marker that makes the optimizations apply to your logged-in admin session, which they normally skip — so the test actually tests something.
Debug Log
Errors and warnings the plugin recorded on its own, with a badge showing how many are waiting. Include its contents when you email support.
Troubleshooting
Work through these in order. In every case the fix is to turn something back off — nothing here is permanent.
My site looks broken after enabling something
- Turn off the last setting you changed, and save
- Clear the cache from the admin bar
- Reload in a private window
If that fixed it, you have your culprit. If you changed several things, use Debug Issues instead of guessing — it isolates one feature per test.
A slider, menu, popup or form stopped working
Delay JavaScript. Confirm with ?nodelayjs on the URL. Then fix it properly: right-click
the broken element, choose Inspect, find the script that powers it, and add a
fragment of its filename to Exclude Scripts. Excluding one script is much better
than turning the whole feature off.
A section lost its styling
Remove Unused CSS. Confirm with ?norucss. The class was almost certainly added by
JavaScript after page load, so the plugin could not see it in the HTML. Add that class to
Exclude Selectors.
My changes don't show up on the site
Almost always caching, and there can be three layers: Easy Optimizer's page cache, your host's
server-level cache, and Cloudflare. Clear all of them. Confirm with ?nocache — if the
page is correct with that parameter, it is purely a cache issue.
Images are missing or blurry
Either lazy loading or image optimization. If images appear only after you scroll past them, add them to Exclude from Lazy Load or raise Exclude First N Images. If they look wrong rather than late, switch off image optimization and reload — your originals were never modified, so they come straight back.
Icons show as empty boxes
Smart Lazyload Fonts deferring an icon font. Add the font family to Exclude Fonts, or switch that setting off — it is deliberately not part of any preset for exactly this reason.
The page jumps around while loading
Missing image dimensions. Turn on Add Missing Image Dimensions on the Lazy Load tab.
My admin area is slow
Not something the page cache can help with — it only serves logged-out visitors. Try Heartbeat Control first, then run the Backend Analyzer to find which plugin is responsible.
The whole site is down / white screen
Rename the easy-optimizer folder inside wp-content/plugins/ using FTP or
your host's file manager. WordPress deactivates it immediately and your site returns. Then email us
what you had just changed — a white screen is a bug on our side, not a mistake on yours.
Still stuck?
Email [email protected] with the URL where you see the problem, the setting you
changed last, your WordPress and PHP versions, a screenshot, and the contents of the Debug Log.
FAQ
Is Easy Optimizer really free?
Yes. Everything documented above except Cloud Optimization is free and always will be, with no account, credit card, trial countdown or feature gate.
Will it break my site?
It can, in the same way any speed plugin can — and every case is reversible by switching one setting back off. The features that cause problems are Delay JavaScript and Remove Unused CSS, both off by default and both with exclusion lists. Nothing in the plugin modifies your content, database or original images.
Do I still need a caching plugin?
No. Page caching is built in. Running a second caching plugin alongside it will cause stale pages.
Does it work with Elementor, Divi and other page builders?
Yes. Builder-generated per-page stylesheets are folded in whole rather than pruned, so the classes
their JavaScript adds at runtime always survive. Divi's /et-cache/ is handled by default;
add Elementor's path to Keep Whole Stylesheets if you use it.
Does it work with WooCommerce?
Yes, and cart, checkout and account pages are excluded from caching automatically. Consider Object Cache as well — it helps the logged-in and checkout pages that a page cache cannot serve.
Does it work on multisite?
Yes. Settings are per-site, so each site in the network is configured independently.
What happens to my site if I delete the plugin?
It goes back to exactly how it was. No content, database rows or image files were ever modified. Cache files and settings are removed too if you enabled "Delete all plugin data on uninstall"; otherwise they are left in place for a reinstall.
Why is my PageSpeed score still low?
Usually one of three things: a heavy theme, too many plugins, or slow hosting. Easy Optimizer can fix how assets are delivered; it cannot make a 2 MB theme small. Run the Backend Analyzer to see where server time actually goes.