WP Manifestindependent plugin directory
manifest / developer / aiya-cms-core

AIYA CMS - Headless Core self-updates

Headless-first administration and content framework for AIYA CMS.

by Yeraph · github.com/yeraph-plus/aiya-cms-core

★ 0stars
0forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/yeraph-plus/aiya-cms-core/archive/refs/heads/main.zip

Ships its own WordPress updater (Plugin Update Checker), so new versions show up under Dashboard → Updates.

Headless-first WordPress plugin for AIYA CMS (WP 6.4+, developed and running against WP 7.1, runtime PHP 8.5, Requires PHP: 8.5): the admin half of a decoupled site — settings, content domains, media pipeline, community, notifications and a versioned REST contract (aiya/core/v1) consumed by the Astro front end. No Gutenberg, no React in the admin; native admin styles only.

Ecosystem

  • this repository — WordPress backend: content domains, settings, the versioned aiya/core/v1 contract
  • aiya-cms-station — the Astro SSR front end that consumes the contract; its README is the authoritative deployment doc (nginx topology, environment variables, the siteurl-origin rule)
  • aiya-cms-resource-publisher — local desktop publisher for resource posts; the companion aiya-publish/v1 WP plugin ships from that same repo

Layout

  • src/ — plugin code (runtime, Settings framework, Admin surfaces, Domain modules, Api contract/presenter/rest layers); autoload Aiya\Core\ plus Aiya\Infra\ from packages/
  • packages/ — WordPress-free infrastructure packages, eight of them: aiya/image-processor, aiya/slug-toolkit, aiya/typesetting, aiya/opencc-convert (unwired by decision), aiya/openlist, aiya/gofile-api, aiya/payment-epay, aiya/payment-afdian — packages/README.md is the authoritative table. They are shipped in-tree and NOT composer-installed: the plugin autoloader reads each package's own composer.json for its PSR-4 prefix, and a package's third-party dependencies are declared in the root composer.json
  • themes/aiya-headless/ — the companion shell theme; sync source for its runtime location wp-content/themes/aiya-headless/ (see its README)
  • assets/ — admin CSS/JS (Backbone + jQuery UI + code editor)
  • languages/ — zh_CN translations (.mo built, see the i18n skill)
  • tests/Unit/ — PHPUnit suite (WP shim bootstrap, no install needed)
  • docs/ — ROADMAP (milestone log), ARCHITECTURE (module wiring and conventions), MIGRATION (legacy disposition)

Development

composer install            # deps + phpunit/phpcs/phpstan tooling
composer php:unit           # PHPUnit (Unit suite)
composer php:cs             # WordPressCodingStandard pass
composer php:stan           # PHPStan (level 8, WP stubs)
i18n                        # see .agents/skills/aiya-i18n-zh-cn (host python)

After activation the plugin runs its five clean-install migrations (0.80.0 pure CREATE TABLE statements — no upgrade steps, no data conversions), defaults permalinks to /%postname%/ when empty and schedules its crons. See docs/ARCHITECTURE.md for module wiring and docs/ROADMAP.md for the milestone-by-milestone iteration log.

Releases

