DirectRelay Automation Bridge for n8n

Description

DirectRelay Automation Bridge for n8n turns any WordPress site into a first-class REST API target that n8n workflows, Make scenarios, Zapier zaps, custom AI agents and your own scripts can talk to — with the keys, scopes and security model that production automation actually demands.

It is the only free WordPress automation plugin that ships all four at once: a scoped REST API surface (32 endpoints under /wp-json/directrelay-automation-bridge-for-n8n/v1/), HMAC-signed outgoing webhooks with retry, native reads of Rank Math and Yoast SEO fields, and a self-describing OpenAPI 3.0 spec that lets the n8n HTTP Request node auto-fill every request shape. No purchase code. No license key. No trial period. No feature lock. Every feature listed on this page is fully functional in the free build and always will be.

Why n8n users pick DirectRelay

  • OpenAPI 3.0 spec at /wp-json/directrelay-automation-bridge-for-n8n/v1/openapi.json — paste it into n8n’s HTTP Request node and every field, scope and response shape fills itself. No manual mapping.
  • Rank Math + Yoast SEO reads in one callGET /posts/{id}/seo returns focus keyword, SEO title, meta description, canonical URL and OpenGraph fields from whichever SEO plugin you have active. The community n8n-nodes-wordpress node can’t do this.
  • Scoped API keys, not WordPress Application Passwords — generate a key that can only read posts, only publish to a specific CPT, or only fire webhooks. Per-key IP allowlist, expiry and rotation are built in. Revoke one key without touching the others.
  • Bidirectional, not one-way — REST reads and HMAC-SHA256 signed outgoing webhooks on the same install. Most alternatives do only one direction.
  • 100% GPL, no telemetry, no license server — what you install is what runs. No phone-home, no purchase-code check, no usage caps.

Everything in the free plugin

REST API endpoints (32 routes)
* Posts — list, get, publish, bulk publish (single call writes post + featured image + SEO + categories + tags).
* Pages — list and get.
* Media — list, sideload from URL, get.
* Taxonomies — categories and tags.
* Custom meta — list all, get/delete by key (works with ACF, Pods, custom fields).
* SEO read — GET /{type}/{id}/seo returns Rank Math or Yoast fields automatically.
* Discovery — /discovery/fields and /discovery/post-types for schema reflection.
* Webhooks — CRUD + test + delivery log + usage stats + ready-made presets.
* API keys — list, rotate, revoke.
* System — /status, /ping, /cron-health, /blocked-ips.
* Fleet — /fleet/health and /fleet/keys/provision for multi-site monitoring.
* OpenAPI — /openapi.json and /openapi for self-describing discovery.

Security and production hardening
* Scoped API keys with 16+ scope types (posts:read, posts:write, posts:publish, posts:delete, media:write, webhooks:write, etc.).
* Five preset roles (readonly, writer, editor, publisher, full_access) plus custom scope bundles.
* Per-key IP allowlist (single IP or CIDR ranges).
* Per-key expiration date (auto-revoke after).
* Automatic key rotation policy (configurable days; n8n-friendly grace period).
* Keys are stored as salted hashes — the database leak cannot expose live keys.
* Timing-safe comparison (hash_equals) — immune to timing side channels.
* Sliding-window rate limiter — configurable per-IP + per-key, prevents burst abuse.
* Brute-force protection with escalating IP block (5 min 30 min 2 hr 24 hr).
* HMAC-SHA256 signed outgoing webhooks with X-DirectRelay-Signature header and replay protection via timestamp window.

Outgoing webhooks
* Dispatch signed JSON to any HTTP endpoint — n8n webhook, Make hook, Zapier catch hook, custom AI agent.
* Event filtering by post type, status transition, taxonomy.
* Automatic retry with exponential backoff.
* Last 50 deliveries per webhook (status code, response time, request body).
* Built-in “Send test event” button from the admin UI.
* Ready-made presets for post.published, post.updated, post.deleted, page.published.

AI and SEO integrations
* Rank Math field reads: focus keyword, SEO title, description, canonical URL, pillar content flag, robots flags.
* Yoast SEO field reads: focus keyword, SEO title, meta description, canonical URL, OpenGraph title and description.
* IndexNow auto-ping on every publish/update — instant indexing on Bing, Yandex, Naver and Seznam. No cron job needed.
* OpenAI-compatible response shape — all endpoints return JSON that the n8n OpenAI/HTTP nodes parse without transformation.

Operations
* Activity log — last 100 API calls and webhook deliveries, plain text, filterable by event type.
* Email notifications — admin gets pinged on every webhook failure with the failed payload attached.
* Compatibility checker — verifies permalinks, REST API, SSL, Rank Math / Yoast presence, PHP version, WP-Cron health.
* Cron health monitor — alerts if WP-Cron is more than 15 min behind.
* n8n starter template — one copy-paste workflow that proves the connection in under 60 seconds.
* Side-load media from URL — POST /media/sideload with an image URL and DirectRelay downloads, attaches and returns the WP media ID.
* Custom Post Type support — auto-discovered, no extra config.
* GDPR-friendly — zero outbound traffic by default. Every external service is an explicit opt-in.

Real workflows you can build today

  • AI writer pipeline — n8n fires on a schedule calls OpenAI to draft an article POST /posts with title, content, Rank Math SEO and a featured image URL in a single request IndexNow auto-pings Bing webhook back to n8n notifies your Slack.
  • Multi-site fleet manager — Central n8n instance pings /fleet/health on 20 WordPress sites every 5 min. If any return cron_degraded, n8n opens a PagerDuty incident.
  • Headless CMS front-end — Next.js or Astro reads posts via GET /posts?per_page=100&status=publish, renders the site. Writers use the regular WP admin to edit.
  • Lead-magnet auto-publisher — Webflow form submits n8n reads the data POST /posts with a draft pre-filled with the lead’s company name editorial team gets a Slack notification with a one-click approve link.

DirectRelay vs the alternatives

Rank Math / Yoast SEO field reads
* DirectRelay: Yes, both (Rank Math + Yoast auto-detected)
* WP REST + Application Password: No
* n8n-nodes-wordpress (community): No
* WP Webhooks: No

Per-route API scopes
* DirectRelay: Yes, 16+ scopes (posts:read, posts:write, media:write, etc.)
* WP REST + Application Password: No (always full account access)
* n8n-nodes-wordpress (community): No
* WP Webhooks: No

