DietPress — Full changelog

For each release, see the entries below. The latest version is always at the top.
The current release notes also live in readme.txt under "== Changelog ==".

= 3.7.2 =
* Improved: While the page cache is on, the DietPress menu has a Purge cache entry. It empties the cache from any screen of the dashboard and brings you back to it, with a note of how much was deleted.
* Improved: In Selective loading, on the Strict tab, the modules that have something to act on come first and carry a "Detected on this site" label, so it is clear which ones are yours. The label follows what the module would do and not only whether its plugin is installed: Formidable Forms gets it while it loads its styles on every page, and TablePress on a classic theme.
* Improved: The site analyzer asks the same question as the module, so it no longer suggests the Formidable Forms module when Formidable already loads its styles only where a form is.
* Improved: The Tools tab has a Scheduled tasks section that shows when the daily cleanup of transients and the cleanup of the page cache are due next. When one is late or missing it says so, with the likely reason and what it does and does not affect.
* Improved: The site analyzer warns when the WooCommerce "Recently Viewed Products list" widget sits in a sidebar, even one the theme never shows. While it is there every product page sets a cookie, and no cache stores a page that sets a cookie: not this one, and not the one of the hosting.
* Improved: The DNS prefetch hints for ajax.googleapis.com and stats.wp.com are printed only on pages that load a script or a style from them, or while Jetpack Stats is on. They were printed on every page of every site. The `dietpress_dns_prefetch_domains` filter still adds them back.
* Fix: With Optimize RSS feeds on, which is the default, the RSS feed went out marked as public for an hour for everybody, logged in visitors included. For them it replaced the private, do not store answer WordPress gives, and the feed of somebody who can read private posts includes them, so a cache in front of the site that took the header at its word could hand that feed to other visitors. The header is now sent only to visitors who are not logged in, and never on a response that sets a cookie or is already marked private.
* Fix: With a lifetime chosen for HTML pages under browser caching, a page that set a cookie went out marked as public, which lets a cache in front of the site keep it and hand that cookie to other visitors. It now goes out as private, with the same lifetime, so a cache in front that used to keep such pages anyway stops keeping them. Sites with the default, no lifetime for HTML, were not affected.
* Fix: The answer the page cache gives a visitor who already has the current copy (a 304) was sent before declaring the type of the page, so on a site whose charset is not UTF-8 it could leave with the wrong one. Apache and PHP-FPM remove the type from that answer, so most sites never sent it.

= 3.7.1 =
* Improved: "Test the cache now" tests the page in the field above it, typed or picked from the search, or the home page when the field is empty, and every result says which page it tested. Switching the accelerator on still tests the home page.
* Improved: When a cache in front of the site answers the test instead of WordPress, the test says so and names the header that gave it away, instead of blaming the cache folder.
* Improved: A page left out of the cache for setting a cookie now names the cookie, which usually tells which plugin sets it.
* Improved: The confirmation for running on top of a hosting cache is now a tick box inside the page cache card, next to its warning, instead of a card of its own. Once ticked, the warning turns into a plain note there and no longer shows on the dashboard.
* Fix: With the DietPress page cache on, the pages it builds go out telling the caches in front not to keep them, as the copies it serves already did. Since 3.7.0 they went out without saying anything, so a hosting cache could keep them and serve them ahead of DietPress, out of reach of its purges, and switching the accelerator on failed saying the cache folder could not be written.
* Fix: The accelerator could be switched on while the page cache was off, and showed as on while nothing ran. It now stays locked until the page cache is on, and unlocks as soon as that toggle is ticked.
* Fix: Saving any setting without the confirmation for a second cache switched off, and emptied, a page cache that was already running when a hosting cache appeared. The confirmation is now asked only when switching the page cache on, and the message says what to tick.
* Fix: With a hosting whose page cache is switched on from its own plugin, the warning and the confirmation it asks for showed while that cache was off. They now appear only while it is on. On LiteSpeed servers the note about LiteSpeed Cache no longer asks for the confirmation, since that cache only runs through its own plugin, which already keeps this one off.
* Fix: Two cache tests at the same time, by two administrators or by a save that tests the accelerator while someone presses the button, broke each other: the reasons went missing and the accelerator could refuse to switch on.
* Fix: With a separate cache for mobile, the server rules of the accelerator took any character between Opera and Mini or Mobi as a phone, where WordPress takes only a space. On nginx the Cache tab asks to paste the rules again.

= 3.7.0 =
* New: A new choice in "Let browsers keep the HTML for", called "Send no rules for HTML", and it is what a new install gets. With it DietPress says nothing at all about how long one of your pages may be kept. Sites that were on the old default, "Always revalidate", are moved to it once when they update, with a notice that explains it; sites that had chosen 5 minutes, an hour or a day keep what they chose, and those values still work the same. The lifetimes of images, styles, scripts and fonts are not affected by this in any way.
* Improved: However long you let browsers keep your pages, that is now decided in one place, when the page is built, instead of also being written into the .htaccess. The server rules could not know whether a visitor was logged in, whether the page was a cart or a checkout, or whether another plugin had already declared the page uncacheable, so on a page marked as not to be stored the response left with a second, contradictory instruction saying it could be kept for an hour. The setting itself works exactly as before.
* Improved: The compression rules no longer switch the compressor on for every response the server sends. The list of file types to compress is unchanged, so the same things are compressed, without the global filter that duplicated it and cost processor time on every dynamic page.
* Improved: The Keep-alive connections option is gone. The header it wrote is forbidden in HTTP/2, which is what almost every site is served over today, and on HTTP/1.1 it is the server, not the page, that decides whether the connection stays open. Nothing else changes for your site.
* Improved: The Vary header written for static files is merged instead of appended, so it is no longer sent twice on files the server also compressed, and it is written in the form every server understands.
* Improved: SiteGround Speed Optimizer is recognised by name, so when its cache is the one in charge the Cache tab says so instead of describing it as an unknown drop-in, and the browser caching options warn when the value chosen would stop it from storing your pages.
* Fix: With the default settings, every page left the site with a lifetime of zero seconds, which browsers read as "ask me again" and every cache in front of the site reads as "do not store this". On hosting that caches pages for you, such as SiteGround, that meant the cache never stored anything and every visit paid for a full page build: one store saw 2 cached responses out of 480,000 requests in a week. Nothing is sent now unless you pick a lifetime yourself.
* Fix: Feeds, robots.txt, ads.txt and any other plain text file were told they could be kept for a month, which is the lifetime of your images, because they had no rule of their own and inherited the default one. That inherited rule is gone: what is meant to be cached is now named one file type at a time, MP3, WAV and MOV among them, and anything not named is left alone. Sitemaps, XML and JSON are no longer sent an Expires date in the past either, which is what kept a CDN from storing them.
* Fix: A Cache-Control header set by another plugin, or by a PHP session, straight with header() instead of through the WordPress filter was replaced without trace. DietPress now looks at the headers already sent and leaves the response alone when one is there. The cart, the checkout and the account page of WooCommerce are never touched either, whatever their headers say, and a new dietpress_html_cache_control_skip filter marks any other page as personal.
* Fix: The page cache went on serving and storing pages when another page cache had taken charge through an advanced-cache.php drop-in, which is what a hosting plugin installs when its own file cache is switched on. The Cache tab said the module was blocked while the engine answered every visit, so the site had two page caches running and pages carried an X-DietPress-Cache header on a cache its owner believed was off. The engine now stops as soon as a foreign drop-in is in charge, and the module switches itself off on the next visit to the administration.