Releases are cut by pushing a version tag — git tag v0.95.0 && git push origin v0.95.0. The tag must equal the plugin header Version: and the AIYA_CORE_VERSION constant; the workflow's gate step refuses to build otherwise. GitHub Actions (.github/workflows/release.yml) then:

  1. installs production dependencies (composer install --no-dev — the shipped vendor/ carries only imagine + pinyin, not the dev toolchain) and compiles the zh_CN .mo with msgfmt (*.mo is gitignored, so the release build is the only place it exists);
  2. stages a slim copy (no .git, .github, tests/, docs/, dev configs or root composer files — the packages' own composer.json manifests stay, the lazy autoloader reads them) and zips it with the top-level aiya-core/ folder;
  3. publishes a GitHub release with the zip, a commit-log changelog since the previous tag and GitHub's generated notes.

workflow_dispatch runs the same build without publishing and uploads the zip as a workflow artifact for inspection.

Online updates

The plugin never ships through wordpress.org, so it checks its own releases: the bundled Plugin Update Checker library (yahnis-elsts/plugin-update-checker, composer-installed) watches this repository's GitHub Releases and surfaces updates in the normal Plugins screen. The update source is built in (yeraph-plus/aiya-cms-core); a site may repoint it per environment — define('AIYA_CORE_UPDATE_REPO', 'owner/repo'); in wp-config.php, or filter aiya_core_update_repo — an empty value turns the checker off. The Update URI: false plugin header keeps wordpress.org out of the picture, and each release carries exactly one zip asset: the checker requires that zip and hands it to the updater — a release cut without it offers no update at all, never GitHub's source archive for the tag (which carries no composer vendor/ tree and no compiled .mo files). The aiya-headless shell theme is deliberately not distributed in releases — it is a placeholder, mirrored from themes/ by hand.

Deployment

The site is two hosts: this WordPress backend (content, media, users, versioned REST) and the Astro SSR application (front-station/) that renders the public site. The wp-content/themes/aiya-headless/ shell theme only catches direct hits on the WP host.

1. Backend (WordPress + aiya-core)

docker compose up -d        # wordpress:php8.5-apache + mariadb + phpmyadmin + wpcli
docker compose run --rm wpcli plugin activate aiya-core
  • wp-content/ is bind-mounted; deploy by syncing the plugin folder (and themes/aiya-headless/) into it — no image rebuild needed.
  • Schema: five 0.80.0 CREATE migrations run once through the schema version runner; a failed migration holds the stored version back and retries on the next request. There are no upgrade paths to maintain.
  • Production checklist:
    • WP_DEBUG / WP_DEBUG_LOG off (dev-only);
    • behind a CDN/reverse proxy, bridge the real client IP through the aiya_core_client_ip filter (rate limiting and guest dedup key on it — REMOTE_ADDR would collapse everyone onto the proxy IP);
    • narrow the web server's forwarded-header trust to the real front proxy only. The official wordpress:*-apache image ships mod_remoteip trusting every RFC1918 range, so any client that can reach WP directly rewrites REMOTE_ADDR with a bare X-Forwarded-For header — no AIYA_PROXY_SECRET needed — and forges a fresh identity per request. Override /etc/apache2/conf-available/remoteip.conf (bind-mount a replacement) with RemoteIPHeader X-Forwarded-For + RemoteIPInternalProxy <real proxy segment> only; the secret bridge is evaluated in PHP after Apache has already decided what REMOTE_ADDR is, so a wide server-level trust defeats it. In front of nginx keep $proxy_add_x_forwarded_for (appending) — spoofed entries always end up left of the real IP and mod_remoteip's rightmost resolution ignores them;
    • leave WP_DEBUG undefined (webhook logs stay off);
    • /wp/v2 is gated to logged-in editors automatically; first-party namespaces self-announce via aiya_core_firstparty_rest_namespaces.

2. Frontend (aiya-cms-station)

The Astro SSR application (front-station/ in the dev workspace). Its README is the authoritative deployment doc; the short version:

cd front-station
npm install
cp .env.example .env        # server-side only: AIYA_SITE_URL / AIYA_WP_API_URL /
                            # AIYA_PROXY_SECRET (+ optional timeout / visitor-IP
                            # header / session cookie domain)
npm run verify              # astro check + vitest + prettier + build
npm start                   # node dist/server/entry.mjs (env-file aware)
  • The .env is server-side only and never reaches the browser bundle; production takes real environment variables.
  • When the backend is unreachable the site serves a 503 gate page with Retry-After and auto-recovers — no crash loops.

3. Contract sync loop

The frontend's zod schemas are enforced against a backend-generated snapshot:

docker compose run --rm wpcli aiya contracts snapshot   # from D:\WordPress_Dev
# → copy the output to front-station/src/lib/core/contracts.snapshot.json
cd front-station && npm test                # shape drift turns the suite red

The v1 lock (contracts.snapshot.v1.json, additive-only) is amended only by owner decision, recorded in the ROADMAP.

4. Shell theme sync

Edit either copy of aiya-headless (repo themes/ or runtime wp-content/themes/) and mirror to the other — the three runtime files (style.css / functions.php / index.php) must stay byte-identical (the README exists only in the repo copy).