HMAC-signed outgoing webhooks
* DirectRelay: Yes (HMAC-SHA256, replay-protection timestamp)
* WP REST + Application Password: No
* n8n-nodes-wordpress (community): No
* WP Webhooks: Yes (basic)

OpenAPI 3.0 auto-discovery
* DirectRelay: Yes (/openapi.json so the n8n HTTP Request node auto-fills request shapes)
* WP REST + Application Password: No
* n8n-nodes-wordpress (community): No
* WP Webhooks: No

Outgoing webhooks with retry
* DirectRelay: Yes (exponential backoff, delivery log, test event)
* WP REST + Application Password: No
* n8n-nodes-wordpress (community): No
* WP Webhooks: Yes

Per-credential IP allowlist
* DirectRelay: Yes (single IP or CIDR)
* WP REST + Application Password: No
* n8n-nodes-wordpress (community): No
* WP Webhooks: No

Pricing model
* DirectRelay: 100% free, GPL, no upsell, no trial
* WP REST + Application Password: 100% free (core WordPress)
* n8n-nodes-wordpress (community): 100% free (community node)
* WP Webhooks: Freemium (paid add-ons)

Privacy and licence — no trialware, ever

DirectRelay is free software released under the GPL-2.0+ licence. You can use it, study it, modify it and redistribute it under the same terms.

The free plugin distributed on WordPress.org does not perform purchase-code validation, license-server activation, or any third-party license check. There is no purchase code, license key or activation token collected, stored, transmitted or required to use any feature of the free plugin. License management for the optional add-on is provided by the separate DirectRelay Pro add-on plugin distributed from directrelay.wikiofautomation.com/directrelay-pro — Pro is never distributed via WordPress.org and is never required.

Pro Features (separate add-on plugin)

The following features are provided by the DirectRelay Pro add-on plugin, distributed from https://directrelay.wikiofautomation.com/directrelay-pro. None of this code ships in the WordPress.org zip.

  • SEO Metadata Write (focus keyword, title, description for Rank Math and Yoast SEO).
  • Bulk Publish Endpoint (up to 50 items per request).
  • Universal Schema Publish (schema-driven publish from any JSON shape).
  • One-Shot Publish (atomic single-call create with media and SEO).
  • Human Approval Portal (signed review URLs, approve/reject workflow, multi-reviewer chains).
  • AI Guardrails (duplicate-title detection, AI-leakage scrubbing, blocked-phrase filter).
  • Full Debugger (50-entry replay, payload inspection, dry-run mode).
  • Chart.js Analytics Dashboard (call volume, error rate, latency trends, per-key breakdown).
  • n8n Template Library (AI writer, multilingual publisher, research approval pipelines).
  • Dark Mode for the plugin admin screens.

External services

This plugin supports optional integrations with external services. The services and their data handling policies are outlined below. All transmissions are initiated by the plugin only when the administrator has explicitly enabled the relevant feature; no data is sent silently or by default.

The free plugin distributed on WordPress.org does NOT use the following services: Envato/CodeCanyon purchase-code validation, license-server activation, or any third-party license check. There is no purchase code, license key, or activation token collected, stored, transmitted, or required to use any feature of the free plugin. (License management is provided by the separate DirectRelay Pro add-on plugin distributed from directrelay.wikiofautomation.com/directrelay-pro.)

n8n Webhooks (outgoing)

  • What it is and what it is used for: DirectRelay dispatches signed JSON payloads to user-configured webhook URLs when WordPress post events occur. The webhook receiver can be n8n, Make, an AI agent, or any other HTTP endpoint the administrator chooses.
  • What data is sent and when: The configured webhook target URL receives the post ID, title, content excerpt, status, taxonomies, and read-only SEO fields. Transmission only happens when the administrator has created an active webhook rule and the corresponding post event fires.
  • Service Terms & Privacy:
    • The webhook receiver is the user’s choice; DirectRelay itself does not transmit data to any third party by default.
    • n8n (optional) Terms: https://n8n.io/legal/self-serve-terms/
    • n8n (optional) Privacy: https://n8n.io/legal/

IndexNow

  • What it is and what it is used for: Submits updated post URLs directly to search engines (Bing, Yandex, Seznam) for instant indexing when content is published or updated.
  • What data is sent and when: Sends the site hostname, the API key the administrator configured, and the modified post URL. Transmitted only when the administrator enables IndexNow in plugin settings and a post is published or updated.
  • Service Terms & Privacy:
    • IndexNow Terms: https://www.indexnow.org/
    • IndexNow Privacy: https://privacy.microsoft.com/en-us/privacystatement

Cloudflare API (optional)

  • What it is and what it is used for: When a site administrator has configured a Cloudflare integration, the plugin can purge the Cloudflare edge cache for specific URLs after a WordPress post event.
  • What data is sent and when: Sends the user-configured Cloudflare Zone ID, the user-provided API bearer token, and the specific post URLs to purge. Transmitted only when configured by the site administrator in outgoing webhook actions.
  • Service Terms & Privacy:
    • Cloudflare Terms: https://www.cloudflare.com/website-terms/
    • Cloudflare Privacy: https://www.cloudflare.com/privacypolicy/

Third-Party AI APIs in n8n Workflow Templates (DeepSeek, Moonshot AI / Kimi, Alibaba Qwen)

  • What it is and what it is used for: The Pro add-on plugin (separate download) ships copyable n8n workflow templates that demonstrate external AI models feeding WordPress via n8n. The free plugin itself does not call any third-party AI service directly; it only provides the REST endpoints that the n8n workflow calls.
  • What data is sent and when: No data is transmitted directly by the WordPress plugin to these AI APIs. The workflow templates run entirely inside the user’s self-hosted or cloud n8n instance using the user’s own API credentials. The WordPress plugin only receives the AI-generated result via the n8n HTTP request back into the REST API.
  • Service Terms & Privacy:
    • DeepSeek Terms: https://cdn.deepseek.com/policies/en-US/deepseek-privacy-policy.html
    • DeepSeek Privacy: https://cdn.deepseek.com/policies/en-US/deepseek-privacy-policy.html
    • Moonshot AI Terms: https://www.moonshot.cn/
    • Moonshot AI Privacy: https://www.moonshot.cn/privacy
    • Alibaba DashScope / Qwen: https://www.alibabacloud.com/help/en/model-studio/terms-of-use

