# wp-plugins/mega-ai/

The MEGA AI WordPress plugin. Customers install this on their site;
it exposes the `/wp-json/mega/v1/*` REST endpoints the bot writes
through, and registers itself for auto-updates from
`https://app.gomega.ai/api/wp-plugins/mega-ai/update.json`.

## Version contract

The canonical version lives in **two places that must stay in sync**:

- The `Version:` plugin header at the top of `mega.php` (read by
  WordPress core and by the `update.json` distribution route).
- The `private static $version` constant inside `MegaPlugin` (used by
  `inject_update_manifest`'s `version_compare` against the manifest).

If you bump one, bump the other. Semver: feature → minor bump,
bugfix → patch bump.

## Self-update mechanism

The plugin has no entry in the WordPress.org directory, so WP core has
no native update source. Self-update is wired through two filters:

- `pre_set_site_transient_update_plugins` →
  `inject_update_manifest`: fetches the manifest (cached 6h in a
  `site_transient`), compares versions, and adds a `response[]` or
  `no_update[]` entry on the transient WP is computing.
- `plugins_api` → `maybe_serve_plugin_info`: serves the "View
  details" thickbox metadata.

`?force-check=1` on update-core.php bypasses the 6h cache so admins
can force a refresh.

## Hard rules

- **Pin the package host.** `$allowed_package_hosts` is the trust
  anchor of the entire auto-update flow — WP's upgrader will download
  - unzip whatever URL ends up in `$transient->response[]->package`
    into `wp-content/plugins/mega-ai/`. A poisoned manifest pointing
    elsewhere becomes a customer-RCE primitive. Never widen the
    allowlist without a corresponding manifest-side commitment to that
    host being permanent.
- **Sanitize every external manifest field that renders into
  wp-admin.** `maybe_serve_plugin_info` runs `sanitize_text_field` /
  `esc_url_raw` / `wp_kses_post` on the manifest values. The thickbox
  is rendered to an authenticated admin — unsanitized HTML in the
  manifest would execute in their session if the manifest is ever
  wrong.
- **Never raise an exception from the update hooks.** Both
  `inject_update_manifest` and `maybe_serve_plugin_info` MUST return
  the original transient/result on any failure — fetch error, parse
  error, host-allowlist miss, anything. Throwing here would break
  WP's overall update flow for every plugin on the site, not just
  this one.

## Distribution side

The matching app-side endpoints live at
`app/api/wp-plugins/mega-ai/` in this repo and are governed by the
`AGENTS.md` there. Changes to the manifest shape need to be made on
both sides simultaneously.