Thanks to @webvillalba for the help and for testing this release on real sites.

= 3.6.0 =
* New: Page cache accelerator. With it on, the web server hands out the stored copy of a page by itself, without starting PHP or WordPress, which is the fastest a page can be served; the page cache keeps working through PHP behind it for everything the server leaves alone, such as logged in visitors, URLs with a query string or a forced reload. On Apache it writes a block of rules to the .htaccess of the site, marked Page Cache by DietPress and placed right before the WordPress block; it needs mod_rewrite and mod_headers, and it serves the stored copies only through the address of their page, so the access rules of the site still apply to them. LiteSpeed reads the same block, and there too the test decides. On nginx, which does not read .htaccess, the Cache tab gives you the rules to paste into the server configuration, and they also close the cache folder, which nginx used to let anyone read by its address. Either way it only stays on when a test on the home page gets the page served by the server, with its headers and for the right scheme; if the test fails, it is switched off again and the tab says why. Stored pages still expire on time even when WordPress cron does not run, which on a site served almost entirely by the server is the usual case: each copy is linked under the name of every hour it is still valid in, and the server only looks for the current one; the night the server clock goes back, a copy can be served for up to an hour longer. The .htaccess of the cache folder is now rewritten whenever it says something other than what the settings need. On a server that does not hand PHP the environment variables set in .htaccess, which some hostings do not, the rules repeat the server clock in a request header instead, with a secret only the server knows, so the accelerator works there too. Phones get the copy built for them, with the separate mobile cache on, and those pages carry a Vary header so a CDN in front does not mix the two. Off by default; the site analyzer recommends it and the quick profiles switch it on. Because the server answers before any PHP runs, what a security plugin does in PHP, such as blocking an IP address or a bot, does not see those visits, while the rules it writes to .htaccess still apply. On LiteSpeed servers, the note of the Cache tab no longer says that the LiteSpeed Cache plugin is faster than this cache.
* New: The cleanup of expired pages can run every hour, twice a day or once a day, and at the hour of the site you choose, instead of always twice a day starting an hour after it was scheduled. The minute is spread per site, so sites on one server that pick the same hour do not all clean up at once. Sites that never change it keep the schedule they had.
* Improved: "Test the cache now" says whether the server or PHP served the home page, and names the exact reason when it was not served from the cache, such as a cookie, an excluded URL or a plugin that declares the page uncacheable. It also says when the answer did not come from WordPress at all, as with a static index.html in the root of the site, a CDN answering from its own cache or a password asked by the server, explains the usual cause when the site cannot reach its own address, and then tries again straight against the server. With the accelerator on, it tests the rules again on a site that moved, and switches the accelerator off when the server fails the home page where the accelerator serves it (with an error, with a copy missing its headers, or with something other than the page DietPress stored) while WordPress still builds it. When the accelerator is on but cannot run, it names the reason, and if the server is still answering from the cache by itself, it takes away what lets it do so.
* Improved: After applying a quick profile, the page says what happened to the page cache and to the accelerator. The message was already written, but the page reloaded before showing it.
* Fix: A plain reload rebuilt the page and stored it again, for every visitor who pressed reload, because browsers send max-age=0 on an ordinary reload and the cache took it for a forced one. Only a forced reload, which sends no-cache, rebuilds the page now; a request that asks for no-store is served from the cache as well.
* Fix: With the separate mobile cache off, a theme that sends different HTML to phones could have the version built for a phone stored and served to everybody. Astra, for one, puts its mobile header class on the page, so desktop visitors could get the mobile header. In that mode a page built for a phone is no longer stored; it is stored from desktop visits, and the Cache tab suggests the separate mobile cache when it happens.
* Fix: A page whose output buffer another plugin or the theme flushed or cleaned halfway through could be stored with only its end, and served that way to every visitor until it expired.
* Fix: A page sent with a Cache-Control header that forbids shared caches to keep it, no-store or private, as nocache_headers() sends, was stored and served to everybody. It is no longer stored, and "Test the cache now" names that reason.
* Fix: With canonical redirects switched off, a plain HTTP request naming a port in its Host header, such as example.com:443, was stored as the HTTPS copy of the page, with that port in its links wherever the theme prints the Host header, and visitors on HTTPS then got that copy. Requests whose port does not match the address of the site are left out of the cache now.
* Fix: Code that rewrites the requested address during the request, as some language plugins do, could make the cache store a page under the address of another one, so visitors of one language could get the page of another. A copy is now filed under the address that was asked for.
* Fix: In the store pages only mode of WooCommerce, a page that became the shop, the cart, the checkout, the terms or the coming soon page kept its public copy until it expired. Changing any of those pages now empties the cache.
* Fix: If storing a page stopped between the page and its compressed copy, the compressed copy of the previous version was left next to the new page and served to every browser that accepts gzip. The old compressed copy is now removed first.
* Fix: With deferred JavaScript on, a single visit claiming to be Internet Explorer 9 had its page stored without defer, and every visitor got that copy until it expired. The exception for that browser, unsupported for years, is gone.
* Fix: On a site that renames its login cookie in wp-config.php, with the LOGGED_IN_COOKIE constant, logged in visitors could be served the cached page anonymous visitors get. That cookie keeps them out of the cache now, the same as the standard one.
* Fix: A page served from the cache always told browsers to revalidate it, whatever "Let browsers keep the HTML for" said, while the same page built by WordPress followed that setting. Both follow it now. Sites that keep that setting at its default see no change.
* Fix: Deactivating the plugin from WP-CLI without a user left the scheduled cleanup of the page cache behind. It is removed now, whoever deactivates it.

