=== Xaflo WP Connect — AI control for WP ===
Contributors: xaflo
Tags: rest-api, automation, mcp, ai, json
Requires at least: 6.0
Tested up to: 6.9
Requires PHP: 8.1
Stable tag: 1.3.2
License: MIT
License URI: https://opensource.org/licenses/MIT

Expose your WordPress site as 50 typed REST tools so MCP-compatible clients can read, write and audit it through scoped JWT tokens.

== Description ==

**Xaflo WP Connect** is a lightweight REST API layer for WordPress. It turns the platform into a programmable surface that external tools — including modern AI assistants that speak the Model Context Protocol (MCP) — can drive safely through scoped, short-lived tokens.

I built this plugin because the existing options were poor: application passwords give blanket access, the WordPress REST API is verbose and partial, and writing a custom integration for every site you manage doesn't scale. **Xaflo WP Connect** ships a single, audited surface that any developer or automation tool can target. No vendor lock-in, no SaaS, no account on a third-party server.

= What you get =

* **50 typed REST endpoints** under `/wp-json/wpcb/v1/*` — posts, pages, media, menus, widgets, customizer, taxonomies, SEO, analytics, multilingual, debug log, backup, health checks. Read-only inspection of installed plugins and theme files.
* **JWT scoped authentication** — 23 granular scopes (`content:read`, `media:write`, `cli:exec`, …). Issue a read-only analytics token, a content-only editor token, a full-admin token. Revoke any of them instantly.
* **Capability + scope double check** on every dangerous route: even a JWT with the right scope still has to belong to a user with the matching WordPress capability (`manage_options`, `edit_plugins`, `edit_themes`, `install_plugins`).
* **Confirmation tokens** on irreversible operations — database writes, plugin install from zip, theme switch — so a single API call cannot do silent damage.
* **Automatic backups** before destructive writes. One-call restore via `wp_backup_restore`.
* **Audit log** for every API call: actor, scope, payload, timestamp.
* **Multilingual aware** — works with WPML and Polylang as first-class objects.
* **Maintenance mode toggle** — branded 503 page + IP allow-list bypass.
* **Debug log tail** — read and filter `wp-content/debug.log` over REST.
* **Filesystem browser** — list / read / write files sandboxed to ABSPATH with extension allowlist, path-traversal hardening (`realpath` containment, null-byte stripping), and a hard block on `wp-config.php` writes.
* **JWT secret never in the database** — defined in `wp-config.php` only.

= Why it exists =

Modern AI coding assistants that speak MCP need a structured, typed interface to do useful WordPress work without scraping admin HTML or executing brittle shell scripts. The MCP spec gives them a way to describe tools. This plugin gives WordPress a matching surface — 78 tools with JSON schemas, scoped auth, automatic rollback. The same surface is equally usable from a curl script, a Python automation, a CI job, or your own Node service. There is nothing AI-specific in the wire protocol; it's plain HTTPS + JWT.

= Pricing =

**The plugin is free forever, MIT licensed.** All 78 REST endpoints are available in the free version, with no upsell screens inside WordPress.