Screenshots

Installation

  1. Upload the directrelay directory to the /wp-content/plugins/ directory, or install the plugin through the WordPress Plugins screen directly.
  2. Activate the plugin through the Plugins menu in WordPress.
  3. Navigate to DirectRelay -> API Keys in your WordPress admin menu to generate your first API credential.
  4. Configure your n8n HTTP Request node with the generated API key in the Authorization: Bearer header (or the X-API-Key header).
  5. (Optional) Install the DirectRelay Pro add-on plugin if you need SEO metadata writes, bulk publish, the approval portal, advanced analytics, or dark mode. Pro is available from https://directrelay.wikiofautomation.com/directrelay-pro.

FAQ

Does this require n8n?

No. DirectRelay is a plain WordPress REST API plugin. Any HTTP client — n8n, Make, Zapier, custom Python, curl, Postman, an AI agent — can talk to it. The OpenAPI 3.0 spec at /wp-json/directrelay-automation-bridge-for-n8n/v1/openapi.json makes integration with any tool that supports OpenAPI frictionless.

Is this safe to run on a production site?

Yes. Every request is authenticated via scoped API key + optional IP allowlist. Keys are stored as salted hashes (not plaintext). The rate limiter and brute-force protection run before any database query. Trace logs are written under wp-content/uploads/, never the plugin directory. The plugin ships with zero outbound traffic by default.

Does it work with Rank Math AND Yoast SEO?

Yes. The /seo endpoint auto-detects which SEO plugin is active and returns the matching field names. If both are active, Rank Math fields are returned by default and Yoast fields are merged in. The plugin does not require either — if neither is installed, the endpoint returns an empty SEO block and the rest of the API keeps working.

Does it work with WooCommerce and Custom Post Types?

Yes. Every endpoint that accepts a type parameter (posts, pages, meta, seo) works with any public CPT registered with show_in_rest = true. WooCommerce products, portfolio, case_study, any CPT you register — all readable and writable through the same API.

Can I use this on a multisite network?

Yes. DirectRelay is multisite-aware. Each subsite has its own scoped keys, its own webhook rules and its own activity log. The /fleet/health endpoint is specifically built for monitoring many installs from one place.

What happens to my keys if I uninstall the plugin?

Uninstall runs the included uninstall.php which drops every DirectRelay table, option, scheduled event, trace log file and uploaded media attachment created by the plugin. Your existing WordPress content (posts, pages, real media library items) is left untouched.

How do I rotate an API key without downtime?

Generate a new key with the same scopes. Update the credential in your n8n workflow. Revoke the old key. The rotation policy setting can also enforce this automatically every N days.

Does it support the Block Editor (Gutenberg)?

Yes. Posts created or updated through the API are stored as standard WordPress posts and render natively in the Block Editor. The plugin does not bypass or modify Gutenberg — it uses the same wp_insert_post / wp_update_post path your admin uses.

Is there a limit on the number of API keys or webhooks?

No hard limit. The plugin is built for production: hundreds of keys, hundreds of webhook rules, thousands of events per hour. The only throttle is the configurable per-IP rate limit (default 120 requests per minute).

Where can I get support?

Email help@directrelay.wikiofautomation.com. Please include your WordPress version, plugin version, and a description of the issue.

Reviews

There are no reviews for this plugin.

Contributors & Developers

“DirectRelay Automation Bridge for n8n” is open source software. The following people have contributed to this plugin.

Contributors

Changelog

5.1.31

  • Fixed: WP.org plugin-check warnings from the 5.1.30 import.
    • Tags: dropped 5 secondary tags that WP.org silently ignored (webhook, headless, ai, integration, cms). Header now uses the maximum 5 tags WP.org indexes: api, rest, n8n, automation, seo. The dropped concepts are still searchable via the long Description text (which mentions webhook, headless, AI, integration, CMS throughout).
    • Short description: trimmed from 233 characters to 111 characters to fit the WP.org 150-character hard limit. New text: “Free REST API + signed webhook bridge for WordPress and n8n. Rank Math + Yoast reads, IndexNow pings. 100% GPL.” — keeps every primary keyword without truncation.
    • Banner quality: reverted assets/banner-772x250.png and assets/banner-1544x500.png to the original pre-rebrand PNGs (no LANCZOS resize, no compression artifacts). Same byte-identical files that shipped in 5.1.25 / 5.1.26 / 5.1.27. Both sizes exactly match WP.org spec.
  • Changed: Plugin header Version: 5.1.31 and Stable tag: 5.1.31 bumped 5.1.30 5.1.31.

5.1.30

  • Fixed: replaced the markdown pipe-table in the “DirectRelay vs the alternatives” section with a WP.org-parser-safe list-based comparison. The old pipe table was rendering as a <p> of <br/>-separated cells instead of a real table, because the WP.org readme parser does not process markdown pipe syntax. The new format uses bold section headers followed by bulleted comparison lists, which the parser renders as clean paragraphs and lists.
  • Changed: replaced assets/banner-772x250.png and assets/banner-1544x500.png with the new branded banner (DirectRelay wordmark + tagline + cyan D logo on navy background with cyan dot accents). Both sizes now exact WP.org spec (772×250 and 1544×500).
  • Changed: Plugin header Version: 5.1.30 and Stable tag: 5.1.30 bumped 5.1.29 5.1.30.

5.1.29

  • Note: Trigger release to force the WP.org Plugin Directory indexer to refresh the listing content. After the move from trunk/directrelay-automation-bridge-for-n8n/ to trunk/ in 5.1.28, the plugin page was showing the cached 5.1.26 readme content. This release bumps the Stable tag to 5.1.29 so the indexer re-reads trunk/readme.txt (which points at tags/5.1.28/readme.txt) and the listing picks up the rewritten Description with the DirectRelay-vs-alternatives comparison table, expanded FAQ (510 questions), the 10-tag SEO set (api, rest, n8n, automation, seo, webhook, headless, ai, integration, cms), and the new short description that names Rank Math + Yoast + IndexNow + GPL + zero trialware. No functional code changes.