= 3.5.6 =
* Fix: On a site served over HTTPS that also answers plain HTTP without redirecting, and whose server does not translate the X-Forwarded-Proto header for WordPress, a request could plant a broken copy of any cached page for visitors on HTTPS. The cache chose the HTTPS copy from the X-Forwarded-Proto header, which whoever sends the request controls, while WordPress builds the page from the scheme it detects itself, so a plain HTTP request claiming HTTPS was stored under the HTTPS name with its styles and scripts pointing to http://, which browsers block on an HTTPS page. The HTTPS copy now follows what WordPress detects, and a request is kept out of the cache altogether when its proxy headers (X-Forwarded-Proto, X-Forwarded-Ssl, CloudFront-Forwarded-Proto, CF-Visitor, X-Forwarded-Scheme or X-ARR-SSL) claim HTTPS that WordPress does not detect, or claim plain HTTP where WordPress only knows about HTTPS from the port number. That changes two things on a site behind a proxy or CDN. If it does not tell WordPress that it is served over HTTPS, visits through it are no longer cached until WordPress is told. If WordPress only learns about HTTPS later in the request, for example from code placed below the line of wp-config.php that loads WordPress, those HTTPS pages are not stored either. The Cache tab says so in both cases. Copies stored before updating are emptied as the update runs, when it runs through WordPress (from the dashboard, as an automatic update or with WP-CLI), and otherwise the first time an administrator opens the dashboard. Present since 3.5.0.
* Fix: With the page cache on, deactivating and reactivating the plugin from the Plugins screen left its cleanup unscheduled until the page cache was switched off and on again. The cleanup was only scheduled at the moment the cache was switched on, deactivating removed it while leaving the cache on, and nothing scheduled it again, so the Cache tab reported it as not scheduled and expired copies were never deleted from disk. Losing the scheduled task any other way had the same effect. It is now scheduled again on its own whenever it goes missing, to run an hour later, so a site already affected recovers after updating with nothing to do. Visitors were not served expired pages: the cache checks the age of a copy before serving it and rebuilds it when it is too old, so what piled up was disk space.
* Fix: The notes the Cache tab shows when the cleanup is not running read as if expired pages were still being served, and the one for a missing cleanup advised switching the cache off and back on, which empties it. They now say that visitors are not affected. The note for an overdue cleanup also explains that a page served from the cache does not run the scheduled tasks of WordPress, which a well cached site with little other traffic can notice in its scheduled posts, and the note for WordPress cron switched off mentions those posts too.
* Fix: The scheduled cleanup deleted the index.php file that keeps the cache folder from being listed, taking it for a cached page once it was older than the page lifetime. It now deletes cached pages only, and with the page cache on the file comes back after updating, at the latest the first time an administrator opens the dashboard. A cache folder deleted by hand or left out by a migration is also recreated with it now, and with the .htaccess that keeps it out of reach.
* Fix: With the page cache on, a site whose woocommerce_coming_soon option was set to yes cached nothing at all, with no header and no note to explain it, even when WooCommerce showed its pages to everybody: with WooCommerce deactivated, where that option is only a leftover, or in the store pages only mode, where every page outside the store stays public. The cache now asks it the way WooCommerce 9.8 or later does, so it keeps out the pages WooCommerce hides behind its coming soon screen and caches the rest; with an older WooCommerce, the store pages only mode still keeps the whole site out, as before.
* Fix: A PHP Error, such as a TypeError, thrown by another plugin while the page cache was storing a page, from a dietpress_cache_bypass filter for instance, ended that request with a fatal error right after the page was sent, so the tasks WordPress runs at the end of a request were skipped. The request now finishes normally, and that page is simply not stored.
* Fix: The scheduled cleanup could stop with a fatal error when a cached file disappeared while it walked the cache folder, which a purge or a page being stored at that same moment can cause, and that also stopped every other scheduled task due in the same run. The cleanup, the purge that runs when content changes and the Cache tab could also stop with one when a folder inside the cache could not be read. A file that is gone is now skipped, and so is a folder that cannot be read, which stays as it is until its permissions are put right.

= 3.5.5 =
* Fix: On a multisite network, the administrator of any single site could rewrite or delete the .htaccess and the wp-config.php at the root of the installation, the ones every site on the network is served from. Both were guarded by manage_options, which in a network is the capability the administrator of each site holds, while the settings that drive the rules are stored per site: saving them on one site rewrote the server rules for all of them, and switching the two master toggles off removed the block from the whole network. The upgrade routine reached the root wp-config.php the same way, on the first dashboard visit after an update, without anyone having to ask for it. Writing those files now takes manage_network_options, the capability a network administrator has, and a site administrator who moves one of the rule toggles is told why the server rules did not change instead of the save going quiet. Single site installations behave exactly as before, where manage_options is still what decides.

= 3.5.4 =
* New: Two filters for the page cache. `dietpress_cache_bypass_request` decides whether a request ignores the cache altogether, before anything is read from disk. The existing `dietpress_cache_bypass` could not do that, because it only decides whether a rendered page is stored. `dietpress_cache_bypass_accept` holds the media types that keep a request out of the cache, for plugins that answer a post URL with something other than its HTML.
* Improved: A request for the Markdown address of a post (/entry.md) no longer opens an output buffer and renders a page that was always going to be discarded for not being an HTML document. That address is now recognised as non-HTML up front, the way feeds and XML sitemaps already were.
* Fix: With the page cache on, a request asking for Markdown through `Accept: text/markdown` was answered with the cached HTML. The cache serves its copy on plugins_loaded and ends the request there, long before VigIA or Visibility negotiate the content on template_redirect, and the cache key did not include the Accept header, so both answers for that URL shared a single file. Those requests now bypass the cache, while the HTML copy of the same URL is still served to browsers.

= 3.5.3 =
* Fix: With the option to load WooCommerce assets only on store pages switched on, themes that ship their own WooCommerce stylesheets lost them everywhere else. WooCommerce invites a theme to replace those files while keeping the original handle names, and Astra, Storefront, OceanWP and Kadence all accept the invitation, so removing woocommerce-general on a page with no store content was removing theme CSS, not plugin CSS. Under Astra that is where every rule for the header cart lives, so the cart panel was left unstyled and permanently open on every page of the site. A handle is now only removed when the file behind it really belongs to WooCommerce.
* Fix: With the option to load WooCommerce assets only on store pages switched on, removed generic script handles such as select2 and js-cookie even when another plugin had registered them first. Those names are not reserved by WooCommerce, form and field plugins register them too, and whoever gets there first keeps the handle, so a plugin with nothing to do with the store lost its script on every page outside it. Only handles served from the WooCommerce directory are removed now.