If you want a GUI to manage multiple WordPress sites from a single window, I also distribute an OPTIONAL desktop companion app — [Xaflo Desktop](https://wpconnect.xaflo.com/desktop-app/):

* **Xaflo Desktop Lite (free)** — manage **1 connected WordPress site**. All 78 tools. Auto-updates. No card, no signup.
* **Xaflo Desktop Pro (€199/year)** — manage **unlimited sites** + bulk parallel operations (e.g. push a plugin update to 50 sites in one click) + cross-site reports + priority support.

If you manage one WordPress site, you never need Pro — the free desktop already gives you everything. **The plugin itself is identical in both cases; the desktop app is what charges for multi-site GUI convenience.**

= Privacy =

* **No phone-home.** The plugin makes zero outbound HTTP requests of its own. No telemetry, no analytics, no cloud account required.
* **No third-party services contacted.** Every request is between your WordPress install and the client calling the REST API.
* **JWT verification is local** — HMAC-SHA-256 against a secret defined in `wp-config.php`.

= External services (disclosure) =

If you install the plugin from this WordPress.org directory, **no external service is contacted**. The plugin updates through wp.org like any other.

If you install the variant distributed at [wpconnect.xaflo.com](https://wpconnect.xaflo.com/wordpress-plugin/), that variant ships an optional self-hosted update channel pointing at `wpconnect.xaflo.com`. That variant is a separate download and is documented [here](https://wpconnect.xaflo.com/wordpress-plugin/).

= Trademark notice =

"Claude", "Claude Code" and "Claude Desktop" are trademarks of Anthropic PBC. "MCP" / "Model Context Protocol" is an open specification published by Anthropic. **Xaflo WP Connect is an independent open-source project, not affiliated with, endorsed by, or sponsored by Anthropic.** References in this plugin documentation describe compatible client software, not a partnership.

"WordPress" is a registered trademark of the WordPress Foundation.

= Source code =

* **License**: MIT — fork, audit, modify freely.
* **Author website**: [xaflo.com](https://xaflo.com/)
* **Support**: [wpconnect.xaflo.com/contact/](https://wpconnect.xaflo.com/contact/)

== Installation ==

1. Upload via Plugins → Add New → Upload Plugin, or copy the folder to `/wp-content/plugins/`.
2. Activate "Xaflo WP Connect" through the Plugins menu.
3. Add the JWT signing secret to `wp-config.php`:

   `define( 'WPCB_JWT_SECRET', 'paste a 64-char random string here' );`

   The admin page suggests a freshly-generated 64-char string on first load — copy it into `wp-config.php`, then reload.
4. Go to **Xaflo → Tokens → New**, pick the scopes you want to grant, copy the token. The token is shown only once; store it in your password manager.
5. Paste the token + your site URL into the tool you're integrating — any MCP-compatible client, a curl script, a Python automation, your own Node service.

== Frequently Asked Questions ==

= Do I need an account on xaflo.com to use the plugin? =

No. The plugin works fully standalone. The xaflo.com website is the optional companion that distributes the desktop GUI app; the plugin itself never contacts it.

= Is any data sent to a third-party server? =

No. Authentication is HMAC-signed JWT verified locally against a secret in your `wp-config.php`. The plugin emits zero outbound HTTP requests — only inbound requests from the tools you choose to grant tokens to.

= Can I restrict what an integration can do? =

Yes. JWT tokens are scoped — pick exactly which of the 23 granular scopes each token gets. A token with `content:read + analytics:read` cannot write a single character or install a plugin. Revoke any token instantly from the admin page.

= What if a write breaks the site? =

Every destructive write triggers a snapshot of the affected resource (theme file, plugin file, post content). Call `wp_backup_restore` with the snapshot ID to roll back. Snapshots are stored in `wp-content/uploads/xaflo-backups/`.

= Will the plugin work alongside Yoast / Rank Math / SEOPress? =

Yes. The SEO endpoints write to the same standard post-meta keys those plugins use, without owning the UI. Your existing SEO plugin keeps working.

= Does it work with WPML / Polylang? =

Yes — multilingual is first-class. Translations, language-linking and string-translation audits work with both WPML and Polylang.

= Does it work on WP Multisite? =

Yes. Each site in the network gets its own JWT secret and its own tokens. Network-wide bulk operations from a single token are on the roadmap.

= Is `wp_cli_exec` safe? =

It is **disabled by default**. When the site operator opts in (`update_option('wpcb_cli_enabled', true)`), it has a hard allowlist of 16 read-mostly commands (`wp option get`, `wp cache flush`, etc.), rejects shell metacharacters, and uses `escapeshellarg`. The endpoint additionally requires the `cli:exec` JWT scope and `manage_options` on the user the token is bound to.

= Where can I report a security issue? =

Privately at `security@xaflo.com`. Public disclosure 90 days after a fix is shipped.

== Screenshots ==

1. Token management dashboard — issue, list, revoke tokens with scope pickers.
2. Audit log — every API call recorded with actor, scope, payload, timestamp.
3. Active tokens — see when each was last used, from which IP, with which scopes.
4. Scope picker — 23 granular permissions.

== Changelog ==

= 1.3.2 — 2026-05-20 =
* Build: WordPress.org distribution variant introduced. This build defines `XAFLO_WPORG_BUILD = true` which disables endpoints classified as disallowed functionality by the WordPress.org Plugin Review Team: WP-CLI execution (`wp_cli_exec`), raw SQL queries (`wp_db_query`), generic filesystem writes (`/fs/write`), plugin/theme file editing (`wp_write_plugin_file` / `wp_write_theme_file`), and any plugin/theme installation, activation, deactivation, scaffold or switch operation. Maintenance-mode drop-in writes are also disabled. The remaining 50 endpoints cover content CRUD, media, SEO, analytics, multilingual, menus/widgets/customizer (read+write via standard core APIs), backup of the plugin's own snapshots, and read-only plugin/theme inspection.
* The full version with all 78 endpoints continues to be distributed at `https://wpconnect.xaflo.com/wordpress-plugin/` as a separate self-hosted build.

= 1.3.1 — 2026-05-17 =
* Improved: extension-aware allowlist on `/fs/write` (only safe text formats — `.php`/binary now require explicit operator opt-in).
* Improved: `Authorization` header falls back to `HTTP_X_WPCB_AUTHORIZATION` for shared hosts that strip the standard header.
* Fixed: `make-plugin-zip.py` was nuking `vendor/firebase/php-jwt/src/` because it excluded `src/` at all depths — split into root-only vs anywhere exclusion lists.
* Fixed: WordPress `sanitize_file_name()` was renaming `.exe.blockmap` to `.exe_.blockmap` — custom sanitizer preserves double-extension artifact names.

= 1.3.0 — 2026-05-16 =
* Added: `FilesystemController` (`/fs/list`, `/fs/read`, `/fs/write`, `/fs/mkdir`, `/fs/delete`) — sandboxed to ABSPATH with `wp-config.php` write block + path-traversal hardening (`realpath` containment, null-byte stripping, `..` rejection).
* Added: text/binary auto-detection for extensionless files (`error_log`, `debug.log`, `LICENSE`, …) with NUL-byte heuristic fallback.

= 1.2.0 — 2026-05-16 =
* Added: `MaintenanceController` — remote toggle with branded 503 drop-in + IP allow-list bypass; admin page server-rendered (works even if React bundle fails).
* Added: `DebugLogController` — tail `wp-content/debug.log` with severity filter; 8 MB tail cap; clear action.
* Added: plugin install / activate / deactivate / read-file / write-file endpoints.
* Added: theme file read / write endpoints.

= 1.1.0 — 2026-05-16 =
* Added: optional self-hosted update channel against `wpconnect.xaflo.com` (off by default in the wp.org build); SHA-256 integrity verification before unpack.
* Added: Plugin Deployer companion in the desktop app — push a `.zip` from your machine to N sites with one click.

= 1.0.0 — 2026-05-15 =
* First stable release. 78 tools, 23 JWT scopes, automatic snapshot before destructive writes, audit log with payload + actor tracking, WPML + Polylang adapters as first-class objects.

= 0.9.0 — 2026-04-22 =
* Added: 10 analytics endpoints (top posts, no-traffic, keywords, referrers, period comparison, category trends).
* Added: WPML + Polylang multilingual adapters.

= 0.8.0 — 2026-03-30 =
* Added: backup + audit subsystem. Automatic snapshot before destructive writes, full audit log, single-call rollback via `wp_backup_restore`.

= 0.5.0 — 2026-01-12 =
* First public preview. 40 tools. JWT auth. Read-only by default.

== Upgrade Notice ==

= 1.3.1 =
Security hardening on the filesystem endpoint and broader auth-header compatibility. No breaking changes.

= 1.3.0 =
Adds the filesystem controller. If you don't grant `fs:write` scope to any token you are not affected. No breaking changes.

= 1.2.0 =
Adds maintenance mode + debug.log tail + plugin install endpoints. New scopes: `system:maintenance`, `system:debug`. Existing tokens keep working.