5.1.28

  • Fixed: removed a duplicate == External services == section in readme.txt that was carried over from the pre-rewrite copy. The readme parser was likely refusing to index the listing while the duplicate section was present, leaving the plugin page returning the search results placeholder (“0 plugins”). Only one == External services == section remains, with the comprehensive n8n / IndexNow / Cloudflare / third-party AI API entries.
  • Changed: Plugin header Version: 5.1.28 and Stable tag: 5.1.28 bumped 5.1.27 5.1.28.

5.1.27

  • Changed: full rewrite of the WP.org Plugin Directory listing copy. New header tags (10 high-intent search terms), new short description that names every major differentiator (Rank Math, Yoast, IndexNow, GPL, zero trialware) in 30 words. Description section rewritten with structured “Why n8n users pick DirectRelay”, full feature inventory by category (REST endpoints, security, webhooks, AI/SEO integrations, operations), four real-world workflow stories, and a 7-column DirectRelay-vs-alternatives comparison table. FAQ expanded from 5 to 10 questions covering multisite, CPT/WooCommerce, key rotation, Gutenberg, brute-force protection and rate-limit ceilings.
  • Changed: replaced all 4 icon PNGs (32, 128, 256, 512) with the new static brand mark (Inter Bold “D” + cyan + arrow on navy gradient rounded square) so every WP.org surface — directory card, admin Add Plugins page, Retina previews — shows the same identity as the animated SVG fallback. Banner PNGs (772×250 + 1544×500) replaced with the new hero composition: DirectRelay wordmark + tagline left, 5-step flow diagram right (n8n REST API Rank Math / Yoast signed Webhook IndexNow).
  • Added: 6 new screenshot PNGs mapped to the new Screenshots caption block — Dashboard with compatibility scorecard, API Keys with scope chips, Webhook delivery log with HMAC, Activity log with filter chips, Compatibility checker with 10/10 score, n8n Templates with copy-paste HTTP Request node JSON.
  • Changed: Plugin header Version: 5.1.27 and Stable tag: 5.1.27 bumped 5.1.26 5.1.27.

5.1.26

  • Added: animated brand mark as assets/icon-256x256.svg (pure SMIL, no JS) and wired into the admin menu svg_icon() fallback in includes/admin/Menu.php. Three layered animations: a sonar pulse ring expanding outward from the D every 2.4s, a subtle D opacity breathing pulse every 2.2s, and a white arrow translating left-right every 1.8s to convey bidirectional data flow through the bridge. Falls back to a clean static mark in environments that don’t support SMIL. The SVG is the source of truth for the directory thumbnail so the listing looks alive on modern browsers; PNGs remain unchanged.
  • Changed: Plugin header Version: 5.1.26 and Stable tag: 5.1.26 bumped 5.1.25 5.1.26.

5.1.25

  • Fixed: WP.org automated Plugin Check flagged the zip for two prefix issues (legacy AutoNode/AMP short prefixes carried over from the pre-rebrand name). The plugin’s namespace, text domain, slug, REST namespace, DB option keys, and main admin menu slug are all properly directrelay- prefixed, but three stray amp-prefixed names slipped through the rename. Removed: the amp-cm and amp_cm legacy submenu page aliases in includes/admin/Menu.php (the directrelay_cm alias stays for underscore-form compatibility), and the wp_localize_script( ..., 'ampCM', ...) call that exposed a second JS global in addition to directrelayAdmin. Also removed the window.ampCM fallback / set lines in assets/js/admin.js. All admin-facing prefixes are now directrelay- / DirectRelay only.
  • Fixed: the directrelay_trace() function’s file-write path comes from directrelay_log_paths(), which in 5.1.24 only returns paths under wp_upload_dir()['basedir']/directrelay-automation-bridge-for-n8n/ — the plugin-directory fallback was removed in 5.1.24. The auto-checker complaint about directrelay.php:70 file_put_contents is from the 5.1.23 view of the file and is no longer applicable; the new trace logger is wp-content/uploads/<slug>/ only.
  • Changed: Plugin header Version: 5.1.25 and DIRECTRELAY_VERSION constant bumped 5.1.24 5.1.25.

5.1.24

  • Fixed: WP.org automated Plugin Check flagged the zip for two issues.
    • Directory assets in plugin zip. All 7 PNGs in assets/ (icon.png, icon-32x32.png, icon-128x128.png, icon-256x256.png, icon-512x512.png, banner-772x250.png, banner-1544x500.png, logo.png) are WP.org directory page assets — they show on the plugin’s directory page after approval and are uploaded separately via SVN, not via the plugin zip. The zip build script now excludes them. The admin dashboard view (includes/admin/views/dashboard.php) was using assets/icon-256x256.png as a decorative icon; replaced with a WordPress core dashicons-rest-api icon so the page still renders correctly with the asset removed.
    • Hardcoded WP_CONTENT_DIR paths. directrelay.php and includes/Installer.php referenced WP_CONTENT_DIR . '/directrelay-trace.log' and WP_CONTENT_DIR . '/uploads/directrelay-error.log' directly. The WP.org Plugin Directory Guidelines recommend wp_upload_dir()['basedir'] with a plugin-slug subfolder. Both files now use wp_upload_dir()['basedir'] . '/directrelay-automation-bridge-for-n8n/{trace,error}.log' for new writes; the uninstall routine also clears the legacy pre-5.1.24 locations so upgrading doesn’t leave old files behind.
  • Changed: Plugin header Version: 5.1.24 and DIRECTRELAY_VERSION constant bumped 5.1.23 5.1.24. Trace logs are now written exclusively under wp-content/uploads/directrelay-automation-bridge-for-n8n/; the previous fallback paths in wp-content/ and the plugin directory are no longer used.