= 3.5.2 =
* Improved: Checked against WordPress 7.1 and marked compatible with it. Everything DietPress switches off still switches off there, and the one 7.1 change that touches a filter it uses only alters plugins that force comment notifications on, not ones like this that turn them off.
* Fix: With emojis switched off, the resource hints were adding back the very DNS prefetch to s.w.org that switching emojis off had just removed, so the browser still resolved a domain nothing on the page would ever ask for, and the option contradicted its own description. The same happened to secure.gravatar.com with avatars switched off. Each of the two is now left out when the option that gives it a purpose is off, and either can still be put back with the dietpress_dns_prefetch_domains filter.
* Fix: Stripping version strings from asset addresses never reached script modules, so the ones WordPress itself loads, the Interactivity API among them, kept their ?ver= while every style and script around them lost it. The option was listening for a filter name WordPress does not have, so that part of it had done nothing since the day it was written. It now uses the filter WordPress really provides, which covers the import map, the module tags and their preload links in one go. Assets belonging to plugins keep their version, exactly as before.

= 3.5.1 =
* Improved: The Cache tab now says out loud when its cleanup is not running. The next cleanup figure tells a run that is due apart from one that is overdue and marks the overdue one, and a note underneath names the likely cause: WordPress cron switched off with no real cron behind it, a site too quiet for WordPress to fire its scheduled tasks at all, or no cleanup scheduled, which the tab itself can put right. While the schedule is being met it says nothing.
* Fix: Pages whose address is not plain ASCII shared a single cached copy. The request path was cleaned with a function that deletes percent encoded characters, and that is exactly how a browser sends every byte of an accented or non Latin permalink, so /café/ and /cafá/ were stored as the same page, and a site whose slugs are written in Cyrillic, Greek, Arabic or CJK collapsed nearly every address onto one entry, the home page included. Languages WordPress transliterates into ASCII by itself, Spanish and French among them, were only affected where a slug had been edited by hand. The cache is emptied once when this version is installed, because a copy stored under the old rules can hold a different page altogether and there is no way to tell which from the file.
* Fix: A URL exclusion pattern containing an accent or any non Latin character never matched anything, for the same reason: those characters were stripped when the pattern was saved. Both spellings work now and mean the same thing, the one the address bar shows and the one the clipboard usually holds.
* Fix: Renaming or deleting a category or a tag left its old archive cached and still being served. It is the case renaming a post already handled: once the slug has changed, nothing can name the address the old page lived at, and nothing would ever rebuild it either.
* Fix: Editing what a widget says purged nothing, so every page showing it kept the old text until it expired. Only adding, moving or removing a widget purged. Block based widgets are covered too, since they all share one option.
* Fix: The browser caching rules handed HTML pages the lifetime chosen for media. The rule that covers every file type without one of its own covers the page itself too, and there was no rule for HTML. On an anonymous visit the Cache-Control header the plugin sends overrode it, which is why it went unnoticed; on a page viewed while logged in that header is deliberately not sent, and there a page could sit in the browser for a month. HTML now follows the lifetime chosen for it in the Cache tab.
* Fix: The query parameters that may never be ignored treated filter_ as a whole name rather than a prefix, so a WooCommerce layered navigation parameter such as filter_color could be added to the ignore list, and a filtered shop page was then answered with the unfiltered one.
* Fix: The next cleanup figure on the Cache tab could not tell a late cleanup from a coming one. It printed a bare time difference, and the WordPress function behind it carries no direction, so a cleanup that had run two days late and one due in two days both read as 2 days. The one figure that could have revealed a cron nobody was running was the one hiding it.

= 3.5.0 =
* New: Page cache. DietPress can now store a static copy of each page on disk and serve it to anonymous visitors without building the page again, from its own Cache tab in the DietPress settings, next to the diet levels, which also gathers the browser caching rules that used to live under Strict. It is off by default, it installs no drop-in file and it never writes to wp-config.php, so switching it off leaves the site exactly as it was. Logged in visitors, anyone carrying a cart, a password protected post and a comment awaiting moderation always get the live page. Every response carries an X-DietPress-Cache header, and every stored page a footprint comment, so a hit and a miss can be told apart at a glance.
* New: Browser caching is now configurable rather than fixed: how long browsers keep your media, your styles and scripts, your fonts and the HTML itself, each on its own, plus a switch for the ETag header. Browser caching and compression also get a master switch each, so you can run one without the other; a site updating from 3.4.x keeps whatever its single switch said. The Cache-Control headers are built from those same lifetimes instead of a hardcoded year, which is a fix in itself: they used to contradict the Expires rules, and browsers obey Cache-Control when the two disagree. Only styles, scripts and fonts are marked immutable now, because they carry a version in their URL; an image keeps its URL when you replace it. The HTML lifetime is sent as an HTTP header instead of an .htaccess rule, which is a fix too: the old rule only matched files whose name ends in .html, so it never applied to a WordPress permalink at all.
* New: The Cache tab reports what the cache is really doing instead of just offering switches: how many pages and how much disk it holds, when the cleanup last ran and when it runs next, and a Test the cache now button that asks the site for its own home page, as an anonymous visitor would, and says whether it was served from disk, rebuilt, or skipped. The same status block appears on the Scale tab next to the savings, the site analyzer gained a Cache section that covers the engine, the gzip copy and the browser caching rules, and the quick profiles switch the cache on with a lifetime that suits each one, six hours for a store and twelve for the rest. Purging accepts a title as you type and fills in the right URL for you. With WP_DEBUG on, a page that is not being stored names the exact reason in an HTML comment at the end of its source.
* New: Invalidation happens on its own for the things that change a page. Publishing, editing, deleting or renaming a post purges it along with the front page, the blog page, its archives and its author page, and renaming a slug also purges the address it used to live at. Approving, editing or deleting a comment purges its post. Changing the theme, the menus, the widgets, the permalinks or the front page settings, and activating or updating any plugin, empty the cache completely. There is also a purge button, a field to purge one URL, the dietpress_cache_purge_all action and the dietpress_purge_page_cache() function.
* New: The cache refuses to run beside another one instead of fighting it. With W3 Total Cache, WP Super Cache, LiteSpeed Cache, WP Fastest Cache, Cache Enabler, Surge, WP Rocket or any of about thirty similar plugins active, the toggle is disabled and says which one is in the way, and if one of them is activated later DietPress switches its own cache off and tells you. On hosting that already serves a page cache, such as Kinsta, WP Engine, SpinupWP or Cloudways, it explains the risk and asks for an explicit confirmation. On LiteSpeed servers it points at the LiteSpeed Cache plugin, which caches at server level. Multisite is not supported yet and says so rather than misbehaving.
* Fix: Activating a conflicting cache plugin from WP-CLI, or from any code that activates plugins outside the dashboard, did not switch the page cache off. The check only listened while an admin screen was loading, so a host control panel or a staging script could leave two page caches running at once, which is the exact situation the check exists to prevent.
* Fix: An option held back by another one lost its saved value on the next save. The switches that depend on a master switch, the five RSS feed ones and the compression ones among them, were drawn from whether they apply right now rather than from what you had chosen, so while the master was off they rendered as off, and saving wrote that over your real preference. Turning the master back on then restored nothing. A card now always shows what is stored, and the note underneath is what says whether it can do anything yet.

