feat(v3.12.0): media pipeline, AI image generation, capability probe, companion v2.9.0
Three-month batch sync from internal repo (~80 commits) covering Tracks F.5a, F.7e, F.8, F.17, F.18, F.X. WordPress media pipeline - Pillow-based optimization, AI image generation (OpenAI / Stability / Replicate / Google Nano Banana / OpenRouter), chunked + resumable uploads, bulk delete/reassign, idempotent retries. Capability discovery (F.7e) - Per-site credential probe + adapters for WordPress / WooCommerce / Gitea, tier-fit unions granted ∪ roles, capability badge UI with HTMX partial re-check, install hint in every companion-unreachable error. Companion plugin overhaul - Renamed wordpress-plugin/airano-mcp-seo-bridge → wordpress-plugin/airano-mcp-bridge. - Eight new endpoints: /capabilities, /bulk-meta, /export, /cache-purge, /transient-flush, /site-health, /audit-hook, /upload-and-attach. - wp.org Plugin Check pass: i18n, WP_Filesystem, scheme allowlist on audit-hook URL. Other - Gitea ergonomics (F.17): batch files, tree, search, compare, releases, fork. - Opportunistic bcrypt upgrade for legacy SHA-256 admin keys (F.8). - n8n refactor: structured errors, capability probe, missing tools backfilled. - Idempotency-Key dedup for AI media upload retries; WP client fast-fails on unreachable sites. Docs - README + CLAUDE.md drop the fixed "633 tools" claim. The total grows with each release; per-plugin approximations + dashboard-surfaced counts replace it. - Tools/Tests badges removed in favour of "Plugins: 10". Deployment - PyPI mirror chain, optional BUILD_HTTP_PROXY, Alpine→Yandex apk mirror, Debian-slim Plan-B Dockerfile, mirror.gcr.io variant. CI - Black + Ruff clean on Python 3.12; pytest tests/ green. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
BIN
wordpress-plugin/airano-mcp-bridge.zip
Normal file
BIN
wordpress-plugin/airano-mcp-bridge.zip
Normal file
Binary file not shown.
193
wordpress-plugin/airano-mcp-bridge/README.md
Normal file
193
wordpress-plugin/airano-mcp-bridge/README.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# Airano MCP Bridge
|
||||
|
||||
**Version:** 2.9.0
|
||||
**Requires WordPress:** 5.0+
|
||||
**Tested up to:** 6.9
|
||||
**Requires PHP:** 7.4+
|
||||
**License:** GPLv2 or later
|
||||
**Plugin slug:** `airano-mcp-bridge` (permanent)
|
||||
|
||||
> Companion plugin for [MCP Hub](https://github.com/airano-ir/mcphub) — the AI-native management hub for WordPress, WooCommerce, and self-hosted services.
|
||||
|
||||
## What this plugin does
|
||||
|
||||
MCP Hub lets AI assistants (Claude, ChatGPT, Cursor, VS Code Copilot, …) manage your WordPress site through the Model Context Protocol. The core features work against the stock `/wp-json/wp/v2/` REST endpoints — **you do not need this plugin to use MCP Hub**.
|
||||
|
||||
Installing **Airano MCP Bridge** unlocks a second tier of capabilities that WordPress's built-in REST API can't reach on its own:
|
||||
|
||||
- **Large-file uploads** that bypass `upload_max_filesize`
|
||||
- **One-round-trip upload + metadata + attach + set-featured** (v2.9.0)
|
||||
- **Thumbnail regeneration** (no WP-CLI / SSH)
|
||||
- **Cache purge** for 6 major cache plugins (LiteSpeed, WP Rocket, W3TC, WP Super Cache, WP Fastest Cache, SG Optimizer)
|
||||
- **Transient cleanup** (expired / all / pattern)
|
||||
- **Bulk post-meta writes** in a single REST round-trip
|
||||
- **Unified site-health snapshot** (5+ stock calls → 1)
|
||||
- **Structured JSON export** (posts / pages / products + media + terms + meta)
|
||||
- **Capability probe** — tells MCP Hub what the calling application password can actually do
|
||||
- **Audit hook** — forwards WordPress action events to MCP Hub with HMAC-signed webhooks
|
||||
- **SEO meta routes** for Rank Math and Yoast
|
||||
|
||||
All operations remain guarded by WordPress's own capability system — this plugin never bypasses auth.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download `airano-mcp-bridge.zip` from the MCP Hub release page.
|
||||
2. In WP Admin → **Plugins → Add New → Upload Plugin**, choose the zip and **Activate**.
|
||||
3. Generate an **Application Password** under Users → Profile (scroll to bottom).
|
||||
4. In MCP Hub dashboard → **My Sites**, add your WordPress site using that Application Password.
|
||||
|
||||
The plugin works out of the box. There are no settings pages to configure; behavior is controlled entirely through the REST API.
|
||||
|
||||
## REST API endpoints
|
||||
|
||||
### SEO meta (namespace `airano-mcp-bridge/v1`)
|
||||
|
||||
- `GET / POST /posts/{id}/seo` — Post SEO data (Rank Math or Yoast, auto-detected)
|
||||
- `GET / POST /pages/{id}/seo` — Page SEO data
|
||||
- `GET / POST /products/{id}/seo` — WooCommerce product SEO data
|
||||
- `GET /status` — Plugin status + active SEO plugins list
|
||||
|
||||
### MCP Bridge helpers (namespace `airano-mcp/v1`)
|
||||
|
||||
| Route | Method | Introduced | Purpose |
|
||||
|---|---|---|---|
|
||||
| `/upload-limits` | GET | 2.0.0 | Returns effective PHP + WP upload limits so MCP Hub can pick the right upload path |
|
||||
| `/upload-chunk` | POST | 2.0.0 | Raw-body upload that bypasses `upload_max_filesize` (still bounded by `post_max_size`) |
|
||||
| `/upload-and-attach` | POST | 2.9.0 | Same as `/upload-chunk` plus query-param metadata (`attach_to_post`, `set_featured`, `title`, `alt_text`, `caption`, `description`) — collapses 3 REST round-trips into 1 |
|
||||
| `/capabilities` | GET | 2.1.0 | Effective capabilities of the calling Application Password + feature flags + available routes |
|
||||
| `/bulk-meta` | POST | 2.2.0 | Batch `post_meta` writes in one request (max 500 items, per-item permission check) |
|
||||
| `/export` | GET | 2.3.0 | Structured JSON export of posts / pages / products + media + terms + meta, with `post_type` / `status` / `since` / `limit` / `offset` paging |
|
||||
| `/cache-purge` | POST | 2.4.0 | Auto-detects LiteSpeed, WP Rocket, W3 Total Cache, WP Super Cache, WP Fastest Cache, SiteGround Optimizer and triggers each one's purge API; always flushes object cache |
|
||||
| `/transient-flush` | POST | 2.5.0 | Native transient cleanup with `expired` / `all` / `pattern` scopes; optional site-transient handling for multisite |
|
||||
| `/site-health` | GET | 2.6.0 | Single-envelope health snapshot: WP/PHP/MySQL versions, disk free, active plugins, theme, writability, SSL — replaces 5+ stock calls |
|
||||
| `/audit-hook` | GET / POST / DELETE | 2.7.0 | Configure a webhook that forwards WP action events to MCP Hub. HMAC-SHA256-signed, non-blocking |
|
||||
| `/regenerate-thumbnails` | POST | 2.8.0 | Rebuild attachment sub-sizes via `wp_generate_attachment_metadata()` for a list of IDs or in paged batch mode |
|
||||
|
||||
### Authentication
|
||||
|
||||
All routes require **HTTP Basic** authentication with a WordPress **Application Password** (Users → Profile → Application Passwords). Per-route capability requirements:
|
||||
|
||||
| Route family | Required capability |
|
||||
|---|---|
|
||||
| SEO meta (read/write) | `edit_posts` |
|
||||
| Upload helpers | `upload_files` or `manage_options` |
|
||||
| Capabilities probe | `read` (any logged-in user) |
|
||||
| Bulk meta, Export | `edit_posts` (per-item `edit_post` check) |
|
||||
| Cache purge, Transient flush, Site health, Audit hook, Regenerate thumbnails | `manage_options` |
|
||||
|
||||
## Privacy
|
||||
|
||||
This plugin makes **no outbound network calls** on its own. It exposes authenticated REST API endpoints that your MCP Hub instance calls into. The audit-hook route **only** sends webhooks when you explicitly configure it (POST to `/audit-hook` with an endpoint URL + secret); without that configuration, zero telemetry leaves your WordPress.
|
||||
|
||||
No analytics, no phone-home, no cloud relay.
|
||||
|
||||
## Security notes
|
||||
|
||||
- All write routes enforce capability checks.
|
||||
- Raw-body uploads go through `wp_handle_sideload()` which respects WordPress's allowed-MIME list.
|
||||
- Bulk meta writes check `current_user_can('edit_post', $post_id)` per item, not just per batch.
|
||||
- Audit-hook secrets are stored in `wp_options` and never echoed in responses (only the last 4 characters are returned on read).
|
||||
- Audit-hook webhooks are signed with HMAC-SHA256 so MCP Hub can verify the message came from your site and hasn't been tampered with.
|
||||
|
||||
If you find a security issue, please report it privately to the maintainers at the [GitHub issues page](https://github.com/airano-ir/mcphub/issues) rather than filing a public issue.
|
||||
|
||||
## Frequently asked questions
|
||||
|
||||
### Do I need MCP Hub to use this plugin?
|
||||
|
||||
No. Every route is a standard authenticated WordPress REST endpoint and can be called from any HTTP client (curl, Postman, a custom integration). MCP Hub is the reference consumer but not a requirement.
|
||||
|
||||
### Which SEO plugins are supported?
|
||||
|
||||
**Rank Math SEO** and **Yoast SEO**. The plugin auto-detects which is active and routes SEO-meta calls accordingly.
|
||||
|
||||
### Does this plugin work on multisite?
|
||||
|
||||
Yes. Route registration, capability checks, and transient flushing all respect multisite boundaries. The optional `include_site_transients` flag on `/transient-flush` handles site transients on multisite setups.
|
||||
|
||||
### Why keep the folder name `airano-mcp-bridge` even though the plugin now does much more than SEO?
|
||||
|
||||
Plugin slugs on WordPress.org are permanent once registered. Existing installs keep working; display name, description, and feature surface are what we can update.
|
||||
|
||||
### What happens if I uninstall?
|
||||
|
||||
Uninstall removes plugin options including the audit-hook secret and endpoint. Media uploaded via the plugin stays in your media library (it's regular WordPress attachments — the plugin just provides the upload pipeline).
|
||||
|
||||
### How large a file can I upload?
|
||||
|
||||
The `/upload-chunk` route bypasses PHP's `upload_max_filesize` (typically 2–64 MB on shared hosting), but is still bounded by `post_max_size` and `memory_limit`. For files larger than `post_max_size`, MCP Hub falls back to its own server-side chunked session pipeline that reassembles chunks before handing the full file to this route.
|
||||
|
||||
## Changelog
|
||||
|
||||
### 2.9.0 — 2026-04-16
|
||||
|
||||
- New: `POST /airano-mcp/v1/upload-and-attach` — raw-body upload + metadata (title / alt / caption / description) + attach-to-post + set-featured in a single REST round-trip. Saves 2–3 calls for every hero-image or product-image workflow. Per-target permission enforced via `current_user_can('edit_post', attach_to_post)`.
|
||||
- Status + capabilities payloads now advertise `upload_and_attach: true` + `regenerate_thumbnails: true`.
|
||||
|
||||
### 2.8.0 — 2026-04-15
|
||||
|
||||
- New: `POST /airano-mcp/v1/regenerate-thumbnails` — rebuild attachment sub-sizes via `wp_generate_attachment_metadata()` after uploads, theme switches, or format conversions. Two modes: `{ "ids": [...] }` for targeted regeneration (max 50/call) or `{ "all": true, "offset": N, "limit": M }` for paged batches.
|
||||
|
||||
### 2.7.0
|
||||
|
||||
- New: `GET|POST|DELETE /airano-mcp/v1/audit-hook` — configure a webhook that forwards WP action events (`transition_post_status`, `deleted_post`, `user_register`, `profile_update`, `deleted_user`, `activated_plugin`, `deactivated_plugin`, `switch_theme`) to MCP Hub. HMAC-SHA256-signed, non-blocking `wp_remote_post`. Permission: `manage_options`.
|
||||
|
||||
### 2.6.0
|
||||
|
||||
- New: `GET /airano-mcp/v1/site-health` — single-envelope snapshot: WP version / multisite / locale, PHP version + extensions, server software + disk free, MySQL/MariaDB version + charset, active plugins + theme, writability checks (wp-content, uploads) + SSL.
|
||||
|
||||
### 2.5.0
|
||||
|
||||
- New: `POST /airano-mcp/v1/transient-flush` — native transient cleanup. Scopes: `expired` (default), `all`, or `pattern` (glob match, e.g. `rank_math_*`). Optional `include_site_transients` for multisite.
|
||||
|
||||
### 2.4.0
|
||||
|
||||
- New: `POST /airano-mcp/v1/cache-purge` — auto-detects active page-cache plugins (LiteSpeed, WP Rocket, W3 Total Cache, WP Super Cache, WP Fastest Cache, SiteGround Optimizer) and invokes each one's purge API. Always calls `wp_cache_flush()` for object caches.
|
||||
|
||||
### 2.3.0
|
||||
|
||||
- New: `GET /airano-mcp/v1/export` — structured JSON export (not WXR). Query params: `post_type`, `status`, `since`, `limit` (max 500), `offset`, `include_media`, `include_terms`, `include_meta`.
|
||||
|
||||
### 2.2.0
|
||||
|
||||
- New: `POST /airano-mcp/v1/bulk-meta` — batch post-meta writes (max 500 items per call). Per-item permission check via `current_user_can('edit_post', $post_id)`. Null meta values delete the key.
|
||||
|
||||
### 2.1.0
|
||||
|
||||
- New: `GET /airano-mcp/v1/capabilities` — reports the effective capabilities of the calling Application Password plus feature flags (Rank Math / Yoast / WooCommerce / multisite) and the list of companion routes this version ships. Consumed by MCP Hub's F.7e capability probe.
|
||||
|
||||
### 2.0.0
|
||||
|
||||
- **Rebrand**: "Airano MCP SEO Meta Bridge" → "Airano MCP Bridge". No longer SEO-only.
|
||||
- New: `GET /airano-mcp/v1/upload-limits` — returns effective PHP + WP upload limits.
|
||||
- New: `POST /airano-mcp/v1/upload-chunk` — raw-body upload route that bypasses `upload_max_filesize`.
|
||||
|
||||
### 1.3.0
|
||||
|
||||
- Added REST API endpoints for posts, pages, and products (GET/POST operations).
|
||||
- Added authentication requirement for all endpoints (edit_posts).
|
||||
- Fixed `rank_math_title` meta key registration.
|
||||
|
||||
### 1.2.0
|
||||
|
||||
- Enhanced WooCommerce product support.
|
||||
- Improved MariaDB compatibility.
|
||||
|
||||
### 1.1.0
|
||||
|
||||
- Added status endpoint for plugin detection.
|
||||
- Improved error handling.
|
||||
|
||||
### 1.0.0
|
||||
|
||||
- Initial release with Rank Math and Yoast SEO support.
|
||||
|
||||
## Upgrade notice
|
||||
|
||||
### 2.9.0
|
||||
|
||||
Adds `POST /airano-mcp/v1/upload-and-attach` — upload + metadata + attach + featured in one REST round-trip. No breaking changes to existing routes.
|
||||
|
||||
## Credits
|
||||
|
||||
Built by the [MCP Hub](https://github.com/airano-ir/mcphub) project. Contributions welcome — see the parent repository for contribution guidelines.
|
||||
2861
wordpress-plugin/airano-mcp-bridge/airano-mcp-bridge.php
Normal file
2861
wordpress-plugin/airano-mcp-bridge/airano-mcp-bridge.php
Normal file
File diff suppressed because it is too large
Load Diff
180
wordpress-plugin/airano-mcp-bridge/readme.txt
Normal file
180
wordpress-plugin/airano-mcp-bridge/readme.txt
Normal file
@@ -0,0 +1,180 @@
|
||||
=== Airano MCP Bridge ===
|
||||
Contributors: airano
|
||||
Tags: mcp, ai, rest-api, seo, media
|
||||
Requires at least: 5.0
|
||||
Tested up to: 6.9
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 2.9.0
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Companion plugin for MCP Hub. REST API routes for SEO meta and raw-binary media uploads that bypass upload_max_filesize.
|
||||
|
||||
== Description ==
|
||||
|
||||
**Airano MCP Bridge** is the official companion plugin for [MCP Hub](https://github.com/airano-ir/mcphub) — the AI-native management hub for WordPress, WooCommerce, and self-hosted services. It extends the WordPress REST API with dedicated routes that AI agents (Claude, ChatGPT, Cursor, VS Code Copilot) and the MCP Hub server rely on:
|
||||
|
||||
* **SEO meta routes** — read and write Rank Math SEO and Yoast SEO metadata for posts, pages, and WooCommerce products.
|
||||
* **Media upload helper routes** — accept raw-binary uploads via `php://input`, which bypasses the `upload_max_filesize` PHP limit (still bounded by `post_max_size`). Unlocks reliable hero-image and large-asset uploads for AI-agent workflows.
|
||||
* **Capability probe** — reports the effective PHP + WordPress upload limits so MCP Hub can pick the right upload path automatically.
|
||||
|
||||
**Features:**
|
||||
|
||||
* **Rank Math SEO Support** — Full access to all Rank Math meta fields
|
||||
* **Yoast SEO Support** — Full access to all Yoast SEO meta fields
|
||||
* **WooCommerce Compatible** — Works with product post types
|
||||
* **MCP Hub media pipeline** — bypasses `upload_max_filesize` for AI-agent uploads
|
||||
* **Secure** — Requires WordPress Application Password + capability checks on every route
|
||||
* **Auto-Detection** — Automatically detects active SEO plugin and advertises capabilities
|
||||
* **Zero Configuration** — Works out of the box after activation
|
||||
|
||||
**REST API Endpoints:**
|
||||
|
||||
*SEO meta (namespace `airano-mcp-bridge/v1`)*
|
||||
|
||||
* `GET/POST /wp-json/airano-mcp-bridge/v1/posts/{id}/seo` — Post SEO data
|
||||
* `GET/POST /wp-json/airano-mcp-bridge/v1/pages/{id}/seo` — Page SEO data
|
||||
* `GET/POST /wp-json/airano-mcp-bridge/v1/products/{id}/seo` — Product SEO data (WooCommerce)
|
||||
* `GET /wp-json/airano-mcp-bridge/v1/status` — Plugin status + active SEO plugins
|
||||
|
||||
*MCP Bridge helpers (namespace `airano-mcp/v1`, added in 2.0.0)*
|
||||
|
||||
* `GET /wp-json/airano-mcp/v1/upload-limits` — Effective PHP + WP upload limits
|
||||
* `POST /wp-json/airano-mcp/v1/upload-chunk` — Raw-body media upload (bypasses `upload_max_filesize`)
|
||||
* `GET /wp-json/airano-mcp/v1/capabilities` — Effective capabilities + feature flags + available routes (added in 2.1.0)
|
||||
* `POST /wp-json/airano-mcp/v1/bulk-meta` — Batch post/product meta writes in a single HTTP round-trip (added in 2.2.0)
|
||||
* `GET /wp-json/airano-mcp/v1/export` — Structured JSON export: posts, pages, products + media + terms + meta, with post_type/status/since/limit/offset paging (added in 2.3.0)
|
||||
* `POST /wp-json/airano-mcp/v1/cache-purge` — Auto-detects active cache plugins (LiteSpeed, WP Rocket, W3TC, Super Cache, Fastest Cache, SG Optimizer) and invokes their purge API; always flushes object cache (added in 2.4.0)
|
||||
* `POST /wp-json/airano-mcp/v1/transient-flush` — Native transient cleanup with scope=expired/all/pattern (glob); optional site-transient handling on multisite (added in 2.5.0)
|
||||
* `GET /wp-json/airano-mcp/v1/site-health` — Unified site-health snapshot: PHP/MySQL/WP versions, extensions, disk free, active plugins + theme, writability checks (added in 2.6.0)
|
||||
* `GET|POST|DELETE /wp-json/airano-mcp/v1/audit-hook` — Configure + query a webhook that forwards WordPress action events to MCP Hub (HMAC-SHA256 signed, non-blocking) (added in 2.7.0)
|
||||
* `POST /wp-json/airano-mcp/v1/regenerate-thumbnails` — Regenerate attachment sub-sizes via `wp_generate_attachment_metadata` for a list of IDs or in paged batch mode (added in 2.8.0)
|
||||
* `POST /wp-json/airano-mcp/v1/upload-and-attach` — Raw-body upload + metadata + attach-to-post + set-featured in a single REST call (added in 2.9.0). Query params: `attach_to_post`, `set_featured`, `title`, `alt_text`, `caption`, `description`. Permission: `upload_files` + `edit_post` on the target post.
|
||||
|
||||
**Designed for [MCP Hub](https://github.com/airano-ir/mcphub)** — the AI-native management hub for WordPress and self-hosted services.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the `airano-mcp-bridge` folder to `/wp-content/plugins/`
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. For SEO meta routes: ensure either Rank Math SEO or Yoast SEO is active
|
||||
4. The REST API endpoints are now available
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= Which SEO plugins are supported? =
|
||||
|
||||
Rank Math SEO and Yoast SEO. The plugin auto-detects which one is active.
|
||||
|
||||
= Does it work with WooCommerce? =
|
||||
|
||||
Yes. Product SEO endpoints are available when WooCommerce is active.
|
||||
|
||||
= How is authentication handled? =
|
||||
|
||||
All endpoints require WordPress Application Password authentication. SEO routes require `edit_posts`. Upload helper routes require `upload_files` or `manage_options`.
|
||||
|
||||
= Do I need MCP Hub to use the upload helper routes? =
|
||||
|
||||
No. The `/airano-mcp/v1/upload-chunk` route is a standard authenticated REST endpoint and can be used from any client that can send a raw-binary `POST` with `Content-Disposition` and `Content-Type` headers.
|
||||
|
||||
= Is there a size cap on the upload helper? =
|
||||
|
||||
The helper reads the request body via `php://input`, which is **not** subject to PHP's `upload_max_filesize` limit — but it is still bounded by `post_max_size` and `memory_limit`. For files larger than `post_max_size`, MCP Hub falls back to its own server-side chunked session pipeline.
|
||||
|
||||
= Why keep the folder name "airano-mcp-bridge" even though the plugin now does more than SEO? =
|
||||
|
||||
Plugin slugs on wordpress.org are permanent. Existing installs keep working; the display name and feature set are updated in 2.0.0.
|
||||
|
||||
= Can I use this without MCP Hub? =
|
||||
|
||||
Yes. All REST API endpoints work with any application that can make authenticated HTTP requests.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 2.9.0 =
|
||||
* Added `POST /wp-json/airano-mcp/v1/upload-and-attach` — same raw-body semantics as `/upload-chunk`, but accepts query params (`attach_to_post`, `set_featured`, `title`, `alt_text`, `caption`, `description`) and applies them in one PHP round-trip. Saves 2-3 REST calls per upload. Per-target permission enforced via `current_user_can('edit_post', attach_to_post)`.
|
||||
* `status` + `capabilities` routes now advertise `upload_and_attach: true` alongside the existing capability flags.
|
||||
|
||||
= 2.8.0 =
|
||||
* Added `POST /wp-json/airano-mcp/v1/regenerate-thumbnails` — rebuild attachment sub-sizes via `wp_generate_attachment_metadata()` after an upload or format conversion changes source pixels. Supports two modes: `{ "ids": [...] }` for targeted regeneration (up to 50 per call) and `{ "all": true, "offset": N, "limit": M }` for paged batches (max 50 per page, with `has_more` + `next_offset` for pagination). Non-image attachments are skipped; per-item permission check via `current_user_can('edit_post', $attachment_id)`. Permission: `upload_files` or `manage_options`.
|
||||
|
||||
= 2.7.0 =
|
||||
* Added `GET|POST|DELETE /wp-json/airano-mcp/v1/audit-hook` — configure a webhook that forwards WordPress action events (post transitions, deletions, user events, plugin activations, theme switches) to MCP Hub for unified auditing. Each event is signed with HMAC-SHA256 using a shared secret and posted non-blocking via `wp_remote_post` so the admin UI stays snappy. Secret is stored in `wp_options` and never echoed back in GET responses (only the last 4 characters are returned). Permission: `manage_options`.
|
||||
|
||||
= 2.6.0 =
|
||||
* Added `GET /wp-json/airano-mcp/v1/site-health` — single-envelope health snapshot: WordPress version/multisite/locale, PHP version + critical extensions, server software + disk free, MySQL/MariaDB version + charset, active plugins list (with versions), active + parent theme, writability checks (wp-content, uploads) and SSL status. Replaces 5+ separate REST calls with a single request. Permission: `manage_options`.
|
||||
|
||||
= 2.5.0 =
|
||||
* Added `POST /wp-json/airano-mcp/v1/transient-flush` — native PHP transient cleanup. Scopes: `expired` (default, calls `delete_expired_transients()`), `all` (delete every `_transient_%` row), or `pattern` (glob match, e.g. `rank_math_*`). Optional `include_site_transients` for multisite. Response includes `deleted_count` + capped `deleted_sample` for observability. Permission: `manage_options`.
|
||||
|
||||
= 2.4.0 =
|
||||
* Added `POST /wp-json/airano-mcp/v1/cache-purge` — auto-detects active page-cache plugins (LiteSpeed Cache, WP Rocket, W3 Total Cache, WP Super Cache, WP Fastest Cache, SiteGround Optimizer) and triggers their purge API. Always calls `wp_cache_flush()` for object caches. Permission: `manage_options`. Removes the need for Docker-socket + WP-CLI to flush caches on managed hosts.
|
||||
|
||||
= 2.3.0 =
|
||||
* Added `GET /wp-json/airano-mcp/v1/export` — structured JSON export of posts, pages, and WooCommerce products (not WXR). Query params: `post_type`, `status`, `since`, `limit` (max 500), `offset`, `include_media`, `include_terms`, `include_meta`. Response includes posts + referenced media + taxonomy terms + post meta in a single envelope, plus `has_more` / `next_offset` for pagination. Permission: `edit_posts`.
|
||||
|
||||
= 2.2.0 =
|
||||
* Added `POST /wp-json/airano-mcp/v1/bulk-meta` — writes many `post_meta` / `product_meta` entries in a single REST request. Capped at 500 items per call; each item is permission-checked via `current_user_can('edit_post', $post_id)`. Null meta values delete the key. Status endpoint now advertises `capabilities.bulk_meta = true` and the capabilities probe reports `routes.bulk_meta = true`.
|
||||
|
||||
= 2.1.0 =
|
||||
* Added `GET /wp-json/airano-mcp/v1/capabilities` — reports the effective capabilities of the calling application password, plus feature flags (Rank Math / Yoast / WooCommerce / multisite) and the list of companion routes this version actually ships. Consumed by MCP Hub's capability probe so per-user clients only see tools they're actually authorised to use.
|
||||
* Status endpoint now advertises `capabilities.capabilities = true`.
|
||||
|
||||
= 2.0.0 =
|
||||
* **Rebrand**: "Airano MCP SEO Meta Bridge" → "Airano MCP Bridge". The companion plugin is no longer SEO-only.
|
||||
* Added `GET /wp-json/airano-mcp/v1/upload-limits` — returns effective PHP + WP upload limits for MCP Hub probes.
|
||||
* Added `POST /wp-json/airano-mcp/v1/upload-chunk` — raw-body upload route that bypasses `upload_max_filesize`.
|
||||
* Status endpoint now includes `capabilities: { seo_meta, upload_limits, upload_chunk }`.
|
||||
* Plugin folder / slug unchanged: `airano-mcp-bridge` (permanent on wordpress.org).
|
||||
|
||||
= 1.3.0 =
|
||||
* Added REST API endpoints for posts, pages, and products (GET/POST operations)
|
||||
* Added authentication requirement for all endpoints
|
||||
* Fixed rank_math_title meta key registration
|
||||
|
||||
= 1.2.0 =
|
||||
* Enhanced WooCommerce product support
|
||||
* Improved MariaDB compatibility
|
||||
|
||||
= 1.1.0 =
|
||||
* Added status endpoint for plugin detection
|
||||
* Improved error handling
|
||||
|
||||
= 1.0.0 =
|
||||
* Initial release with Rank Math and Yoast SEO support
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 2.9.0 =
|
||||
Adds `POST /airano-mcp/v1/upload-and-attach` — upload + metadata + attach + featured in one REST round-trip. No breaking changes.
|
||||
|
||||
= 2.8.0 =
|
||||
Adds `POST /airano-mcp/v1/regenerate-thumbnails` for rebuilding attachment sub-sizes after uploads or format changes. No breaking changes.
|
||||
|
||||
= 2.7.0 =
|
||||
Adds `GET|POST|DELETE /airano-mcp/v1/audit-hook` to forward WordPress action events to MCP Hub. Disabled until configured. No breaking changes.
|
||||
|
||||
= 2.6.0 =
|
||||
Adds `GET /airano-mcp/v1/site-health` for a unified site-health snapshot. No breaking changes.
|
||||
|
||||
= 2.5.0 =
|
||||
Adds `POST /airano-mcp/v1/transient-flush` for native transient cleanup. No breaking changes.
|
||||
|
||||
= 2.4.0 =
|
||||
Adds `POST /airano-mcp/v1/cache-purge` for native cache flushing. No breaking changes.
|
||||
|
||||
= 2.3.0 =
|
||||
Adds `GET /airano-mcp/v1/export` for offline backups and migrations. No breaking changes.
|
||||
|
||||
= 2.2.0 =
|
||||
Adds `POST /airano-mcp/v1/bulk-meta` so MCP Hub can write many post meta values in one request. No breaking changes.
|
||||
|
||||
= 2.1.0 =
|
||||
Adds `GET /airano-mcp/v1/capabilities` so MCP Hub can probe which tools the current application password can actually use. No breaking changes; existing routes unchanged.
|
||||
|
||||
= 2.0.0 =
|
||||
Rebranded to "Airano MCP Bridge". Adds new `airano-mcp/v1` namespace with upload-helper routes. All existing 1.x REST endpoints keep working unchanged.
|
||||
|
||||
= 1.3.0 =
|
||||
GET endpoints now require authentication (edit_posts capability). Update your API clients if needed.
|
||||
Binary file not shown.
@@ -1,309 +0,0 @@
|
||||
# Airano MCP SEO Bridge - WordPress Plugin
|
||||
|
||||
**Version:** 1.3.0
|
||||
**Requires:** WordPress 5.0+, PHP 7.4+
|
||||
**License:** GPLv2 or later
|
||||
|
||||
## Description
|
||||
|
||||
SEO API Bridge is a comprehensive WordPress plugin that exposes Rank Math SEO and Yoast SEO meta fields via dedicated REST API endpoints. This enables MCP servers, AI agents, and other applications to read and write SEO metadata programmatically for posts, pages, and WooCommerce products.
|
||||
|
||||
## What's New in 1.3.0
|
||||
|
||||
- **Full REST API Endpoints** - GET and POST operations for all post types
|
||||
- **Product SEO Support** - Complete WooCommerce product SEO management
|
||||
- **Simplified Integration** - Direct API calls instead of meta field manipulation
|
||||
- **Better Error Handling** - Proper validation and error responses
|
||||
|
||||
## Features
|
||||
|
||||
- **Rank Math SEO Support** - Full access to all Rank Math meta fields
|
||||
- **Yoast SEO Support** - Full access to all Yoast SEO meta fields
|
||||
- **WooCommerce Compatible** - Works with product post types
|
||||
- **Secure** - Requires proper authentication and edit_posts capability
|
||||
- **Auto-Detection** - Automatically detects which SEO plugin is active
|
||||
- **Health Check Endpoint** - Dedicated API endpoint for plugin detection
|
||||
- **Zero Configuration** - Works out of the box after activation
|
||||
|
||||
## Supported SEO Fields
|
||||
|
||||
### Rank Math SEO
|
||||
|
||||
| Category | Field | Description |
|
||||
|----------|-------|-------------|
|
||||
| Core | `rank_math_focus_keyword` | Focus keyword |
|
||||
| Core | `rank_math_title` | Meta title |
|
||||
| Core | `rank_math_description` | Meta description |
|
||||
| Core | `rank_math_additional_keywords` | Additional keywords |
|
||||
| Advanced | `rank_math_canonical_url` | Canonical URL |
|
||||
| Advanced | `rank_math_robots` | Robots meta directives |
|
||||
| Advanced | `rank_math_breadcrumb_title` | Breadcrumb title |
|
||||
| Open Graph | `rank_math_facebook_title` | OG title |
|
||||
| Open Graph | `rank_math_facebook_description` | OG description |
|
||||
| Open Graph | `rank_math_facebook_image` | OG image URL |
|
||||
| Open Graph | `rank_math_facebook_image_id` | OG image ID |
|
||||
| Twitter | `rank_math_twitter_title` | Twitter title |
|
||||
| Twitter | `rank_math_twitter_description` | Twitter description |
|
||||
| Twitter | `rank_math_twitter_image` | Twitter image URL |
|
||||
| Twitter | `rank_math_twitter_image_id` | Twitter image ID |
|
||||
| Twitter | `rank_math_twitter_card_type` | Card type (summary, summary_large_image) |
|
||||
|
||||
### Yoast SEO
|
||||
|
||||
| Category | Field | Description |
|
||||
|----------|-------|-------------|
|
||||
| Core | `_yoast_wpseo_focuskw` | Focus keyword |
|
||||
| Core | `_yoast_wpseo_title` | Meta title |
|
||||
| Core | `_yoast_wpseo_metadesc` | Meta description |
|
||||
| Advanced | `_yoast_wpseo_canonical` | Canonical URL |
|
||||
| Advanced | `_yoast_wpseo_meta-robots-noindex` | Noindex setting |
|
||||
| Advanced | `_yoast_wpseo_meta-robots-nofollow` | Nofollow setting |
|
||||
| Advanced | `_yoast_wpseo_bctitle` | Breadcrumb title |
|
||||
| Open Graph | `_yoast_wpseo_opengraph-title` | OG title |
|
||||
| Open Graph | `_yoast_wpseo_opengraph-description` | OG description |
|
||||
| Open Graph | `_yoast_wpseo_opengraph-image` | OG image URL |
|
||||
| Open Graph | `_yoast_wpseo_opengraph-image-id` | OG image ID |
|
||||
| Twitter | `_yoast_wpseo_twitter-title` | Twitter title |
|
||||
| Twitter | `_yoast_wpseo_twitter-description` | Twitter description |
|
||||
| Twitter | `_yoast_wpseo_twitter-image` | Twitter image URL |
|
||||
| Twitter | `_yoast_wpseo_twitter-image-id` | Twitter image ID |
|
||||
|
||||
## Installation
|
||||
|
||||
### Method 1: Upload via WordPress Admin
|
||||
|
||||
1. Download `airano-mcp-seo-bridge.zip` from [Releases](https://github.com/airano-ir/mcphub)
|
||||
2. Go to WordPress Admin > Plugins > Add New > Upload Plugin
|
||||
3. Upload the ZIP file and click "Install Now"
|
||||
4. Click "Activate Plugin"
|
||||
|
||||
### Method 2: FTP/SSH Upload
|
||||
|
||||
1. Upload the `airano-mcp-seo-bridge` folder to `/wp-content/plugins/`
|
||||
2. Go to WordPress Admin > Plugins
|
||||
3. Find "Airano MCP SEO Bridge" and click "Activate"
|
||||
|
||||
### Method 3: WP-CLI
|
||||
|
||||
```bash
|
||||
cd /var/www/html/wp-content/plugins/
|
||||
# Copy the plugin folder here
|
||||
wp plugin activate airano-mcp-seo-bridge
|
||||
```
|
||||
|
||||
## REST API Endpoints
|
||||
|
||||
All endpoints require **WordPress Application Password** authentication.
|
||||
|
||||
### Status Endpoint
|
||||
|
||||
**GET** `/wp-json/airano-mcp-seo-bridge/v1/status`
|
||||
|
||||
```bash
|
||||
curl -X GET "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/status" \
|
||||
-u "username:application_password"
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"plugin": "SEO API Bridge",
|
||||
"version": "1.3.0",
|
||||
"active": true,
|
||||
"seo_plugins": {
|
||||
"rank_math": { "active": true, "version": "1.0.257" },
|
||||
"yoast": { "active": false, "version": null }
|
||||
},
|
||||
"supported_post_types": ["post", "page", "product"],
|
||||
"message": "SEO API Bridge is active and working with Rank Math SEO."
|
||||
}
|
||||
```
|
||||
|
||||
### Post SEO Endpoints
|
||||
|
||||
**GET** `/wp-json/airano-mcp-seo-bridge/v1/posts/{id}/seo` — Get SEO metadata for a post
|
||||
|
||||
**POST** `/wp-json/airano-mcp-seo-bridge/v1/posts/{id}/seo` — Update SEO metadata for a post
|
||||
|
||||
```bash
|
||||
# Get post SEO
|
||||
curl -X GET "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/posts/123/seo" \
|
||||
-u "username:application_password"
|
||||
|
||||
# Update post SEO
|
||||
curl -X POST "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/posts/123/seo" \
|
||||
-u "username:application_password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"focus_keyword": "wordpress", "seo_title": "My Title"}'
|
||||
```
|
||||
|
||||
### Page SEO Endpoints
|
||||
|
||||
**GET** `/wp-json/airano-mcp-seo-bridge/v1/pages/{id}/seo`
|
||||
|
||||
**POST** `/wp-json/airano-mcp-seo-bridge/v1/pages/{id}/seo`
|
||||
|
||||
### Product SEO Endpoints (WooCommerce)
|
||||
|
||||
**GET** `/wp-json/airano-mcp-seo-bridge/v1/products/{id}/seo`
|
||||
|
||||
**POST** `/wp-json/airano-mcp-seo-bridge/v1/products/{id}/seo`
|
||||
|
||||
```bash
|
||||
curl -X POST "https://yoursite.com/wp-json/airano-mcp-seo-bridge/v1/products/1217/seo" \
|
||||
-u "username:application_password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"focus_keyword": "product keyword", "seo_title": "Product Title"}'
|
||||
```
|
||||
|
||||
### Alternative: Standard WordPress REST API
|
||||
|
||||
The plugin also registers all SEO meta fields on standard WordPress REST API endpoints. You can read/write SEO data directly via:
|
||||
|
||||
- `GET/POST /wp-json/wp/v2/posts/{id}` — SEO fields in the `meta` object
|
||||
- `GET/POST /wp-json/wp/v2/pages/{id}`
|
||||
- `GET/POST /wp-json/wp/v2/products/{id}` (WooCommerce)
|
||||
|
||||
```bash
|
||||
# Read SEO fields via standard endpoint
|
||||
curl -X GET "https://yoursite.com/wp-json/wp/v2/posts/123" \
|
||||
-u "username:application_password"
|
||||
|
||||
# Update SEO via standard endpoint
|
||||
curl -X POST "https://yoursite.com/wp-json/wp/v2/posts/123" \
|
||||
-u "username:application_password" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"meta": {"rank_math_focus_keyword": "wordpress optimization"}}'
|
||||
```
|
||||
|
||||
## Usage with MCP Hub
|
||||
|
||||
This plugin is designed to work with [MCP Hub](https://github.com/airano-ir/mcphub).
|
||||
|
||||
```javascript
|
||||
// Get product SEO
|
||||
const seo = await mcp.wordpress_get_product_seo({
|
||||
site: "yoursite",
|
||||
product_id: 1217
|
||||
});
|
||||
|
||||
// Update product SEO
|
||||
await mcp.wordpress_update_product_seo({
|
||||
site: "yoursite",
|
||||
product_id: 1217,
|
||||
focus_keyword: "keyword",
|
||||
seo_title: "Title",
|
||||
meta_description: "Description"
|
||||
});
|
||||
```
|
||||
|
||||
```python
|
||||
# Get post SEO data
|
||||
result = await mcp.call_tool(
|
||||
"wordpress_get_post_seo",
|
||||
{"site": "yoursite", "post_id": 123}
|
||||
)
|
||||
|
||||
# Update post SEO
|
||||
result = await mcp.call_tool(
|
||||
"wordpress_update_post_seo",
|
||||
{
|
||||
"site": "yoursite",
|
||||
"post_id": 123,
|
||||
"focus_keyword": "wordpress seo",
|
||||
"seo_title": "Complete SEO Guide",
|
||||
"meta_description": "Learn WordPress SEO..."
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
1. **Admin Notice:** After activation, visit the Plugins page to see a status notice indicating which SEO plugin was detected.
|
||||
|
||||
2. **Status Endpoint:**
|
||||
```bash
|
||||
curl -X GET "https://your-site.com/wp-json/airano-mcp-seo-bridge/v1/status" \
|
||||
-u "username:application_password"
|
||||
```
|
||||
|
||||
3. **REST API Test:**
|
||||
```bash
|
||||
curl -X GET "https://your-site.com/wp-json/wp/v2/posts/1" \
|
||||
-u "username:application_password"
|
||||
```
|
||||
|
||||
4. **MCP Health Check:** The MCP server automatically detects the plugin using the status endpoint.
|
||||
|
||||
## Security
|
||||
|
||||
- All meta fields require authentication via Application Passwords
|
||||
- Write access requires `edit_posts` capability
|
||||
- Read access follows WordPress post visibility rules
|
||||
- No sensitive data exposed without proper permissions
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### MCP Server Cannot Detect Plugin
|
||||
|
||||
1. Upgrade to v1.1.0+ (has dedicated health check endpoint)
|
||||
2. Restart MCP server
|
||||
3. Test endpoint: `curl "https://your-site.com/wp-json/airano-mcp-seo-bridge/v1/status" -u "user:pass"`
|
||||
|
||||
### SEO Plugin Not Detected
|
||||
|
||||
1. Verify Rank Math or Yoast SEO is installed and activated
|
||||
2. Deactivate and reactivate SEO API Bridge
|
||||
3. Check PHP error logs for warnings
|
||||
|
||||
### Meta Fields Not Appearing in REST API
|
||||
|
||||
1. Ensure you're authenticated (use Application Password)
|
||||
2. Check user has `edit_posts` permission
|
||||
3. Verify the post type is supported (post, page, product)
|
||||
|
||||
## Compatibility
|
||||
|
||||
- WordPress 5.0+
|
||||
- PHP 7.4+
|
||||
- Rank Math SEO 1.0+
|
||||
- Yoast SEO 14.0+
|
||||
- WooCommerce 5.0+ (for product support)
|
||||
- Classic Editor & Gutenberg
|
||||
- Multisite compatible
|
||||
|
||||
## Changelog
|
||||
|
||||
### 1.3.0 (2025-02-18)
|
||||
- Added REST API endpoints for posts, pages, and products (GET/POST operations)
|
||||
- Added authentication requirement for all endpoints
|
||||
- Fixed `rank_math_title` meta key registration
|
||||
- Fixed output escaping for WordPress.org compliance
|
||||
|
||||
### 1.2.0 (2025-02-15)
|
||||
- Enhanced WooCommerce product support
|
||||
- Improved MariaDB compatibility for meta field queries
|
||||
|
||||
### 1.1.0 (2025-01-10)
|
||||
- Added health check REST API endpoint `/airano-mcp-seo-bridge/v1/status`
|
||||
- Direct plugin detection without requiring posts/products
|
||||
- Better compatibility with sites that have no content
|
||||
- Returns SEO plugin versions in status endpoint
|
||||
|
||||
### 1.0.0 (2025-01-10)
|
||||
- Initial release
|
||||
- Rank Math SEO support (15 meta fields)
|
||||
- Yoast SEO support (15 meta fields)
|
||||
- WooCommerce product support
|
||||
- Auto-detection of active SEO plugins
|
||||
|
||||
## Support
|
||||
|
||||
- **Plugin issues:** [GitHub Issues](https://github.com/airano-ir/mcphub/issues)
|
||||
- **MCP Server:** [MCP Hub Documentation](https://github.com/airano-ir/mcphub)
|
||||
- **Rank Math SEO:** [Rank Math Support](https://rankmath.com/support/)
|
||||
- **Yoast SEO:** [Yoast Support](https://yoast.com/help/)
|
||||
|
||||
## License
|
||||
|
||||
GPLv2 or later - See [LICENSE](https://www.gnu.org/licenses/gpl-2.0.html) for details
|
||||
@@ -1,82 +0,0 @@
|
||||
=== Airano MCP SEO Meta Bridge ===
|
||||
Contributors: airano
|
||||
Tags: seo, rest-api, rank-math, yoast, mcp
|
||||
Requires at least: 5.0
|
||||
Tested up to: 6.9
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 1.3.0
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Exposes Rank Math SEO and Yoast SEO meta fields via WordPress REST API for use with MCP servers and AI agents.
|
||||
|
||||
== Description ==
|
||||
|
||||
Airano MCP SEO Bridge is a WordPress plugin that exposes Rank Math SEO and Yoast SEO meta fields via dedicated REST API endpoints. This enables MCP servers, AI agents, and other applications to read and write SEO metadata programmatically for posts, pages, and WooCommerce products.
|
||||
|
||||
**Features:**
|
||||
|
||||
* **Rank Math SEO Support** — Full access to all Rank Math meta fields
|
||||
* **Yoast SEO Support** — Full access to all Yoast SEO meta fields
|
||||
* **WooCommerce Compatible** — Works with product post types
|
||||
* **Secure** — Requires WordPress Application Password and edit_posts capability
|
||||
* **Auto-Detection** — Automatically detects which SEO plugin is active
|
||||
* **Status Endpoint** — Dedicated API endpoint for plugin and SEO detection
|
||||
* **Zero Configuration** — Works out of the box after activation
|
||||
|
||||
**REST API Endpoints:**
|
||||
|
||||
* `GET/POST /wp-json/airano-mcp-seo-bridge/v1/posts/{id}/seo` — Post SEO data
|
||||
* `GET/POST /wp-json/airano-mcp-seo-bridge/v1/pages/{id}/seo` — Page SEO data
|
||||
* `GET/POST /wp-json/airano-mcp-seo-bridge/v1/products/{id}/seo` — Product SEO data (WooCommerce)
|
||||
* `GET /wp-json/airano-mcp-seo-bridge/v1/status` — Plugin status and SEO detection
|
||||
|
||||
**Designed for [MCP Hub](https://github.com/airano-ir/mcphub)** — the AI-native management hub for WordPress and self-hosted services.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the `airano-mcp-seo-bridge` folder to `/wp-content/plugins/`
|
||||
2. Activate the plugin through the 'Plugins' menu in WordPress
|
||||
3. Ensure either Rank Math SEO or Yoast SEO is active
|
||||
4. The REST API endpoints are now available
|
||||
|
||||
== Frequently Asked Questions ==
|
||||
|
||||
= Which SEO plugins are supported? =
|
||||
|
||||
Rank Math SEO and Yoast SEO. The plugin auto-detects which one is active.
|
||||
|
||||
= Does it work with WooCommerce? =
|
||||
|
||||
Yes. Product SEO endpoints are available when WooCommerce is active.
|
||||
|
||||
= How is authentication handled? =
|
||||
|
||||
All endpoints require WordPress Application Password authentication and the `edit_posts` capability. POST requests require the same capability.
|
||||
|
||||
= Can I use this without MCP Hub? =
|
||||
|
||||
Yes. The REST API endpoints work with any application that can make HTTP requests with proper WordPress authentication.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 1.3.0 =
|
||||
* Added REST API endpoints for posts, pages, and products (GET/POST operations)
|
||||
* Added authentication requirement for all endpoints
|
||||
* Fixed rank_math_title meta key registration
|
||||
|
||||
= 1.2.0 =
|
||||
* Enhanced WooCommerce product support
|
||||
* Improved MariaDB compatibility
|
||||
|
||||
= 1.1.0 =
|
||||
* Added status endpoint for plugin detection
|
||||
* Improved error handling
|
||||
|
||||
= 1.0.0 =
|
||||
* Initial release with Rank Math and Yoast SEO support
|
||||
|
||||
== Upgrade Notice ==
|
||||
|
||||
= 1.3.0 =
|
||||
GET endpoints now require authentication (edit_posts capability). Update your API clients if needed.
|
||||
@@ -1,715 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: Airano MCP SEO Meta Bridge
|
||||
* Plugin URI: https://github.com/airano-ir/mcphub
|
||||
* Description: Exposes Rank Math SEO and Yoast SEO meta fields via WordPress REST API for use with MCP servers and AI agents. Supports posts, pages, and WooCommerce products with full CRUD operations.
|
||||
* Version: 1.3.0
|
||||
* Author: MCP Hub
|
||||
* Author URI: https://github.com/airano-ir
|
||||
* License: GPL-2.0-or-later
|
||||
* Requires at least: 5.0
|
||||
* Requires PHP: 7.4
|
||||
* Text Domain: airano-mcp-seo-bridge
|
||||
*
|
||||
* Changelog:
|
||||
* 1.3.0 - Added REST API endpoints for posts, pages, and products (GET/POST operations)
|
||||
* 1.2.0 - Enhanced WooCommerce product support, improved MariaDB compatibility
|
||||
* 1.1.0 - Added status endpoint and improved plugin detection
|
||||
* 1.0.0 - Initial release
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Airano MCP SEO Meta Bridge Main Class
|
||||
*/
|
||||
class SEO_API_Bridge {
|
||||
|
||||
/**
|
||||
* Plugin version
|
||||
*/
|
||||
const VERSION = '1.3.0';
|
||||
|
||||
/**
|
||||
* Supported post types
|
||||
*/
|
||||
private $supported_post_types = ['post', 'page', 'product'];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action('rest_api_init', [$this, 'register_meta_fields']);
|
||||
add_action('rest_api_init', [$this, 'register_rest_routes']);
|
||||
add_action('admin_notices', [$this, 'admin_notices']);
|
||||
|
||||
// Add product support message if WooCommerce is active
|
||||
if ($this->is_woocommerce_active()) {
|
||||
$this->supported_post_types[] = 'product_variation'; // Also support variations
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register REST API routes
|
||||
*/
|
||||
public function register_rest_routes() {
|
||||
// Status endpoint
|
||||
register_rest_route('airano-mcp-seo-bridge/v1', '/status', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_status'],
|
||||
'permission_callback' => function() {
|
||||
return is_user_logged_in();
|
||||
}
|
||||
]);
|
||||
|
||||
// Post SEO endpoints
|
||||
register_rest_route('airano-mcp-seo-bridge/v1', '/posts/(?P<id>\d+)/seo', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_post_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'update_post_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
// Page SEO endpoints
|
||||
register_rest_route('airano-mcp-seo-bridge/v1', '/pages/(?P<id>\d+)/seo', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_page_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'update_page_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_pages');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
// Product SEO endpoints (WooCommerce)
|
||||
register_rest_route('airano-mcp-seo-bridge/v1', '/products/(?P<id>\d+)/seo', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_product_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
],
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'update_product_seo'],
|
||||
'permission_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
},
|
||||
'args' => [
|
||||
'id' => [
|
||||
'validate_callback' => function($param) {
|
||||
return is_numeric($param);
|
||||
}
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plugin status endpoint
|
||||
*/
|
||||
public function get_status() {
|
||||
$rank_math_active = $this->is_rank_math_active();
|
||||
$yoast_active = $this->is_yoast_active();
|
||||
|
||||
$response = [
|
||||
'plugin' => 'Airano MCP SEO Meta Bridge',
|
||||
'version' => self::VERSION,
|
||||
'active' => true,
|
||||
'seo_plugins' => [
|
||||
'rank_math' => [
|
||||
'active' => $rank_math_active,
|
||||
'version' => $rank_math_active && defined('RANK_MATH_VERSION') ? RANK_MATH_VERSION : null
|
||||
],
|
||||
'yoast' => [
|
||||
'active' => $yoast_active,
|
||||
'version' => $yoast_active && defined('WPSEO_VERSION') ? WPSEO_VERSION : null
|
||||
]
|
||||
],
|
||||
'supported_post_types' => $this->supported_post_types,
|
||||
'message' => $this->get_status_message($rank_math_active, $yoast_active)
|
||||
];
|
||||
|
||||
return rest_ensure_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get status message based on active plugins
|
||||
*/
|
||||
private function get_status_message($rank_math_active, $yoast_active) {
|
||||
if (!$rank_math_active && !$yoast_active) {
|
||||
return 'No SEO plugin detected. Please install and activate Rank Math SEO or Yoast SEO.';
|
||||
}
|
||||
|
||||
$active_plugins = [];
|
||||
if ($rank_math_active) $active_plugins[] = 'Rank Math SEO';
|
||||
if ($yoast_active) $active_plugins[] = 'Yoast SEO';
|
||||
|
||||
return 'Airano MCP SEO Meta Bridge is active and working with ' . implode(' and ', $active_plugins) . '.';
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all meta fields for REST API
|
||||
*/
|
||||
public function register_meta_fields() {
|
||||
// Register Rank Math fields if plugin is active
|
||||
if ($this->is_rank_math_active()) {
|
||||
$this->register_rank_math_fields();
|
||||
}
|
||||
|
||||
// Register Yoast SEO fields if plugin is active
|
||||
if ($this->is_yoast_active()) {
|
||||
$this->register_yoast_fields();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Rank Math is active
|
||||
*/
|
||||
private function is_rank_math_active() {
|
||||
return defined('RANK_MATH_VERSION') || class_exists('RankMath');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Yoast SEO is active
|
||||
*/
|
||||
private function is_yoast_active() {
|
||||
return defined('WPSEO_VERSION') || class_exists('WPSEO_Options');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if WooCommerce is active
|
||||
*/
|
||||
private function is_woocommerce_active() {
|
||||
return class_exists('WooCommerce') || defined('WC_VERSION');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Rank Math meta fields
|
||||
*/
|
||||
private function register_rank_math_fields() {
|
||||
$rank_math_fields = [
|
||||
// Core SEO Fields
|
||||
'rank_math_focus_keyword' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math focus keyword',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math SEO title (meta title)',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_description' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math meta description',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Additional Keywords
|
||||
'rank_math_additional_keywords' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math additional keywords (comma-separated)',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Advanced Fields
|
||||
'rank_math_canonical_url' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math canonical URL',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_robots' => [
|
||||
'type' => 'array',
|
||||
'description' => 'Rank Math robots meta (noindex, nofollow, etc.)',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_breadcrumb_title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math breadcrumb title',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Open Graph Fields
|
||||
'rank_math_facebook_title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Facebook Open Graph title',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_facebook_description' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Facebook Open Graph description',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_facebook_image' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Facebook Open Graph image URL',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_facebook_image_id' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Rank Math Facebook Open Graph image ID',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Twitter Card Fields
|
||||
'rank_math_twitter_title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Twitter Card title',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_twitter_description' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Twitter Card description',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_twitter_image' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Twitter Card image URL',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_twitter_image_id' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Rank Math Twitter Card image ID',
|
||||
'single' => true,
|
||||
],
|
||||
'rank_math_twitter_card_type' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Rank Math Twitter Card type (summary, summary_large_image)',
|
||||
'single' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$this->register_fields($rank_math_fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Yoast SEO meta fields
|
||||
*/
|
||||
private function register_yoast_fields() {
|
||||
$yoast_fields = [
|
||||
// Core SEO Fields
|
||||
'_yoast_wpseo_focuskw' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO focus keyword',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO title (meta title)',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_metadesc' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO meta description',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Advanced Fields
|
||||
'_yoast_wpseo_canonical' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO canonical URL',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_meta-robots-noindex' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO noindex setting (0 = index, 1 = noindex)',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_meta-robots-nofollow' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO nofollow setting (0 = follow, 1 = nofollow)',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_bctitle' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO breadcrumb title',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Open Graph Fields
|
||||
'_yoast_wpseo_opengraph-title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Open Graph title',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_opengraph-description' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Open Graph description',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_opengraph-image' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Open Graph image URL',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_opengraph-image-id' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Yoast SEO Open Graph image ID',
|
||||
'single' => true,
|
||||
],
|
||||
|
||||
// Twitter Card Fields
|
||||
'_yoast_wpseo_twitter-title' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Twitter title',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_twitter-description' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Twitter description',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_twitter-image' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Yoast SEO Twitter image URL',
|
||||
'single' => true,
|
||||
],
|
||||
'_yoast_wpseo_twitter-image-id' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Yoast SEO Twitter image ID',
|
||||
'single' => true,
|
||||
],
|
||||
];
|
||||
|
||||
$this->register_fields($yoast_fields);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register fields for all supported post types
|
||||
*/
|
||||
private function register_fields($fields) {
|
||||
foreach ($this->supported_post_types as $post_type) {
|
||||
foreach ($fields as $meta_key => $args) {
|
||||
$show_in_rest = $args['type'] === 'array'
|
||||
? [ 'schema' => [ 'type' => 'array', 'items' => [ 'type' => 'string' ] ] ]
|
||||
: true;
|
||||
|
||||
register_post_meta($post_type, $meta_key, [
|
||||
'show_in_rest' => $show_in_rest,
|
||||
'single' => $args['single'],
|
||||
'type' => $args['type'],
|
||||
'description' => $args['description'],
|
||||
'auth_callback' => function() {
|
||||
return current_user_can('edit_posts');
|
||||
}
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SEO data for a post
|
||||
*/
|
||||
public function get_post_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->get_seo_data($post_id, 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update SEO data for a post
|
||||
*/
|
||||
public function update_post_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->update_seo_data($post_id, $request->get_json_params(), 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SEO data for a page
|
||||
*/
|
||||
public function get_page_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->get_seo_data($post_id, 'page');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update SEO data for a page
|
||||
*/
|
||||
public function update_page_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->update_seo_data($post_id, $request->get_json_params(), 'page');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SEO data for a product
|
||||
*/
|
||||
public function get_product_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->get_seo_data($post_id, 'product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update SEO data for a product
|
||||
*/
|
||||
public function update_product_seo($request) {
|
||||
$post_id = $request['id'];
|
||||
return $this->update_seo_data($post_id, $request->get_json_params(), 'product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method to get SEO data
|
||||
*/
|
||||
private function get_seo_data($post_id, $post_type) {
|
||||
// Verify post exists and is correct type
|
||||
$post = get_post($post_id);
|
||||
if (!$post || $post->post_type !== $post_type) {
|
||||
return new WP_Error(
|
||||
'invalid_post',
|
||||
sprintf('%s not found', ucfirst($post_type)),
|
||||
['status' => 404]
|
||||
);
|
||||
}
|
||||
|
||||
$seo_data = [
|
||||
'post_id' => $post_id,
|
||||
'post_type' => $post_type,
|
||||
'post_title' => $post->post_title,
|
||||
];
|
||||
|
||||
// Detect which SEO plugin is active and get data
|
||||
if ($this->is_rank_math_active()) {
|
||||
$seo_data['plugin'] = 'rank_math';
|
||||
$seo_data = array_merge($seo_data, $this->get_rank_math_data($post_id));
|
||||
} elseif ($this->is_yoast_active()) {
|
||||
$seo_data['plugin'] = 'yoast';
|
||||
$seo_data = array_merge($seo_data, $this->get_yoast_data($post_id));
|
||||
} else {
|
||||
return new WP_Error(
|
||||
'no_seo_plugin',
|
||||
'No supported SEO plugin found (Rank Math or Yoast required)',
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
return rest_ensure_response($seo_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Rank Math SEO data
|
||||
*/
|
||||
private function get_rank_math_data($post_id) {
|
||||
return [
|
||||
'focus_keyword' => get_post_meta($post_id, 'rank_math_focus_keyword', true),
|
||||
'seo_title' => get_post_meta($post_id, 'rank_math_title', true),
|
||||
'meta_description' => get_post_meta($post_id, 'rank_math_description', true),
|
||||
'canonical_url' => get_post_meta($post_id, 'rank_math_canonical_url', true),
|
||||
'robots' => get_post_meta($post_id, 'rank_math_robots', true),
|
||||
'og_title' => get_post_meta($post_id, 'rank_math_facebook_title', true),
|
||||
'og_description' => get_post_meta($post_id, 'rank_math_facebook_description', true),
|
||||
'og_image' => get_post_meta($post_id, 'rank_math_facebook_image', true),
|
||||
'twitter_title' => get_post_meta($post_id, 'rank_math_twitter_title', true),
|
||||
'twitter_description' => get_post_meta($post_id, 'rank_math_twitter_description', true),
|
||||
'twitter_image' => get_post_meta($post_id, 'rank_math_twitter_image', true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Yoast SEO data
|
||||
*/
|
||||
private function get_yoast_data($post_id) {
|
||||
return [
|
||||
'focus_keyword' => get_post_meta($post_id, '_yoast_wpseo_focuskw', true),
|
||||
'seo_title' => get_post_meta($post_id, '_yoast_wpseo_title', true),
|
||||
'meta_description' => get_post_meta($post_id, '_yoast_wpseo_metadesc', true),
|
||||
'canonical_url' => get_post_meta($post_id, '_yoast_wpseo_canonical', true),
|
||||
'noindex' => get_post_meta($post_id, '_yoast_wpseo_meta-robots-noindex', true),
|
||||
'nofollow' => get_post_meta($post_id, '_yoast_wpseo_meta-robots-nofollow', true),
|
||||
'og_title' => get_post_meta($post_id, '_yoast_wpseo_opengraph-title', true),
|
||||
'og_description' => get_post_meta($post_id, '_yoast_wpseo_opengraph-description', true),
|
||||
'og_image' => get_post_meta($post_id, '_yoast_wpseo_opengraph-image', true),
|
||||
'twitter_title' => get_post_meta($post_id, '_yoast_wpseo_twitter-title', true),
|
||||
'twitter_description' => get_post_meta($post_id, '_yoast_wpseo_twitter-description', true),
|
||||
'twitter_image' => get_post_meta($post_id, '_yoast_wpseo_twitter-image', true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method to update SEO data
|
||||
*/
|
||||
private function update_seo_data($post_id, $params, $post_type) {
|
||||
// Verify post exists and is correct type
|
||||
$post = get_post($post_id);
|
||||
if (!$post || $post->post_type !== $post_type) {
|
||||
return new WP_Error(
|
||||
'invalid_post',
|
||||
sprintf('%s not found', ucfirst($post_type)),
|
||||
['status' => 404]
|
||||
);
|
||||
}
|
||||
|
||||
$updated_fields = [];
|
||||
|
||||
// Update based on active SEO plugin
|
||||
if ($this->is_rank_math_active()) {
|
||||
$updated_fields = $this->update_rank_math_data($post_id, $params);
|
||||
} elseif ($this->is_yoast_active()) {
|
||||
$updated_fields = $this->update_yoast_data($post_id, $params);
|
||||
} else {
|
||||
return new WP_Error(
|
||||
'no_seo_plugin',
|
||||
'No supported SEO plugin found',
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
return rest_ensure_response([
|
||||
'post_id' => $post_id,
|
||||
'post_type' => $post_type,
|
||||
'updated_fields' => $updated_fields,
|
||||
'message' => 'SEO metadata updated successfully'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Rank Math data
|
||||
*/
|
||||
private function update_rank_math_data($post_id, $params) {
|
||||
$updated = [];
|
||||
$field_map = [
|
||||
'focus_keyword' => 'rank_math_focus_keyword',
|
||||
'seo_title' => 'rank_math_title',
|
||||
'meta_description' => 'rank_math_description',
|
||||
'canonical_url' => 'rank_math_canonical_url',
|
||||
'robots' => 'rank_math_robots',
|
||||
'og_title' => 'rank_math_facebook_title',
|
||||
'og_description' => 'rank_math_facebook_description',
|
||||
'og_image' => 'rank_math_facebook_image',
|
||||
'twitter_title' => 'rank_math_twitter_title',
|
||||
'twitter_description' => 'rank_math_twitter_description',
|
||||
'twitter_image' => 'rank_math_twitter_image',
|
||||
];
|
||||
|
||||
foreach ($field_map as $param_key => $meta_key) {
|
||||
if (isset($params[$param_key])) {
|
||||
update_post_meta($post_id, $meta_key, $params[$param_key]);
|
||||
$updated[] = $meta_key;
|
||||
}
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Yoast data
|
||||
*/
|
||||
private function update_yoast_data($post_id, $params) {
|
||||
$updated = [];
|
||||
$field_map = [
|
||||
'focus_keyword' => '_yoast_wpseo_focuskw',
|
||||
'seo_title' => '_yoast_wpseo_title',
|
||||
'meta_description' => '_yoast_wpseo_metadesc',
|
||||
'canonical_url' => '_yoast_wpseo_canonical',
|
||||
'og_title' => '_yoast_wpseo_opengraph-title',
|
||||
'og_description' => '_yoast_wpseo_opengraph-description',
|
||||
'og_image' => '_yoast_wpseo_opengraph-image',
|
||||
'twitter_title' => '_yoast_wpseo_twitter-title',
|
||||
'twitter_description' => '_yoast_wpseo_twitter-description',
|
||||
'twitter_image' => '_yoast_wpseo_twitter-image',
|
||||
];
|
||||
|
||||
foreach ($field_map as $param_key => $meta_key) {
|
||||
if (isset($params[$param_key])) {
|
||||
update_post_meta($post_id, $meta_key, $params[$param_key]);
|
||||
$updated[] = $meta_key;
|
||||
}
|
||||
}
|
||||
|
||||
return $updated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display admin notices
|
||||
*/
|
||||
public function admin_notices() {
|
||||
// Only show notices on the Plugins page to avoid clutter on every admin page
|
||||
$screen = get_current_screen();
|
||||
if ( ! $screen || $screen->id !== 'plugins' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$rank_math_active = $this->is_rank_math_active();
|
||||
$yoast_active = $this->is_yoast_active();
|
||||
$woocommerce_active = $this->is_woocommerce_active();
|
||||
|
||||
if (!$rank_math_active && !$yoast_active) {
|
||||
echo '<div class="notice notice-warning is-dismissible">';
|
||||
echo '<p><strong>Airano MCP SEO Meta Bridge:</strong> ' . esc_html__( 'Neither Rank Math SEO nor Yoast SEO is detected. Please install and activate one of these plugins to enable SEO meta field access via REST API.', 'airano-mcp-seo-bridge' ) . '</p>';
|
||||
echo '</div>';
|
||||
} else {
|
||||
$active_plugins = [];
|
||||
if ($rank_math_active) $active_plugins[] = 'Rank Math SEO';
|
||||
if ($yoast_active) $active_plugins[] = 'Yoast SEO';
|
||||
|
||||
$supported_types = implode(', ', $this->supported_post_types);
|
||||
|
||||
echo '<div class="notice notice-success is-dismissible">';
|
||||
echo '<p><strong>Airano MCP SEO Meta Bridge v' . esc_html( self::VERSION ) . ':</strong> ' . esc_html( sprintf( 'Successfully registered meta fields for %s.', implode( ' and ', $active_plugins ) ) ) . '</p>';
|
||||
echo '<p><strong>' . esc_html__( 'Supported post types:', 'airano-mcp-seo-bridge' ) . '</strong> ' . esc_html( $supported_types ) . '</p>';
|
||||
|
||||
if ($woocommerce_active) {
|
||||
echo '<p><strong>WooCommerce:</strong> ' . esc_html__( 'Detected and supported. Product SEO fields are available via REST API.', 'airano-mcp-seo-bridge' ) . '</p>';
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the plugin
|
||||
new SEO_API_Bridge();
|
||||
Reference in New Issue
Block a user