=== LNDLE Speed ===
Contributors: lndle
Tags: cache, performance, page cache, lazy load, minify
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 0.9.0
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Page cache, cache preload, lazy load, CSS minification and WordPress cleanup, with a setup wizard that checks your server first.

== Description ==

LNDLE Speed is a caching and front-end optimization plugin for WordPress sites running on Apache-compatible servers. It stores finished HTML pages as static files, serves them through `.htaccess` rewrite rules and applies a small set of low-risk optimizations to the HTML when a page is cached.

After activation, a setup wizard inspects the site and proposes settings. You decide which of them are applied, and every setting can be changed later.

= Features =

* **Page cache** – Pages are saved as static HTML files in `wp-content/cache/lndle-speed/` and served directly by Apache or LiteSpeed. On other web servers the cache is served through PHP by the `advanced-cache.php` drop-in.
* **Automatic cache clearing** – When a post, page, comment or term changes, the affected pages and their archives are cleared. Changes to themes, menus, widgets, plugins and Elementor templates clear the whole cache. Cached pages also expire after a configurable lifetime.
* **Cache preload** – After the cache has been cleared, the plugin reads your XML sitemap and requests the pages one after another via WP-Cron, in short time-limited runs. If no sitemap is found, it uses the most recently modified published content.
* **Browser cache rules** – Optional Expires and Deflate (GZIP) rules written to `.htaccess`.
* **Lazy load for images and iframes** – Adds the native `loading="lazy"` attribute. The first images on a page (two by default) are left out so that the logo and hero image load immediately. Exclusions by file name or class are possible.
* **Lazy load for video posters** – Preview images of videos load shortly before the video scrolls into view, and the video file itself only loads on playback. Videos with autoplay are not changed.
* **Missing image dimensions** – Adds `width` and `height` to local images that have neither, to avoid layout shifts.
* **CSS minification** – Minifies local stylesheets that are not minified yet. The original files are not changed.
* **Google Fonts display swap** – Adds `display=swap` to Google Fonts stylesheet URLs that are already on the page.
* **Preconnect hints** – Adds `preconnect` links for the origins you enter.
* **WordPress cleanup** – Disable the emoji script and the embed script, remove the generator tag, RSD, wlwmanifest and shortlink from the head, remove Dashicons for visitors who are not logged in, remove jQuery Migrate on the front end, and reduce or disable the Heartbeat API.
* **Manual database cleanup** – Removes revisions, auto-drafts, trashed posts, spam and trashed comments and expired transients, then optimizes the tables. It runs only when you click the button.
* **Setup wizard** – Detects the web server, Cloudflare, an existing server-side page cache, other caching and optimization plugins, plugins that already lazy-load images, Elementor, WooCommerce, cookie banner plugins, directory protection and the WP-Cron configuration, and recommends settings based on what it finds.
* **Tools** – Admin bar entries to clear the whole cache or the current page, and a "View as visitor" link that shows the optimized page while you are logged in.

= What is not cached =

Logged-in users, requests with query strings (common tracking parameters such as `utm_*`, `gclid` and `fbclid` are ignored), password-protected posts, search results, 404 pages, feeds, REST requests, and visitors with a comment-author or WooCommerce cart cookie. The WooCommerce cart, checkout and account pages are always excluded. You can exclude further paths in the settings.

= Elementor =

LNDLE Speed is built with Elementor sites in mind. The cache is cleared when Elementor templates are saved or when Elementor regenerates its CSS files, the Elementor preview is never cached or optimized, and the setup wizard points out when Elementor's CSS print method is set to inline output.

= Requirements and limits =

* Apache or LiteSpeed with `.htaccess` support is recommended. On other web servers (for example Nginx) the `.htaccess` rules have no effect; cached pages are then served through PHP, and the browser cache rules do not apply.
* WordPress Multisite is not supported.
* There is no separate cache for mobile devices and no cache for logged-in users.
* Cache preload and cache expiry depend on WP-Cron. On a site that is served mostly from the cache, a real cron job calling `wp-cron.php` is recommended.

= LNDLE Speed Pro =