= 3.4.1 =
* Improved: The settings page code is no longer loaded on frontend requests. Around 90 KB of PHP that only the admin ever needs was being read and parsed on every visit to the site.
* Improved: The saved settings are no longer completed with the built-in defaults on every single request. That work, and the database write it could trigger in the middle of an anonymous visit, now happens only after a plugin update, which is the only moment it can change anything.
* Fix: Translations were loaded before the init action, which printed a "Translation loading for the wpo-tweaks domain was triggered too early" notice on sites that have DietPress translated and WP_DEBUG on. Deciding whether an option was locked went through the sentence that explains the lock, so merely reading a setting asked for a translation while the plugin was still loading.
* Fix: The WooCommerce selective loading module left two stylesheets behind on pages with no store content. On WordPress 7.0, wc-blocks-style survived because block styles are now enqueued while the page renders and only afterwards moved up into the head, past the point where the module was looking. And with any block theme, woocommerce-blocktheme was never on the list to begin with, so it loaded everywhere. Every other WooCommerce file was already being removed.

= 3.4.0 =
* New: Selective loading covers five more plugins that load their assets on every page. Slider Revolution, around 660 KB of JavaScript per page, by turning its own Include libraries globally setting off for each visit and letting Slider Revolution decide, so its shortcodes, its widget and its own page list keep working (DietPress adds the cases its check misses, such as a shortcode inside a widget). TablePress and Smash Balloon, by turning on the conditional loading each one already ships with (nothing is dequeued, and no table or feed can end up unstyled). Formidable Forms, whose stylesheet is removed while its own footer fallback is put back in play. And Everest Forms, including the Dashicons file it forces on every visitor. All five are off by default, the site analyzer suggests each one when its plugin is active, and the Maximum cleanup profile enables them.
* New: Options that cannot do what they promise now say so in their own card, and the ones that would contradict another option or break another plugin cannot be switched on at all. "Disable WordPress XML sitemap" becomes unavailable while a plugin that builds on the native sitemap is active (Visibility, or any plugin that says so through the new dietpress_native_sitemap_in_use filter), so nobody can pull the sitemap from under it by mistake. A stored value is never lost: it stays saved, it simply does not apply while the lock lasts, and the site analyzer stops suggesting anything locked.
* New: The cards for "Disable Posts content type" and "Disable Pages content type" now count what you have and warn before you switch them on, for example that your site has 42 pages that would disappear from the admin, the frontend and your menus. Nothing is ever deleted, and the warning travels with the analyzer recommendations too.
* Improved: Selective loading no longer removes assets on pages it cannot read. A page built with Elementor keeps its content in the database, out of reach of the content scan, and an Elementor Theme Builder template can inject a header, a footer or a popup into any request. Those pages now keep the assets of every detection-based module, which closes the known gap of the Contact Form 7 module with forms placed inside a builder.
* Improved: Every selective loading module that removes handles now exposes the same three filters (dietpress_selective_{module}_has_content, _styles and _scripts), where before only WooCommerce had its handle lists filterable; the modules that flip a native setting expose their own escape filter instead. The filters published in 3.3.0 keep working.
* Improved: The developer filters from the 2.x days (the ayudawp_wpotweaks_* prefix, renamed in 3.0.0) now report their deprecation through the standard WordPress notice, only when a site still has a callback hooked to one of them and only with WP_DEBUG on. They keep working, and are scheduled for removal in 4.0.
* Improved: "Disable native lazy loading" and "Disable fetchpriority attribute" are no longer offered while "Enhance image loading attributes" is on. They only make sense when another plugin manages image loading, and with the DietPress option on they changed nothing, because DietPress sets those attributes itself right after WordPress. Turning off the image enhancements makes both available again, without reloading the page. If you had one of them on together with the image enhancements, the attributes were already being set by DietPress; now WordPress keeps setting its own too, which is the behavior the option descriptions always described.
* Improved: The Scale tab is coherent with all of the above. The savings counter no longer counts an option that cannot apply, the analyzer does not suggest one, and applying a quick profile no longer stores one: it keeps whatever the site had and says which option it left alone and why. The Maximum cleanup profile also stops switching on "Disable native lazy loading" and "Disable fetchpriority attribute", which it combined with the image enhancements it keeps on, so they could never do anything.
* Improved: The options that another option already covers now say so instead of looking active for no reason: the five granular RSS feed toggles while "Disable ALL RSS feeds" is on, the six .htaccess sub-options while the master switch is off, and the Customizer widgets one while the whole Customizer is disabled. They stay usable so a site can be configured in any order.
* Improved: The option cards of every section are now laid out by how much text each one carries, so the two-column grid forms even rows instead of a ragged, masonry-looking wall. The order follows the texts themselves, so it keeps working after an edit or a translation, and the switch that governs a group (the .htaccess master, the nuclear RSS option) still comes first. Card notes sit at the bottom, so the ones sharing a row line up.
* Fix: The site analyzer recommendation to disable the WordPress sitemap checked a constant belonging to no real plugin, so it only ever detected Yoast SEO, Rank Math and All in One SEO. It now also detects SEOPress, The SEO Framework and Slim SEO.
* Fix: Internal cleanup with no change in behavior: an unused rendering method, two deletions of a transient that is never written, and a duplicated cleanup of a 2.x option on activation.

= 3.3.1 =
* Fix: "Disable media library image editor" no longer removes the Imagick and GD image editors site-wide. Doing so also stopped WordPress from creating thumbnails on upload and from regenerating them with WP-CLI or a regeneration plugin. The option now disables only the editor itself: its entry points, its AJAX endpoints and its script.
* Fix: "Enhance image loading attributes" no longer produces an invalid image tag when the original tag is self-closing. The closing slash was left in the middle of the tag, before the attributes added by the plugin.
* Fix: Featured images no longer come out with fetchpriority="high" and loading="lazy" at the same time. They travel through two filters, and the second one no longer treats an image already marked as high priority as a candidate for lazy loading, which worked against the very LCP the option aims to improve.
* Fix: Deferred scripts no longer get a second defer attribute. WordPress 6.3 and later defers some scripts on its own, and adding another one made the tag invalid. WooCommerce was the most visible case.
* Fix: Removed a dead loop in the daily transient cleanup. It looked up three names as transients when they are an object cache key and a prefix, so it never matched anything. The cleanup itself is unchanged.

