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.