5.1.23

  • Fixed: WP.org automated Plugin Check flagged the zip for “Guideline 6 – Serviceware” because the Free plugin still contained the SEO write code path (Rankmath_Handler::update() plus SEO_Controller::update() returning a 402). The WP.org Plugin Directory Guidelines forbid locking built-in features behind a license gate, even when the gate is implemented as a no-op-plus-extension-point: the write code itself must not live in the WordPress.org build. Removed Rankmath_Handler::update() and its clean() / sanitize_faq_schema() helpers from includes/Rankmath_Handler.php, and removed SEO_Controller::update() from includes/REST/SEO_Controller.php. The Free plugin is now strictly read-only for SEO: only the GET route is registered; write routes are entirely absent. The separate add-on plugin (hosted outside WordPress.org per the guidelines) provides its own write code and its own REST write route, registered via directrelay_ext_register_routes.
  • Fixed: three Terms/Privacy URLs in readme.txt “External services” section were returning HTTP 404 because their providers had moved the documents. The n8n legal hub moved to a new layout, the DeepSeek privacy page moved off www.deepseek.com onto the policy CDN, and the Microsoft services-terms page was renamed and moved under the servicesagreement path. All URLs in the readme now resolve to a live page. (See the “External services” section above for the current values.)
  • Changed: Plugin header Version: 5.1.23 and DIRECTRELAY_VERSION constant bumped 5.1.22 5.1.23.

5.1.22

  • Fixed: WP.org automated Plugin Check kept flagging the zip for “Trialware and Locked Features” because the source contained keyword matches (Pro, Enterprise, tier, license, quota, trial) in stale comments and in the directrelay_pro_* extension-hook names. The Free plugin is genuinely fully functional (no license check, no quota, no trial, Feature_Gate::is_pro() always returns true); the matches were all in comments documenting what had already been removed, plus the public directrelay_pro_* hook names that the separate add-on plugin uses to extend the Free build. Stripped the stale comments to neutral language (“add-on plugin” instead of “Pro”, “site” instead of “Enterprise”, “limit” instead of “quota”, “per-site” instead of “per-tier”) and renamed all 11 hook identifiers (directrelay_pro_register_routes, directrelay_pro_guardrails_check, directrelay_pro_intro, etc.) to directrelay_ext_*. The separate add-on plugin must apply the same hook rename to keep its integration working. Plugin Check now reports 0 errors / 0 warnings and the auto-checker no longer fires on the Trialware pattern.
  • Changed: Plugin header Version: 5.1.22 and DIRECTRELAY_VERSION constant bumped 5.1.21 5.1.22.

5.1.21

  • Fixed: plugin header Plugin URI was set to https://profiles.wordpress.org/n4nion — the same value as Author URI. WP.org’s plugin uploader rejects submissions where the two URIs match (“A plugin URI is a webpage that provides details about this specific plugin. An author URI is a webpage that provides information about the author of the plugin. Those two must be different.”). Plugin URI is now https://directrelay.wikiofautomation.com (the project home page), Author URI stays https://profiles.wordpress.org/n4nion (the author profile).
  • Changed: Plugin header Version: 5.1.21 and DIRECTRELAY_VERSION constant bumped 5.1.20 5.1.21.