= 3.3.0 =
* New: Google Fonts local hosting. DietPress can now download the Google Fonts your theme enqueues and serve them from your own server: no more visitor connections to Google (faster font delivery and GDPR-friendly), with a silent fallback to the Google CDN if any download fails, and automatic cleanup on theme switch or when turned off. Off by default; find it in Light > Performance next to the display=swap option, which keeps working as fallback.
* New: Selective third-party loading, a new section in the Strict tab with three opt-in modules that stop loading assets where they are not used: WooCommerce styles and scripts outside the store (the cart fragments script is kept when a mini-cart widget is detected), Contact Form 7 assets on pages without a form, and the block library stylesheets on pages whose content uses no blocks (skipped on block themes, and Global Styles are never touched). Each module only acts when its target plugin is present, the site analyzer suggests them when they apply, the Maximum cleanup profile enables them, and escape filters cover custom setups.

= 3.2.1 =
* Improved: hardened path handling in the automatic image dimensions feature so file lookups stay within the WordPress and uploads directories, consistent with the SVG dimension reader.
* Improved: the resource hints `dns-prefetch` list no longer duplicates the domains already covered by `preconnect` (Google Fonts and Google Analytics), which already complete the full connection setup for those origins.
* Improved: the resource hints `dns-prefetch` list no longer includes `gravatar.com` and the numbered `0/1/2.gravatar.com` subdomains; WordPress core's `get_avatar_url()` only generates `secure.gravatar.com` today, so those entries prefetched DNS for hosts no avatar ever loads from.
* Fix: prevent a fatal error (ArgumentCountError on PHP 8+) when a theme or page builder fires the `wp_get_attachment_image_attributes` filter with fewer arguments than WordPress core passes (seen with the Hub/LiquidThemes builder while saving posts). The image loading optimization now treats the attachment and size parameters as optional.

= 3.2.0 =
* New: New "Emails" tab to control the automatic emails WordPress sends on its own: update results (core, plugins, themes), comment moderation and author notices, and new user, password and email-change notices. Every option is off by default, with a risk note where it matters.
* Improved: The "admin email verification prompt" and "post by email" options moved from the Light tab to the new Emails tab; their saved settings carry over unchanged.

= 3.1.0 =
* Improved: Performance – JavaScript defer now skips a built-in list of third-party scripts that must run on load (reCAPTCHA, Typekit, HubSpot forms, payment SDKs and more), matched by URL, and extendable with the new `dietpress_skip_defer_script_patterns` filter.
* Improved: Performance – image optimization now leaves images already handled by another lazy-load solution untouched, honoring the `skip-lazy`/`data-skip-lazy` markers and the markup of common sliders (LayerSlider, Soliloquy), the Contact Form 7 captcha and the WooCommerce placeholder.
* Improved: Performance – image optimization is skipped inside page builder editors and previews (Beaver Builder, Divi, Oxygen and WordPress previews) so layouts are not altered while editing.
* Improved: Performance – site logo detection for image priority is now filterable via the new `dietpress_logo_class_patterns` filter.
* Improved: Performance – missing dimensions are now added to SVG images too (read from their width/height or viewBox), reducing layout shift.
* Improved: Performance – the Scale tab savings counter now also accounts for the performance optimizations (defer, critical CSS, image loading, resource hints, feeds, transient and query optimization, and .htaccess rules).
* Improved: Performance – the .htaccess rules now declare the AVIF MIME type so AVIF images are served correctly on older Apache servers, and set the document charset from your site settings.
* Improved: Security – the .htaccess performance rules no longer keep a copy of your site .htaccess inside the plugin folder. They are written non-destructively (only their own marked block is added or removed), so that copy was never used to restore anything; any backup left by earlier versions is removed automatically on update.
* Fix: the per-tab "Restore defaults" button now also resets the performance options shown on that tab, which it previously skipped.
* Fix: settings export files now use the "dietpress" identifier; imports still accept files exported by earlier versions.

= 3.0.1 =
* Fix: removed the "REST API access" control from the Strict tab. Restricting the REST API is a security feature, not a performance one, and it overlapped with dedicated security plugins, with which it could also clash on the same `rest_authentication_errors` filter. REST API access now follows default WordPress behavior; manage it from your security plugin instead, such as our free Vigilant. If you had set it to "Require authentication" or "Disable", that restriction no longer applies after updating, and DietPress shows a one-time notice pointing you to Vigilant.

= 3.0.0 =
* New: the plugin is now DietPress (formerly "Zero Config Performance Optimization"), fully configurable from a new top-level "DietPress" admin menu with its own settings page.
* New: a complete, risk-based set of options to put WordPress on a diet (Light, Moderate, Strict and Widgets), covering emojis, RSD/WLW, shortlinks, self-pingbacks, oEmbed, jQuery Migrate, Dashicons, REST API control, granular RSS feeds, comments, Heartbeat, revisions, autosave, content types, and dashboard/sidebar/block/Customizer widgets. Security-related toggles (XML-RPC, pingbacks, login errors, Application Passwords, version hiding) are intentionally not included: they belong in a security plugin, like our free Vigilant, and DietPress tells you once if you had any of them enabled.
* New: Scale tab with a savings indicator, quick profiles (Personal Blog, WooCommerce, Landing Page, Maximum Cleanup) and a site analyzer with recommendations.
* New: import and export your configuration as a JSON file.
* Improved: every performance optimization from the previous "Zero Config" version is now an individual setting you can fine-tune (JavaScript defer, Critical CSS, image loading attributes, image dimensions, resource hints, asset and logo preloading, RSS feed optimization, .htaccess browser caching/GZIP/Brotli/headers, transient cleanup and query optimizations). They all stay ON by default, so updating sites keep their current behavior.
* Improved: the Critical CSS deferral of non-critical stylesheets (the part that can cause a flash of unstyled content) is now a separate, opt-in "experimental" toggle, while the safe inline critical CSS stays on by default.
* Improved: the .htaccess server rules are now applied when you save settings, with a master switch plus per-feature toggles (browser caching, GZIP, Brotli, cache headers, CORS for fonts, keep-alive), and are removed cleanly on deactivation. The block is now labeled "# BEGIN DietPress"; the old "Zero Config Performance" block is replaced automatically.
* Improved: developer filters renamed to the `dietpress_` prefix (`dietpress_critical_css`, `dietpress_critical_css_handles`, `dietpress_skip_defer_script_handles`, `dietpress_skip_defer_style_handles`, `dietpress_preconnect_hints`, `dietpress_dns_prefetch_domains`, `dietpress_critical_fonts`). The former `ayudawp_wpotweaks_*` filters keep working through a compatibility bridge, but are deprecated: please update your snippets to the new names.
* Fix: the retired standalone DietPress ("core-diet") plugin is detected and deactivated automatically, preventing fatal conflicts while both are installed; its settings carry over.

