Changelog
> Scope: this covers the Olympus theme **and** the bundled Crumina/Unyson framework > extensions that ship with it (sign-form, post-reaction, ajax-blog, extended-search, > post-share, stunning-header, contact-form). Items marked _(framework)_ live in the > bundled Unyson extensions. ## [4.8.0] — 2026-06-03 A large security, performance, and modernization release. The theme now targets modern PHP/WordPress, moves its AJAX surface to a namespaced REST API, migrates key UI to the WordPress Interactivity API, and trims hundreds of KB of JavaScript from every page. ### ⚠️ Requirements / breaking changes - **Minimum platform raised to PHP 8.1+ and WordPress 6.9+** (previously PHP 5.6 / WP 5.7). Verified compatible across PHP 8.1–8.4. Sites on older PHP/WordPress must update first. - Legacy IE11 polyfills and other dead browser shims have been removed. ### Security - **Notifications — fixed an IDOR/CSRF.** Notification actions (mark read/unread/delete, mark-all) are now served by an authenticated REST endpoint with per-user ownership checks, so one user can no longer act on another user's notifications. - **Sign-in / Registration _(framework)_ — multiple fixes:** - Restored CSRF protection in a **cache-safe** way: forms carry no stale nonce; a fresh nonce is fetched from an uncached REST endpoint at submit time and enforced server-side (fails closed with a friendly "session expired" message). Works behind full-page caches. - Fixed a **reflected XSS** in the Youzer registration prefill (`$_GET` values were echoed into an inline script) — now `esc_js()`-escaped. - Fixed an **SQL injection** in the activation lookup (prepared statement). - reCAPTCHA verification now uses the WordPress HTTP API (`wp_remote_post`) with timeouts and error handling instead of `file_get_contents()` — no `allow_url_fopen` dependency, fails closed. - Sanitized all login/registration inputs; added a **same-origin guard**, **per-IP rate limiting**, an **open-redirect fix** (redirect targets validated against the site host), and a **URL-parameter-injection fix** in the registration prefill. - **Post reactions _(framework)_ — fixed an SQL injection.** The guest identity was taken from a spoofable `X-Forwarded-For`/`Client-IP` header and reached SQL unescaped. IPs are now validated and all reaction queries use prepared statements. Reaction `type` is whitelisted, preventing writes to arbitrary post-meta keys. The action nonce is now cache-safe. - **AJAX blog _(framework)_ — fixed a path traversal / local file inclusion.** The pagination view name came from the request and was concatenated into an include path; it is now whitelisted, and the template slug is sanitized against traversal. - **Extended search _(framework)_ — fixed a regex injection / ReDoS.** The raw search query was used as a regular expression; replaced with safe case-insensitive substring matching. - **SVG uploads — hardened against XXE/SSRF** in metadata parsing (network access disabled, DOCTYPE rejected). - **General hardening:** prepared statements for custom SQL, escaped output, HTTPS for remote downloads, and demo-import URL hardening. ### ⚡ Performance - **~385 KB of JavaScript removed from typical page loads:** - **sweetalert2 (105 KB)** is no longer enqueued globally — it lazy-loads only when an error notice actually needs to be shown. - **Lottie player** swapped for a lighter build (**280 KB → 168 KB**) and **deferred** — it now loads only when a visitor starts filling the registration form, instead of on every page. - **Replaced the SmoothScroll JS library with native CSS** smooth scrolling, with full `prefers-reduced-motion` support (no animation for users who request reduced motion). - Deferred non-critical JavaScript; removed dead IE11 and unused Font Awesome assets. ### ✨ Modernization - **REST API (`olympus/v1`).** AJAX handlers moved to a namespaced REST API with proper permission callbacks and schemas: instant search, notifications, friend requests (via BuddyPress core REST), demo tools, admin notices, sign-form nonce, **post-reaction toggle**, and the **AJAX blog listing**. Frontends prefer REST and fall back to admin-ajax, so there is no hard cutover. - **Interactivity API.** Migrated from jQuery to the WordPress Interactivity API: sidebar toggle, header instant search, friend-request accept/reject, and the notifications dropdown. - **Blocks & `theme.json`.** Added a settings-only `theme.json` (brand color palette, typography, layout) and replaced the deprecated `block_categories` filter with `block_categories_all`. Added a `@wordpress/scripts` build pipeline for blocks. ### Styling - Body/canvas and unread-notification backgrounds now use the `--ol-main-bg-color` token (correct light/dark theming); dropdown triangle colors aligned to the same token. ### Developer / tooling - Added quality gates: **PHPCS (WordPress Coding Standards)**, **PHPCompatibilityWP** (8.1+), and **PHPStan**. New `composer compat:ext` script runs the PHP 8.1 compatibility check across the bundled Crumina extensions (currently clean). - Added a runtime verification checklist (`docs/verification-checklist.md`) and an ADR recording the PHP 8.1+ / WP 6.9+ support matrix. ### Maintenance - **WooCommerce:** replaced template-file overrides with hooks/CSS, reducing the number of override files that must be kept in sync across WooCommerce updates. - Removed a duplicated `stunning-header` directory _(framework)_ that previously required patching the same file twice. - Fixed deprecated `FILTER_SANITIZE_STRING` usage and other PHP 8.1 runtime-deprecation hotspots across the bundled extensions.