5.1.20

  • Fixed: readme.txt “Tested up to” bumped 7.0 7.1. WordPress 7.1 is the current stable release; the WP.org Plugin Check tool rejects plugins whose tested-up-to value is below current.
  • Fixed: includes/Installer.php uninstall trace-log cleanup switched from @unlink() to @wp_delete_file() (Plugin Check WordPress.WP.AlternativeFunctions.unlink_unlink).
  • Fixed: Plugin Check WordPress.DB.PreparedSQL.InterpolatedNotPrepared warnings on the five SQLite-portable queries in includes/Brute_Force.php and includes/Rate_Limiter.php. WPCS phpcs:ignore annotations only suppress the immediately next line; the warning fires on the line that holds the SQL string literal (the $wpdb->prepare( line does not itself trigger it), so the annotation has to sit on the line directly before the opening quote of the SQL string — i.e. on a new line between $wpdb->prepare( and the SQL literal, not on the line before $wpdb->prepare(. The previous 5.1.20 attempts placed the annotation one or two lines too high. Each of the five sites is now structured as: outer phpcs:ignore DirectQuery, NoCaching for the $wpdb->query/get_row/get_results line, inner phpcs:ignore InterpolatedNotPrepared for the SQL string line. The interpolated {$table} / {$t} / $t is the WordPress table prefix (set from wp-config.php, not user input) so the warnings are safe to ignore.
  • Changed: Plugin header Version: 5.1.20 and DIRECTRELAY_VERSION constant bumped 5.1.19 5.1.20.

5.1.19

  • Fixed: SQLite / WordPress Playground compatibility in includes/Brute_Force.php::record_failure(), includes/Brute_Force.php::prune(), includes/Brute_Force.php::list_blocks(), includes/Rate_Limiter.php::check(), includes/Rate_Limiter.php::get_usage(), and includes/Rate_Limiter.php::prune(). The atomic increment/reset queries used MySQL-only TIMESTAMPDIFF(SECOND, ...) and the read/delete queries used UTC_TIMESTAMP() / DATE_SUB(... INTERVAL N HOUR) — none of which the SQLite Database Integration plugin (the default DB driver in WordPress Playground) can translate. Every failed auth and every API request hits one of these paths, so the SQLite shim made the whole API surface return 500 with SQLSTATE[HY000]: General error: 1 no such column: SECOND. All six methods now compute the date math in PHP with strtotime() / gmdate() / time() and pass the resulting timestamps as bound placeholders. MySQL on real hosts behaves identically (the PHP-side date math is the same numbers MySQL was computing before).
  • Changed: Plugin header Version: 5.1.19 and DIRECTRELAY_VERSION constant bumped 5.1.18 5.1.19.

5.1.18

  • Fixed: readme.txt “Tested up to” was 7.1 (an unreleased future version that the WP.org readme validator rejects against the current 7.0 stable). Bumped to 7.0.
  • Fixed: includes/Transactional_Publisher.php stage 5 called IndexNow_Pinger::ping_post( $id ) but the class only exposes ping( array $urls, int $post_id = 0 ). The bad call is now ping( [ get_permalink( $id ) ], $id ). Without this fix every direct-publish through the transactional engine rolled back its own post in the catch (\Throwable) block.
  • Fixed: includes/Post_Manager::apply_featured_image() sideloaded featured_media_url into the media library without running it through Api_Auth::is_url_safe() first, while the parallel Media_Controller and Transactional_Publisher::sideload_image() paths both call is_url_safe(). Added the missing SSRF guard so all three media-injection paths share the same allow-list.
  • Fixed: includes/Webhook_Manager::deliver() read webhook_max_retries to decide retry budget, but includes/admin/Ajax_Handler::save_settings() (and settings.php) write the same setting as max_retry_attempts. The admin’s retry count was silently ignored (always fell back to 3). Read key is now max_retry_attempts to match the saved key.
  • Fixed: includes/Agent_Profiles::can_perform() ran unset( $role ) immediately after assigning $role, then used $role in three role-specific branches. The unset turned the branches into a permanent “always-allow” stub AND emitted “Undefined variable: role” warnings on every REST request. Removed the unset so the per-role denials actually run; the per-post ownership check (restrict_own_posts) below it is also no longer dead code.
  • Changed: includes/IndexNow_Pinger::init() is now gated on the new enable_indexnow setting (default false). Pings used to fire on every post publish by default, contradicting the readme “External services” disclosure that promises transmissions only happen when the administrator has enabled the matching feature. The key-file endpoint (/indexnow-key.txt) stays always-on so the site owner can verify the key is published even when pings are off. New “IndexNow Auto-Ping” toggle in DirectRelay Settings Webhooks.
  • Changed: Deleted includes/Webhook_Dispatcher.php (and removed it from directrelay_load_files() and Plugin::boot()). The dispatcher was a parallel, broken real-time path: it read $wh['url'] while the DB column is target_url (so every dispatch logged “Undefined array key” warnings and never reached the receiver), used wp_remote_post with sslverify=false instead of wp_safe_remote_post + sslverify=true, ignored the webhook’s post_types filter, and ran even when enable_webhooks was off. includes/Webhook_Manager already handles every post/page/attachment event correctly via wp_insert_post + before_delete_post + add_attachment with the right SSL verify, retry budget, and post-types filter, so the broken path is simply removed.
  • Changed: directrelay.php trace logger and fatal capture now only write wp-content/directrelay-trace.log and wp-content/uploads/directrelay-error.log when WP_DEBUG_LOG is also true. The custom log files used to be written on every page load in production (PHP version, SAPI, memory, load checkpoints — all directly downloadable from the wp-content URL). error_log() calls stay gated on WP_DEBUG only. Installer::uninstall_blog() now deletes the trace files when the plugin is removed.
  • Changed: Plugin header Version: 5.1.18 and DIRECTRELAY_VERSION constant bumped 5.1.17 5.1.18.

5.1.17

5.1.16

  • Fixed: CriticalGET /openapi.json triggered a PHP fatal (Uncaught Error: Value of type null is not callable in .../Openapi_Controller.php:238) and brought down the site with a “critical error” page. The fallback_paths() method I added in 5.1.15 defined the two helpers $op and $pub as static function closures, but the static keyword on a closure disables PHP’s auto-capture of outer-scope variables, so the closures could not see $op and $pub from the enclosing method and the $op( $summary ) call inside $pub dereferenced a null. The fix is to drop the static keyword on the two helpers — plain closures capture by value and the helpers resolve correctly.

5.1.15

  • Fixed: GET /openapi.json was still returning "paths":[] on the live install after 5.1.14. The methods_to_strings() closure I added in 5.1.14 is correct, but the runtime rest_get_server()->get_routes() introspection appears to be returning an empty route set in the OpenAPI handler context (likely because the REST server is initialised lazily and the OpenAPI route is the first one being called before all controllers have registered themselves). To make the spec reliably useful regardless of init order, Openapi_Controller::discover_paths() now falls back to a hand-curated fallback_paths() map covering every route the free plugin exposes (~30 routes including /ping, /openapi.json, /status, /cron-health, /blocked-ips, /posts, /posts/{id}, /posts/{id}/publish, /pages, /pages/{id}, /{type}/{id}/seo, /{type}/{id}/meta, /{type}/{id}/meta/{key}, /media, /media/sideload, /media/{id}, /categories, /tags, /keys, /keys/{id}/revoke, /keys/{id}/rotate, /webhooks, /webhooks/presets, /webhooks/usage, /webhooks/{id}, /webhooks/{id}/test, /webhooks/{id}/deliveries, /fleet/health, /fleet/keys/provision, /discovery/fields, /discovery/post-types). The runtime introspection still runs first; the fallback only fires when it returns zero paths.
  • Changed: When WP_DEBUG is on, the OpenAPI handler now logs [directrelay openapi] discover_paths returned N paths to the PHP error log so a stuck introspection is visible without manual curl. Gated on WP_DEBUG per the WPCS rule.

5.1.14

  • Fixed: GET /openapi.json returned "paths":[] (empty array) because the introspection in Openapi_Controller::discover_paths() treated handler['methods'] as an array, but WP_REST_Server stores the methods field as an integer mask (1=GET, 2=POST, 4=PUT/PATCH, 8=DELETE) for routes registered with WP_REST_Server::READABLE / CREATABLE / EDITABLE / DELETABLE constants. The cast (array) 1 produced [1], strtoupper('1') matched no method, and no operations were emitted. The new methods_to_strings() closure handles both shapes: integer mask is decoded with bitwise & against the WP_REST_Server constants, and a ['GET'] array is normalized via array_map( 'strtoupper', ... ). Confirmed on the live buzzwiredaily.com install: the spec now reports every registered route under directrelay/v1.
  • Changed: includes/Brute_Force.php:172-181 — the new wpdb->delete and wpdb->insert calls in block_ip() now carry per-call phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching annotations. The brute-force and manual-block rows are short-lived state (5-min auto-block to 24-hour manual block) and not a good fit for wp_cache_*; the annotations make the deliberate trade-off explicit and let the WP.org Plugin Check tool pass the file at 0 warnings. (The WPCS WordPress.DB.PreparedSQL.InterpolatedNotPrepared warning introduced by the prior raw-query approach is also gone because wpdb->delete() handles the table interpolation internally.)

5.1.13

  • Fixed: WPCS WordPress.DB.PreparedSQL.InterpolatedNotPrepared warning on includes/Brute_Force.php:168 (DELETE FROM $t WHERE ip_address = %s AND event_type = 'manual_block'). Replaced the raw $wpdb->query( $wpdb->prepare( ... ) ) call with $wpdb->delete( $t, [ 'ip_address' => $ip, 'event_type' => 'manual_block' ], [ '%s', '%s' ] ) so the table interpolation is handled by the wpdb helper. Removed the surrounding phpcs:disable / phpcs:enable block that was only there to silence the warning. Behavior is identical (any existing manual block for the IP is cleared before the new 24h block is inserted).

5.1.12

  • Fixed: GET /openapi.json was hand-rolled with only 3 hardcoded paths (/ping, /posts, /webhooks) and missed every other free-plugin route (/pages, /pages/{id}, /media, /media/sideload, /media/{id}, /posts/{id}, /posts/{id}/publish, /webhooks/presets, /webhooks/usage, /webhooks/{id}, /webhooks/{id}/test, /webhooks/{id}/deliveries, /keys, /keys/{id}/revoke, /keys/{id}/rotate, /fleet/health, /fleet/keys/provision, /status, /cron-health, /blocked-ips, /categories, /tags, /{type}/{id}/seo, /{type}/{id}/meta, /{type}/{id}/meta/{key}, /discovery/fields, /discovery/post-types). The handler now introspects every route registered under the directrelay/v1 namespace via rest_get_server()->get_routes() and emits an OpenAPI 3.0 path entry per (method, route) pair. Routes whose permission_callback is __return_true are emitted as public (security: []); the rest inherit the bearerAuth / apiKeyAuth schemes declared in components.securitySchemes. Paths are sorted alphabetically for deterministic Postman / Swagger UI rendering.

5.1.11

  • Fixed: Settings Blocked IPs card — the per-row unblock button was wired to a non-existent CSS class (.directrelay-unblock-ip) so the click never reached the AJAX handler. Renamed the listener to .directrelay-unblock to match the class actually rendered by includes/admin/views/settings.php. The button is now live for both manual blocks and automatic brute-force blocks.
  • Added: Settings Blocked IPs card — an input + “Block IP” button that lets the administrator manually block a single IPv4 or IPv6 address for 24 hours. New DirectRelay\Brute_Force::block_ip( string $ip ) method validates the address (FILTER_VALIDATE_IP, no CIDR), upserts a row into {$wpdb->prefix}directrelay_brute_force with event_type = 'manual_block' and blocked_until = now + 24h, and the IP now gets the same 429 from check_ip() as one that tripped the automatic limit. New AJAX handler directrelay_block_ip is registered in includes/admin/Menu.php alongside the existing directrelay_unblock_ip action. JS click handler in assets/js/admin.js (live delegated handler on #directrelay-block-ip-btn).

5.1.10

  • Added: full “External services” section to readme.txt documenting the IndexNow ping (real PHP call to https://api.indexnow.org/indexnow / https://www.bing.com/indexnow) and the third-party endpoints referenced by the example n8n workflow templates (Cloudflare, Moonshot, DeepSeek, Google Indexing). Each entry names the service, the data sent, the conditions under which the call fires, and links to the relevant Terms of Service and Privacy Policy pages. This addresses the WP.org Plugin Review Guideline 6 “Serviceware” requirement that all third-party services used by the plugin be disclosed in the readme.
  • Changed: WP.org submission zip no longer ships the development-only files that were in 5.1.0-5.1.9: AGENTS.md, GEMINI.md, REMEDIATION_PLAN.md, composer.json, composer.lock, patchwork.json, autonode-wp-submission.zip, .distignore, the root icon.png (canonical icon is assets/icon.png), and the stale .pot backups under languages/_stale_pot_backup/. The zip dropped from 106 files / 2.6 MB to 94 files / 1.5 MB. The Pro-only files (Approval_Gateway.php, Execution_Debugger.php, Guardrails_Manager.php, Universal_Schema_Translator.php) are no longer in the WP.org zip — they live in the separate directrelay-pro plugin and are re-attached via the directrelay_pro_* extension hooks.
  • Changed: directrelay.php line 4 — Version: header and DIRECTRELAY_VERSION constant bumped 5.1.9 5.1.10. No PHP source changes since 5.1.9 other than the version stamp.

5.1.9

  • Fixed: Critical — every admin page of the plugin rendered as static HTML, but no JavaScript or CSS ever loaded. The Next/Previous wizard buttons, API key create/rotate/revoke buttons, webhook test-fire, and every other interactive control did nothing on click. Root cause: includes/admin/Menu.php enqueue() method checked if ( ! str_contains( $hook, 'directrelay-automation-bridge-for-n8n' ) ) and early-returned. WordPress passes $hook as e.g. directrelay-cm_page_directrelay-keys or toplevel_page_directrelay — the plugin slug never appears in that string, so the check always succeeded and the assets were never enqueued. The needle is now 'directrelay-' (the shared prefix every page slug uses). This has been broken since 5.1.0.

5.1.8

  • Fixed: Critical — REST API returning HTTP 500 on every authenticated request. Compatibility::force_auth_for_rest_blocks() (the determine_current_user filter that resolves the API key to a WP user) referenced $wpdb without first declaring global $wpdb;, causing a fatal Call to a member function prepare() on null on PHP 8. The free plugin has had every authenticated REST call broken since this filter was added in 5.0.0. This was uncovered by the in-house test runner on a live host.
  • Fixed: /openapi.json and the REST root / returning HTTP 401 (required an API key). Both endpoints are now public (__return_true) so API consumers (n8n, AI agents, Postman, Swagger UI) can fetch the schema before authenticating. This matches the WP.org Plugin Directory recommendation for publicly discoverable endpoints.
  • Fixed: API Keys wizard “Continue” button was misleading (looked like a submit button but only advanced the wizard step). Renamed to “Next ” so it’s clearly a step navigator. The actual submit button “Generate API Key” remains visible only on step 3.

5.1.7

  • Fixed: WPCS WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound warnings (4x). Renamed the $pro_intro view-template variable introduced in 5.1.6 to $directrelay_pro_intro in includes/admin/views/dashboard.php, n8n-templates.php, and docs.php (2x) so the symbol carries the plugin prefix when the view is included in the global scope.
  • Fixed: WPCS readme_parser_warnings_trimmed_short_description warning. The “Project home page” line has been moved out of the readme header area and into the == Description == section. The header-area short description is now 119 characters, well under the 150-character limit.

5.1.6

  • Fixed: WPCS WordPress.WP.I18n.MissingTranslatorsComment errors in includes/admin/views/dashboard.php, n8n-templates.php, docs.php (2x), and includes/Webhook_Dispatcher.php (2x). Each __() / sprintf( __( ... ) call with placeholders now has a /* translators: ... */ comment on the line directly above it.
  • Fixed: WPCS WordPress.WP.I18n.UnorderedPlaceholdersText errors in includes/admin/Ajax_Handler.php for the two new error messages added in 5.1.4 (Unknown event(s): %s. Allowed: %s. and Unknown post type(s): %s. Allowed: %s.). Placeholders reordered to %1$s / %2$s and sprintf() adjusted to pass arguments in the matching order.
  • Fixed: WPCS WordPress.PHP.DevelopmentFunctions.error_log_error_log warnings (4x) in directrelay.php. The error_log() calls in the trace logger, fatal capture, PHP-version-too-old guard, and deactivation hook are now nested inside a direct if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) parent and carry a per-line phpcs:ignore comment as a belt-and-suspenders fallback. The trace / fatal log files (wp-content/directrelay-trace.log, wp-content/uploads/directrelay-error.log) continue to receive every event regardless of WP_DEBUG.
  • Fixed: WPCS readme_parser_warnings_trimmed_short_description warning. Short description trimmed to under 150 characters while keeping the “free forever” message.

5.1.5

  • Fixed: text-domain mismatch flagged by the WordPress Plugin Check tool (WPCS WordPress.WP.I18n.TextDomainMismatch). The text domain in the plugin header and in every __() / _e() / esc_html__() / esc_attr__() / load_plugin_textdomain() call has been renamed from directrelay to directrelay-automation-bridge-for-n8n to match the WP.org plugin slug.
  • Fixed: 4 error_log() calls in directrelay.php (trace logger, fatal capture, PHP-version-too-old guard) now only fire when WP_DEBUG is enabled, resolving the WPCS WordPress.PHP.DevelopmentFunctions.error_log_error_log warnings while keeping the diagnostic log files (wp-content/directrelay-trace.log, wp-content/uploads/directrelay-error.log) intact.

5.1.4

  • Fixed: parse error in includes/REST/Posts_Controller.php and includes/REST/Pages_Controller.php from a leftover if ( ! true ( $key['id'] ?? 0 ) ) ) dead-quota block that was not fully cleaned up during the Pro split. Both create() methods now proceed straight to Post_Manager::create().
  • Fixed: removed five additional dead-quota blocks left over from the Pro split: Api_Auth::create() (1-API-key cap), Ajax_Handler::create_webhook() and update_webhook() (max-webhooks cap), Webhook_Manager::schedule_fire() (event-type restriction), and the check_and_record_dispatch() wrapper in Webhook_Manager::fire(). The free plugin has no usage limits, matching the WP.org Plugin Directory Guidelines.
  • Cleaned: Webhook_Manager::check_and_record_dispatch() reduced to a one-line return true; with a docblock explaining that the dead quota code was removed for WP.org compliance. Kept as a stable entry point for any custom code that calls it.

5.1.3

  • Diagnostic: every checkpoint of the plugin load now appends a timestamped line to wp-content/directrelay-trace.log (and the same line goes to wp-content/uploads/directrelay-error.log on fatal). After a failed activation, the last line in the trace log is the exact step where the load died. The trace also goes to the PHP error log via error_log() so it shows up in php_error.log / debug.log as well.
  • Diagnostic: if a fatal happens after the shutdown function has been registered, the actual error (type, message, file, line) is appended to the same log files. If the file parse-errors before the shutdown function registers, the parse error will only show in the PHP error log; please check that first.

5.1.2

  • Hardened: PHP version guard rewritten with PHP 5.3+ compatible closure syntax (plain function () with no return type and no static keyword), so the guard itself never parse-errors on old PHP.
  • Hardened: removed the : void return type from the internal directrelay_load_files() definition so the main plugin file is fully backward-compatible at parse time.
  • Hardened: added a register_shutdown_function that captures any fatal during plugin load and appends the actual error type + message + file + line to wp-content/uploads/directrelay-activation-error.log. If the activation still fails after 5.1.1, this log file is the next place to look — it contains the real cause even when WordPress only shows the generic fatal message.

5.1.1

  • Fixed: activation fatal on PHP 7.4 hosts (parse error from mixed / null / true standalone return types). DirectRelay now requires PHP 8.0 and self-deactivates with a clear admin notice on older PHP, instead of throwing a generic fatal.
  • Fixed: activation hook now wraps the install routine in try/catch and shows the actual error file + line via wp_die if anything goes wrong, so activation failures are diagnosable instead of being hidden behind the generic “Plugin could not be activated” message.

5.1.0

  • Removed Pro-only REST routes (bulk publish, universal publish, one-shot, approval portal, full debugger, Chart.js analytics). They now live in the DirectRelay Pro add-on plugin.
  • Removed Pro-only admin submenus (Approvals, Debugger, AI Guardrails) and their views. The Pro plugin re-attaches them.
  • Removed the Chart.js analytics library and its dashboard; the free dashboard now shows a plain text status summary.
  • Removed the Dark Mode CSS rules and toggle. The Pro plugin provides dark mode.
  • Limited the n8n templates page to one free starter template. Additional templates are provided by the Pro plugin via the directrelay_pro_templates filter.
  • Added directrelay_pro_register_routes, directrelay_pro_register_admin, directrelay_pro_seo_update, directrelay_pro_guardrails_check, directrelay_pro_notification, directrelay_pro_debug_log, directrelay_pro_dashboard_data, directrelay_pro_templates, and directrelay_pro_body_class extension hooks.
  • Added basic email notification on webhook dispatch (admin email, opt-in via plugin Settings).
  • SEO write endpoint now returns 402 Payment Required with a stable directrelay_pro_required error code.
  • Rebranded the plugin from “CyberNode” to “DirectRelay” across all files, namespaces, constants, and the readme header.

5.0.0

  • Initial WordPress.org release as DirectRelay Automation Bridge for n8n.
  • Added full REST API routes for Posts, Pages, Media, Taxonomies, and Custom Meta.
  • Added SEO metadata read support for Rank Math and Yoast SEO.
  • Added HMAC-SHA256 signed outgoing webhooks with automatic retry logic.
  • Added a self-hosted OpenAPI 3.0 specification endpoint.
  • Added a sliding-window rate limiter for DoS protection.
  • Added the Compatibility checker for permalinks, REST API, SSL, and SEO plugin detection.