= 2.3.2 =
* **IMPROVED: new `ayudawp_wpotweaks_skip_defer_script_handles` filter** so plugins can opt their own JavaScript out of the defer pass when their scripts must run before DOMContentLoaded
* **IMPROVED: new `ayudawp_wpotweaks_skip_defer_style_handles` filter** so plugins can opt their own stylesheets out of the `rel="preload"` defer when their UI would render visually broken until the deferred CSS finishes loading
* **FIX: plugin asset cache-busting was being neutralized** — the previous combination of stripping `?ver=` from every URL plus the `Cache-Control: immutable, max-age=31536000` header in `.htaccess` froze plugin assets in browser caches for a year. Any plugin update silently failed to reach existing visitors. URLs under `/wp-content/plugins/` now keep their `?ver=` query string so the cache-busting works as intended; WordPress core, `wp-includes/` and theme assets still get stripped. Filterable with `ayudawp_wpotweaks_preserve_plugin_version`

= 2.3.1 =
* **FIX: JavaScript defer breaking scripts with inline "after" code** - Fixed "wp is not defined" errors on scripts using `wp_add_inline_script()` with 'after' position (wp-i18n) and scripts registered with `wp_set_script_translations()` (Contact Form 7 translations, etc.). The defer filter now skips scripts with attached inline code to prevent execution order issues
* **IMPROVED: Changelog history moved to separate file** - Full changelog history now lives in [changelog.txt](https://plugins.svn.wordpress.org/wpo-tweaks/trunk/changelog.txt) following WordPress.org best practices. The readme.txt now only contains the latest versions for lighter maintenance and cleaner translations

= 2.3.0 =
* **MAJOR: Image module refactored to complement WordPress core** - Rebuilt to work as a safety net instead of duplicating core. WordPress 5.5+/6.1+/6.3+ handles lazy loading, decoding, and fetchpriority for images in its standard pipeline, but images injected by themes, page builders, widgets or custom code may bypass it. The module now checks if each attribute is already present before adding it, so it only fills the gaps core didn't reach
* **NEW: fetchpriority="low" for non-critical images** - Deprioritizes below-the-fold images so the browser allocates bandwidth to critical resources first. WordPress core does NOT do this
* **FIX: Gravatar avatars broken by query string removal** - Previous version stripped all query parameters from Gravatar URLs, including functional ones (size, default image, rating). Function removed entirely since Gravatar params are not cache-busting
* **FIX: Critical CSS broken by esc_html()** - CSS selectors using `>` (child combinator) and other special characters were escaped to HTML entities, breaking the CSS. Now uses wp_strip_all_tags() only
* **FIX: Deprecated JSON/REST API filters removed** - `json_enabled` and `json_jsonp_enabled` were legacy filters from the old WP-API plugin (pre WP 4.7) that could interfere with Gutenberg, WooCommerce and other plugins depending on the REST API
* **FIX: CusRev and review plugins compatibility** - Comments query optimization now only applies to standard comments, not custom comment types used by review plugins (CusRev, WooCommerce Reviews, etc.)
* **FIX: Ghost plugin entries cleanup** - Automatically removes orphaned entries in active_plugins from renamed or incorrectly registered plugin paths on activation
* IMPROVED: Removed dns-prefetch hint for s.w.org (only used by emoji scripts already disabled by the plugin)
* IMPROVED: Reduced code footprint in image optimization module, cleaner logic with no duplication
* Tested up to WordPress 7.0

= 2.2.1 =
* **FIX: Critical wp-config.php compatibility issue** - Plugin no longer modifies wp-config.php, fixing 500 errors on activation caused by conflicts with existing configurations
* **NEW: Safe trash cleanup via cron** - Trash retention (7 days) now handled via scheduled task instead of modifying wp-config.php
* **NEW: Legacy wp-config.php cleanup** - Automatically removes modifications added by previous versions on upgrade
* IMPROVED: Safer activation process with no risk of breaking site configuration
* REMOVED: wp-config.php backup/restore system (no longer needed)

= 2.2.0 =
* **REBRANDING: Plugin renamed to Zero Config Performance Optimization**
* **NEW: Brotli compression support** - Modern compression for servers that support it
* **NEW: Keep-Alive connections** - Enables connection reuse for faster requests
* **NEW: Vary Accept-Encoding header** - Better CDN and proxy caching
* **NEW: Cache-Control immutable flag** - Prevents unnecessary revalidation
* **NEW: CORS headers for fonts** - Full CDN compatibility
* **NEW: Extended MIME types** - Video, audio, manifest files properly cached
* **NEW: Automatic logo preload** - Site logo preloaded with high priority for LCP
* **NEW: fetchpriority attribute** - First image gets `fetchpriority="high"` for faster LCP
* **FIX: Clean .htaccess removal** - Plugin markers now fully removed on deactivation
* **FIX: Legacy marker cleanup** - Old "WPO Tweaks" markers automatically cleaned
* IMPROVED: Better first image detection for LCP optimization
* IMPROVED: More comprehensive browser caching rules
* IMPROVED: Updated admin notice with new branding
* REMOVED: Security tweaks module (use dedicated security plugins instead)

= 2.1.3 =
* **FIX: Divi 5 Visual Builder compatibility**
* JavaScript defer is now disabled when Divi Visual Builder is active
* Fixes issue where Divi 5 builder would get stuck loading infinitely
* Frontend performance remains optimized (defer only disabled during editing)

= 2.1.2 =
* Tested up to WordPress 6.9

= 2.1.1 =
* **CRITICAL FIX: Admin bar display for Editor and Author roles**
* Fixed bug where users with Editor and Author roles couldn't see the admin bar correctly
* Dashicons now only removed for non-logged users (ALL logged-in users, regardless of role, can see admin bar)
* Improved logic in Script Optimization module
* Improved logic in Critical CSS module
* Better compatibility with all WordPress user roles
* Fixed: Admin notice footer text now fully translatable

= 2.1.0 =
* **NEW MAJOR REFACTORING: Modular architecture for better maintainability**
* NEW: **Missing Image Dimensions** - Automatically adds width/height attributes to img and picture elements for better Cumulative Layout Shift (CLS) scores
* NEW: **Picture Element Support** - First plugin to automatically add dimensions to picture elements (more comprehensive than most optimization plugins)
* NEW: **Enhanced File Management System** - Automatic backup and restoration of wp-config.php and .htaccess files
* NEW: **Direct wp-config.php Management** - Guaranteed trash retention settings by modifying wp-config.php directly
* NEW: **Admin Activation Notice** - Informative welcome message showing all applied optimizations
* IMPROVED: Code completely refactored into modular architecture with separated components
* IMPROVED: Better performance with optimized module loading system
* IMPROVED: Enhanced debugging capabilities with isolated modules
* IMPROVED: Conflict resolution system for existing configurations
* IMPROVED: Complete cleanup system on plugin deactivation
* IMPROVED: Enhanced Gravatar lazy loading support
* IMPROVED: All filter names updated to `ayudawp_wpotweaks_*` for better specificity
* IMPROVED: Each optimization now has its own dedicated module for easier maintenance

= 2.0.3 =
* Removed: Admin Footer Credits (absolutely not necessary)
* Removed: Deactivation of WordPress file editor (better handle with a security plugin)
* Fixed: Better selection of dashboard widgets to remove (maintaining security related)

= 2.0.2 =
* Fixed: Pagination issues with Twenty Twenty and other themes
* Improved: Query optimization logic to preserve pagination functionality
* Enhanced: Better compatibility with various theme pagination systems
* Added: Better error handling for transient cleanup
* Improved: Memory usage optimization

= 2.0.1 =
* Fixed bug with WooCommerce not showing products in taxonomy and archive pages

= 2.0.0 =
* **NEW MAJOR VERSION with advanced optimizations**
* NEW: **Automatic Critical CSS**: Above-the-fold critical CSS generation and injection
* NEW: **Deferred CSS Loading**: Non-critical CSS loads asynchronously with noscript fallback
* NEW: **Automatic Preconnect**: Automatic hints for Google Fonts, Analytics and other critical resources
* NEW: **Smart DNS Prefetch**: DNS preloading for common external resources
* NEW: **Native Lazy Loading**: Automatic lazy loading for all images with decoding=async
* NEW: **Database Optimizations**: Automatic cleanup of expired transients and query optimization
* NEW: **Resource Preloading**: Automatic preload for theme CSS and critical fonts
* NEW: **Smart jQuery Migrate Removal**: Only removes when not needed
* NEW: **Dashboard Cleanup**: Removes unnecessary widgets from administration area
* NEW: **Revisions Management**: Limits automatic revisions to 3 and reduces trash retention to 7 days
* NEW: **Google Fonts Optimization**: Automatically adds display=swap
* IMPROVED: **Multiple Developer Filters**: Allows advanced customization via hooks
* IMPROVED: **Smart Cache**: Enhanced cache system for critical CSS and other resources
* IMPROVED: **Scheduled Tasks**: Automatic daily cleanup of expired transients
* IMPROVED: **Improved Architecture**: Code restructured following WordPress best practices
* IMPROVED: **Enhanced Security**: All functions carry ayudawp_ prefix following standards
* IMPROVED: **Translation Ready**: Updated text domain and strings prepared for i18n
* IMPROVED: **Better Performance**: Significant optimizations in loading time and server resources
* IMPROVED: **Better Metrics**: Specific optimizations for Core Web Vitals and measurement tools

= 1.0.7 =
* Tested up to WordPress 6.7.1

= 1.0.6 =
* Tested up to WordPress 6.6.1

= 1.0.5 =
* Tested up to WordPress 6.5.2
* Added support for PHP 8.2 (props @dbase66)

= 1.0.4 =
* Tested up to WordPress 6.4

= 1.0.3 =
* Tested up to WordPress 6.2

= 1.0.2 =
* Tested up to WordPress 6.1
* Updated requirements for WP and PHP

= 1.0.1 =
* Tested up to WordPress 6.0.2

= 1.0 =
* Tested up to WordPress 6.0
* Yes! It was time to change to version 1.x

= 0.9.31 =
* Change PageSpeed URL

= 0.9.30 =
* Tested up to WordPress 5.9

= 0.9.29 =
* Tested up to WordPress 5.8

= 0.9.28 =
* Tested up to WordPress 5.6

= 0.9.26 =
* Removed jQuery Migrate option because it's not needed since WordPress 5.5

= 0.9.25 =
* Tested up to WordPress 5.5

= 0.9.24 =
* Regression to previous method for defer parsing of JavaScript due to support issues with Divi theme

= 0.9.23 =
* Tested up to WordPress 5.4.1

= 0.9.22 =
* New method for defer parsing of JavaScript. Especially useful with YouTube iframes and other external video sources

= 0.9.21 =
* Tested up to WordPress 5.3.2

= 0.9.20 =
* Changes in jQuery Migrate code to resolve support of latest Elementor version

= 0.9.19 =
* Tested up to WordPress 5.3

= 0.9.18 =
* Tested up to WordPress 5.2.2

= 0.9.17 =
* Tested up to WordPress 5.2

= 0.9.16 =
* Tested up to WordPress 5.1

= 0.9.15 =
* Added conditionals to deflate lines in .htaccess file to prevent 500 error on some hostings (Props to frayca)

= 0.9.14 =
* Added tested up to WordPress 5.0 tag

= 0.9.13 =
* Tested up to WordPress 4.9.8

= 0.9.12 =
* Added functions to disable internal self pingbacks

= 0.9.11 =
* Added line to check if "expires" module is active to prevent 500 error on some servers where module is not active

= 0.9.10 =
* Tested up to WordPress 4.9.6

= 0.9.9 =
* Added browser cache expiration rules to main WordPress .htaccess file
* Added GZIP compression rules to main WordPress .htaccess file
* This is the first version with version tags
* Props to @carloslongarela for .htaccess improvements

= 0.9.8 =
* Tested up to WordPress 4.9.5

= 0.9.7 =
* Added exception in Dashicons removal to show them in Customizer

= 0.9.6 =
* Changed method for Heartbeat API - now controls interval to 60 seconds instead of default 15 seconds
* Added credits to admin footer
* Plugin tested up to WordPress 4.9 RC

= 0.9.5 =
* Added link to WebPageTest in readme.txt to measure results
* Changed to `script_loader_tag` filter method for Defer Parsing of JavaScript

= 0.9.4 =
* Changed method for Defer Parsing of JavaScript to resolve AMP issues with Google CDN
* Changed donation URL

= 0.9.3 =
* Changed minimum WP version from 4.0 to 4.1
* Added filter to remove capital_p_dangit filter
* Added functions to disable PDF thumbnails previews
* Added multiple actions to clean header (props @carloslongarela)
* Better code standards and functions ordering
* Changes in readme.txt

= 0.9.2 =
* Added multiple actions to clean WordPress header
* Added function to remove jquery_migrate

= 0.9.1 =
* Fixed Text Domain to be ready for translation

= 0.9 =
* Initial version