LNDLE Speed Pro is a separate plugin available at [lndle.media/plugins/speed/](https://lndle.media/plugins/speed/). It replaces the free plugin, takes over its settings and adds:

* Defer JavaScript and Delay JavaScript until user interaction
* Combine CSS and load selected stylesheets asynchronously
* Preload of the hero background image and of fonts
* Lazy load for background images
* WebP conversion
* YouTube facade (preview image instead of the iframe until the video is clicked)
* Scheduled database cleanup

The Pro features are not contained in this plugin: the code for them is only part of the separate Pro plugin. Everything in the feature list above works without Pro, and your settings are kept if you switch.

== Installation ==

1. In your WordPress dashboard, go to Plugins → Add New, search for "LNDLE Speed", then install and activate it. Alternatively, upload the `lndle-speed` folder to `/wp-content/plugins/` and activate the plugin on the Plugins screen.
2. After the first activation you are taken to the setup wizard at Settings → LNDLE Speed. It lists what was detected on your site and the recommended settings.
3. Switch the recommendations you want on or off and click "Apply recommendations".
4. Open your site in a private browser window and check that pages look and work as before. The response header `X-LNDLE-Speed: HIT` shows that a page was served from the cache.

If another caching plugin is active, deactivate it first. Two page caches interfere with each other.

== Frequently Asked Questions ==

= Does it work with Elementor? =

Yes. The cache is cleared when you save Elementor templates or when Elementor regenerates its CSS files, and the Elementor preview is never cached or optimized. If Elementor prints its CSS inline, the setup wizard suggests switching the CSS print method to "External File", which works better with a page cache.

= What does the plugin write to my server? =

On activation and whenever you save the settings, LNDLE Speed writes the following:

* `wp-content/advanced-cache.php` – the WordPress drop-in that loads the cache engine before WordPress itself. If a drop-in from another caching plugin already exists and that plugin is still active, the file is not replaced; you get a notice and can replace it manually. The previous drop-in is then kept in the database and written back when LNDLE Speed is deactivated.
* `wp-content/cache/lndle-speed/config.php` – a generated configuration file for the cache engine, in the plugin's own cache directory. That directory denies direct access to PHP files.
* `define( 'WP_CACHE', true ); // LNDLE Speed` in `wp-config.php`. If `WP_CACHE` is already set to `true`, the file is left unchanged. An existing `WP_CACHE` line with another value is replaced.
* A block between `# BEGIN LNDLE Speed` and `# END LNDLE Speed` at the top of the `.htaccess` file in your site root, containing the rewrite rules for the page cache and, if enabled, the browser cache rules.
* The folder `wp-content/cache/lndle-speed/` with the cached pages, the minified CSS files and a small `.htaccess` file that sets the response headers for cached pages.

When you deactivate the plugin, it removes its `.htaccess` block, its own `advanced-cache.php` (or restores the drop-in that was there before), the `WP_CACHE` line it added, the folder `wp-content/cache/lndle-speed/` with the configuration file, and its scheduled events. When you delete the plugin, its options are removed from the database as well.

Not removed automatically: a `WP_CACHE` line that was already in `wp-config.php` before activation. Removal requires that the files are still writable at the time of deactivation.

= My host already has a server cache. Do I still need the page cache? =

Usually not. The setup wizard requests your home page and looks for response headers of a server-side page cache (for example Varnish, Nginx FastCGI cache or LiteSpeed) and of the Cloudflare HTML cache. If it finds one, it switches the page cache and the preload off in its recommendations so that pages are not cached twice. The other features – lazy load, image dimensions, CSS minification and the WordPress cleanup – can be used together with a server cache. In that case, clear the cache at your hosting provider after changing settings or content.

= Does the plugin send data anywhere? =

No. The plugin has no tracking, does not contact a license or update server and loads no external scripts or fonts.

It makes HTTP requests to your own site only: the cache preload requests your sitemap and your pages so that they are cached, and the setup wizard fetches your home page from your browser to look for cache headers. Pages are only preloaded if they belong to your own domain. Sitemaps on other domains are ignored.

The settings page contains links to the LNDLE Speed Pro page on lndle.media. They are plain links; nothing is loaded from there unless you click them.

= Does it support Multisite? =

No. Multisite networks are not supported, and the setup wizard shows a warning when it detects one.

= Does it work on Nginx? =

Partly. Without `.htaccess`, cached pages are served through PHP instead of directly by the web server, which is slower than on Apache or LiteSpeed, and the browser cache rules have no effect. The setup wizard tells you which web server it found.

= My staging site is password protected. Why does the preload not work? =

With HTTP basic authentication in front of the site, the preload receives a 401 response. Add `define( 'LNDLE_SPEED_HTTP_AUTH', 'user:password' );` to `wp-config.php` so that the preload and WP-Cron requests can authenticate.

= How do I check a page without the cache? =

Append `?nolndlespeed` to the URL to bypass cache and optimization for a single request. Append `?lndle-speed-guest` to see the page as a visitor would, with all optimizations, while you are logged in.

= How do I exclude an image from lazy load? =

Add the class `skip-lazy` or the attribute `data-no-lazy` to the image, or enter part of the file name or class under "Lazy load exclusions".

= Is the database cleanup reversible? =

No. Revisions, auto-drafts, trashed items and spam are deleted permanently. Create a backup first.

== Screenshots ==

1. Dashboard
2. Setup wizard
3. Cache settings

== Changelog ==

= 0.9.0 =
* First public release.

== Upgrade Notice ==

= 0.9.0 =
First public release.
