# v2.2.14 ## 10/26/2026 1. [](#improved) * Disabled plugins are no longer loaded, so a disabled plugin with code that doesn't work on this version of Grav can't take the site down, and requests do less work. A disabled plugin is still listed with its settings, and its class still loads if another plugin asks for it. Thanks @NoNoNo [#4374](https://github.com/getgrav/grav/issues/4374) 2. [](#bugfix) * CSS with a long quoted string or comment (such as an inlined data: URI) minifies again instead of failing with a PCRE error, and a very large data: URI no longer empties the whole stylesheet from the bundle. Thanks @NoNoNo [#4372](https://github.com/getgrav/grav/issues/4372) * Inline JavaScript added with `loading: 'inline'` no longer renders a stray `inline` attribute on its script tag, and an inline JS module keeps its code when the pipeline is off. Thanks @NoNoNo [#4373](https://github.com/getgrav/grav/issues/4373) # v2.2.13 ## 10/23/2026 1. [](#bugfix) * [security] A field in a page's Flex form override keeps the stricter rules for dynamic options after it is merged into the directory blueprint, however it is renamed or numbered. Thanks @soquip * [security] Page content is now checked for unsafe markup as though its Twig runs, even when Twig is off for that page, since a later move or rename can turn it into a module. Thanks @vLWa7ch * [security] Flex user accounts: an account without super-admin access can no longer edit or delete a super-admin account through a Flex form, and a submitted password hash is ignored when an account is saved. Thanks @manus-pi * [security] Flex page storage now refuses a folder, template or language that is not a plain name. Thanks @shm0x00 * [security] Images referenced by stream URI in page content, the watermark image and `media_directory()` now only come from media folders (pages, images, media, themes, plugins), configurable with the new `security.media.allowed_roots` setting. Thanks @123abab123789 # v2.2.12 ## 10/22/2026 1. [](#improved) * The scheduler webhook now also runs jobs that missed their time since the last call, so a site pinged hourly (or late) no longer skips jobs set for another minute. Add `?mode=due` for the old behaviour. The scheduler health check now warns when a job is behind schedule, instead of five minutes after the last run [getgrav/grav-plugin-scheduler-webhook#9](https://github.com/getgrav/grav-plugin-scheduler-webhook/issues/9) 2. [](#bugfix) * Admin listings of a folder with thousands of pages no longer reload the folder once for every page in it, which made them slow and could run out of memory with caching on [getgrav/grav-plugin-admin2#200](https://github.com/getgrav/grav-plugin-admin2/issues/200) * A scheduled backup no longer fails with "ZipArchive::close(): Unexpected length of data" when another job changes a file in the site while the backup is being written. The backup is built again (up to three tries), and if it still can't be written, it is marked as failed while the rest of the scheduler run carries on. A failing job used to stop the whole run, so the jobs after it never ran and none of their results were saved # v2.2.11 ## 10/19/2026 1. [](#bugfix) * A licence key saved with a stray space in the product slug or the key itself (` lightbox-gallery`, for example) now works for installs and updates. Spaces are trimmed when a key is saved, and keys already saved that way are read correctly * An image pasted into the editor as inline data (a `data:` image) now shows on the frontend. Grav was turning the `+` characters in the image data into spaces, which also affected image paths with a `+` in them such as `a+b.png` [getgrav/grav-premium-issues#628](https://github.com/getgrav/grav-premium-issues/issues/628) # v2.2.10 ## 10/16/2026 1. [](#bugfix) * With `images.watermark.watermark_all` on, every image now gets the watermark, not only images with a resize or other action. A 1x image made from an `@2x` file and a framed image are stamped once, and retina alternatives are kept. Thanks @HawkForge [#4359](https://github.com/getgrav/grav/issues/4359) [#4360](https://github.com/getgrav/grav/pull/4360) * A remote CSS or JS file in the asset pipeline (a CDN stylesheet, for example) now gives up after 5 seconds if its server doesn't answer (set with the new `assets.pipeline_remote_timeout` option in `system.yaml`), instead of holding the page until PHP's `max_execution_time` ends it with a 503. When a remote file can't be downloaded, its group is not cached: that request renders each file as its own tag, and the next request tries the download again # v2.2.9 ## 10/14/2026 1. [](#bugfix) * Adding an environment folder such as `user/env//` no longer creates a new security key for that host, which broke forms and sessions signed with the old one. The key stays in `user/config`, and a copy an earlier version put in an environment folder is moved there * A plugin or theme zipped from inside its own folder, or a zip made on macOS with a `__MACOSX` folder, now installs with `bin/gpm direct-install` and the admin's install-from-zip instead of failing with "Not a valid Grav package". Thanks @wakqasahmed [#2688](https://github.com/getgrav/grav/issues/2688) [#4357](https://github.com/getgrav/grav/pull/4357) * Sites on PHP-FPM pools that disable `getmypid()` (a common hardening) no longer fail when the page index is rebuilt: its temporary database file is named with a random string instead of the process id. The scheduler's `whoami()` also checks for `get_current_user()` before calling it # v2.2.8 ## 10/13/2026 1. [](#new) * Plugins can react when an image is loaded with the new `onImageMediumReset` event, for example to queue a watermark or other action on every image from its own metadata 2. [](#bugfix) * Setting only `watermark_all` for images in `system.yaml` no longer removes the watermark image, position and scale settings, and the watermark settings can now be edited in the Admin under Images # v2.2.7 ## 10/13/2026 1. [](#bugfix) * The scheduler log no longer gets two lines written every minute when no job was due; runs that do work still log their full detail. Thanks @onetrev [#4355](https://github.com/getgrav/grav/issues/4355) * The compiled config, blueprints and languages caches are written to a temporary file and moved into place, and a damaged one is rebuilt, so a request arriving while the cache is being rewritten no longer fails with a blank error page. Thanks @omega8cc [#4356](https://github.com/getgrav/grav/issues/4356) * The scheduler's run summary in `scheduler.log` counted each successful job twice # v2.2.6 ## 10/09/2026 1. [](#bugfix) * With the logs or cache folder moved by `GRAV_LOG_PATH` or `GRAV_CACHE_PATH`, the cache and backup jobs write their output to the moved logs folder, a job's `output:` can be a `log://` path, and `bin/grav cache-cleanup` and the GPM permission check find the moved cache folder. Thanks @onetrev [#4344](https://github.com/getgrav/grav/issues/4344) * Scheduler history files older than the `retention_days` setting are now deleted, instead of collecting forever [#4344](https://github.com/getgrav/grav/issues/4344)