Add website module presets for choosing a site distribution from the Module Manager, including Base, Support, Standard, Development, and Demo presets.
Add Module Manager preset controls with active preset display, preset comparison details, preset membership filtering, and an option to keep currently enabled modules when applying a preset.
Add REST API endpoints for reading and applying the selected website preset, including per-module preset membership and selected-preset status in module responses.
Add an admin notice that prompts administrators to choose a website preset when none is selected.
Changed
Replace module auto_enable metadata with preset membership metadata across module definitions, generated module references, and developer documentation.
Update first-run module discovery to enable modules from the selected preset, preserve required infrastructure and dependencies, and track newly discovered modules by preset.
Separate preset membership chips from module taxonomy metadata on Module Manager cards.
Internal: Resolve 46 ESLint warnings across block edit components and admin UI — memoised JSX props with useCallback/useMemo, extracted sub-components for handlers created inside .map(), and silenced intentional sequential-await patterns in e2e test helpers
Internal: Add Airfleet Nexus Tooling (SSH agent) and Airfleet Nexus + WordPress (SSH agent) dev container variants with explicit SSH_AUTH_SOCK bind-mount for developers using 1Password or other non-standard SSH agents
video-youtube: New YouTube Video block with URL input, lazy loading, autoplay/autopause, poster, and iframe postMessage bridge.
video-vimeo: New Vimeo Video block with lazy loading, autoplay/autopause, poster via WP oEmbed proxy, and iframe postMessage bridge.
video-wistia: New Wistia Video block using Aurora Player (<wistia-player> Web Component) with native DOM events, lazy loading, and auto-poster via oEmbed.
allow-wistia-oembed: New module that registers Wistia as an oEmbed provider for auto-poster thumbnail fetching.
Poster image support for all 4 video blocks with auto-poster for YouTube, Vimeo, and Wistia. Video File supports custom upload only.
Shared video architecture in src/shared/scripts/video/ reused across all providers — media controls, iframe bridge, overlay, playback state, unmute indicator, and DOM events (afnx-video-*, afnx-media-*).
Filterable play button and unmute button icons and labels via PHP filters.
Changed
video-file: Refactored to use shared video modules. Editor uses MediaPlaceholder and MediaReplaceFlow. Settings labels updated for clarity.
allow-lottie: Tier changed to enhancement.
block-lottie: Live animation preview in editor via sandbox iframe. Simplified poster handling to match video blocks. Poster panel moved after Behavior panel.
disable-data-uninstalling: New module allowing site administrators to prevent plugin data from being deleted when the plugin is uninstalled or when switching between plugin preview versions in the Airfleet plugin manager. Module state is checked directly in the uninstall hook via ModuleManager to ensure data protection works correctly outside the normal plugin lifecycle.
Internal: Store unreleased changelog entries as separate changelog/unreleased/*.md fragments and consolidate them into CHANGELOG.md during plugin release via @airfleet/wordpress-dev.
Internal: Update @airfleet/wordpress-dev to 4.11.1.
Added changelog-fragments command for validating and consolidating changelog/unreleased/*.md files into CHANGELOG.md.
Changed
changelog-add --check now accepts either CHANGELOG.md Unreleased entries or valid changelog/unreleased/*.md fragments, with --skip-changelog-fragments available when fragments should be ignored.
version-set now includes changelog fragments when auto-determining and checking .airfleet-release, with --skip-changelog-fragments to use only CHANGELOG.md entries.
release github, release npm, release plugin, and release theme now consolidate changelog fragments before Keep a Changelog updates CHANGELOG.md, with --skip-changelog-fragments to bypass consolidation.
Adds a new Accordion module and block with auto-close, icon system, and custom events, alongside a CSS color sanitization utility and documentation updates.
Updated docs docs/guide/modules.md and docs/blocks/background-image.md.
Added
block-registration - added method to unregister blocks that depend on modules, when the modules are not active.
accordion: New Accordion module — registers and manages the lifecycle of the accordion block. Enabled by default; disabling this module will unregister the accordion block and its related child blocks (accordion-item, accordion-item-heading, accordion-item-content).
block-accordion: New Accordion block (airfleet-nexus/accordion) — a container block for collapsible content items with autoClose behavior and showIcon context. Toolbar "Add item" button for faster item creation. CSS modifier classes (.afnb-accordion--has-icon, .afnb-accordion--no-icon, .afnb-accordion--icon-left, .afnb-accordion--icon-right) for icon-aware heading padding. Tab color controls (Active/Inactive Background and Text) set via inline style attribute on the wrapper, cascading to all tabs via CSS custom properties. Auto-switch option with timed item cycling, configurable interval, manual click reset, viewport-aware pausing, and optional progress bar animation.
block-accordion: Extensible icon system featuring SVG path-based animations (plus-minus and arrows), a filterable PHP configuration, and a server-side localized icon picker in the editor.
block-accordion: Custom DOM events dispatched on the wrapper: afnx-accordion-load, afnx-accordion-open, and afnx-accordion-close.
block-accordion: Vanilla JS frontend behavior (view.js) — handles expand/collapse toggling, autoClose logic, and deep linking via URL hash. No external dependencies or Interactivity API.
block-accordion: Enhanced editor experience mimicking the native accordion block.
block-accordion-item: New Accordion Item block (airfleet-nexus/accordion-item) — a wrapper for heading and content, supporting openByDefault for initial state control.
block-accordion-item-heading: New Accordion Item Heading block (airfleet-nexus/accordion-item-heading) — locked inner block for accordion-item. Wraps a core/heading and a toggle button HTML element. The heading's native HTML anchor field enables URL deep-linking to that item.
block-accordion-item-content: New Accordion Item Content block (airfleet-nexus/accordion-item-content) — locked inner block for accordion-item. Provides the collapsible panel body with CSS grid-based transitions.
SanitizeCssColor: New utility for sanitizing CSS color values (hex, rgb/rgba, hsl/hsla, oklch, oklab, color, var, and CSS keywords). Includes comprehensive PHPUnit test suite covering all WordPress-produced color formats and injection attack prevention.
Prevented open_basedir warnings (is_readable(): open_basedir restriction in effect. File(~/.aws/config) is not within the allowed path(s)) when initializing the S3 client on hosts that restrict access to the home directory (e.g. Kinsta). The AWS SDK is now configured with use_aws_shared_config_files => false, so it no longer probes ~/.aws/config and ~/.aws/credentials since credentials are already supplied explicitly.
Suppress spurious invalid_grant: Malformed auth code errors caused by duplicate OAuth callback requests (browser back/forward navigation, link prefetch, and bot replay) re-redeeming a single-use Google authorization code. The callback handler now guards against duplicate processing per state using an atomic object-cache lock with a transient fallback, redirecting already-authenticated users instead of re-exchanging the code.
Docs: move all auto-generated documentation (docs/api/, docs/release-notes.md) to docs/generated/ and add it to .gitignore to prevent merge conflicts across branches.
Slack digest release lists: Weekly Slack digests now list only the latest release per repository and show the total release count across the number of repos, matching the monthly digest format. Both weekly and monthly Slack digests also drop the extra generated-from-summary footer line.
Worker observability: Enabled Cloudflare Worker observability in worker/wrangler.toml and added explicit release-processing/build-hook logs so webhook deliveries, summary generation, and Pages build-trigger attempts can be traced in Cloudflare Workers logs.
Changed
Slack digest workflows: Moved the weekly and monthly Slack schedules off the top of the hour, added shared period-target resolution, and updated both workflows to seed the required closed-period summary before sending to Slack.
Summary and deploy docs: Documented the production site URL, clarified the daily Worker cron and rollover rebuild behavior, and noted the optional PAGES_BUILD_HOOK_URL GitHub Actions secret used to refresh the static site after Slack-triggered summary backfills.
Worker scheduled rebuilds: The daily Worker cron now triggers a Pages rebuild when the featured closed week or month rolls over, even if the relevant summary already exists and no summary content changed.
Fixed
Slack summary availability: Weekly and monthly Slack digests now ensure the required summary exists in KV before posting, so scheduled sends no longer fail when the daily Worker cron has not backfilled that period yet.
Static weekly/monthly freshness: Weekly and monthly landing pages no longer stay pinned to the previous closed period until another release arrives; the Worker now forces a rebuild after week/month rollover so the featured static pages stay aligned with current closed periods.
Added error handling for missing compiled Blade cache files during rendering; automatically recompiles and retries when a compiled cache file is deleted mid-request (race condition during cache clear)
Added logging for cache file recovery attempts via Airfleet Cache Control logger (falls back to error_log)
Worker uncaught exception handling: Wrapped the fetch handler's handleWebhook call in a top-level try/catch so any unhandled exception returns a 500 response instead of crashing the Worker with a Cloudflare 1101 error. GitHub retries on 500, so no webhook deliveries are permanently lost.
Missing secret guards: Added explicit configuration guards for GITHUB_PRIVATE_KEY (in importPrivateKey) and PAGES_BUILD_HOOK_URL (in maybeTriggerBuild), throwing descriptive errors when either secret is not set rather than a cryptic TypeError.
GitHub App webhook signature verification: Guarded verifySignature against an undefined or empty GITHUB_WEBHOOK_SECRET, which previously caused crypto.subtle.importKey to throw a DataError (empty HMAC key material) and return a 500 instead of processing the webhook. The worker now throws a descriptive error that is caught and logged clearly. Also added a missing draft release check so draft releases are ignored alongside prereleases.
Local summary generation: Added scripts/summarize-local.ts and npm run summarize:local to generate release, weekly, and monthly summaries using a local Ollama model instead of Cloudflare Workers AI. Supports the same --year/--month/--week/--release selectors and --existing/--only modes as the cloud seeding script. An optional --upload flag pushes generated summaries directly to Cloudflare KV. OLLAMA_HOST and OLLAMA_DEFAULT_MODEL env vars configure the Ollama endpoint and default model.
Changelog stats: Added a Stats page with all-time repository and release totals, monthly release activity, and per-repository release counts.
Seeded previews: Added a preview:seed script to seed live KV data, build the site, and start the local preview server in one command.
Selective summary seeding: Added --only flag to npm run data:seed-summaries to control which summary types are regenerated. Accepts a comma-separated list of releases, weekly, and monthly — e.g. --month 2026-04 --only monthly regenerates only the monthly summary without touching release or weekly summaries.
Repository exclusion config: Added src/data/excluded-repos.json to exclude repositories from all changelog views. Entries are full repo names (owner/name). airfleet/airfleet-elements-test is excluded by default. Filtering is applied centrally in the data layer across all pages.
Changed
Changelog page polish: Refined release-card disclosure controls, simplified the project filter, tightened weekly/monthly summary layouts, added month summaries to archive cards, aligned weekly/monthly archive labels and cards, and added previous/next navigation to archive detail pages.
Layout and archive polish: Made the site brand in the header link back to the homepage, refreshed the footer copy to use the product name, surfaced the all-time release count, and aligned archive week pages around the YYYY-Www label plus a clearer week range.
Weekly and monthly summaries: Added a Monthly page, promoted summary-aware weekly cards, introduced separate monthly and summary KV paths, and wired the Worker plus a manual backfill workflow to generate Cloudflare-native release/weekly/monthly summaries for closed periods.
Summary backfill controls and prompts: Expanded the manual summary seeding workflow and CLI to target a full year, one month, one week, or one release; added explicit refresh/skip/overwrite behavior plus model overrides; switched the shared default model to @cf/zai-org/glm-4.7-flash; and upgraded monthly summaries to use a more narrative grouped prompt.
Summary presentation: Tightened release, weekly, and monthly summary prompts to avoid redundant project/version/count phrasing and generic openings; stopped generating unused expanded release summaries; promoted compact summaries on week/month cards; and aligned weekly/monthly landing pages with the archive detail layouts.
Monthly summary prompts: Upgraded monthly compact summaries to avoid opening with the month name, year, or any time-period reference — the summary must start with the work itself. Upgraded monthly expanded summaries to produce a richer structured narrative with 2–4 ##-headed sections by capability theme, starting with a one-sentence overview. Prompt version bumped to monthly-v6 with increased token budget.
Release card repo label: The repository label on release cards is now a link to the repository's release history page (/repo/{owner}/{name}).
Slack digest automation: Added weekly and monthly GitHub Actions workflows plus CLI helpers that post stored summaries to Slack through a Slack app bot, with manual period overrides for reruns.
Docs and workflow guidance: Updated README.md and AGENTS.md for the summaries workflow, release checklist, and changelog expectations.
Fixed
Homepage load-more page count: Capped getRequiredPageCount() by the total matching release count so filtering to a repo with fewer releases than the visible limit no longer requests non-existent pages and triggers 404 errors.
Monthly week overlap filter: Normalized both sides of the week/month overlap comparison to YYYY-MM-DD so full ISO timestamps stored in monthly index items no longer cause boundary weeks to be incorrectly excluded.
Markdown protocol-relative URL sanitization: sanitizeUrl now explicitly rejects protocol-relative URLs (//example.com) instead of normalizing them to http: and passing the allowlist check.
Weekly Slack digest formatting: Applied the same markdown-to-mrkdwn conversion used by the monthly digest so weekly summaries render bold text, headings, and links correctly in Slack instead of showing raw markdown syntax.
KV data download safety: downloadKvData now only deletes public/data after confirming the KV namespace contains keys, preventing an empty build when credentials point at a wrong or temporarily empty namespace.