=== Edward – AI SEO Autopilot & Content Writer ===
Contributors: edwardseo, simonaspetk
Tags: seo, ai, autopilot, content, publishing
Requires at least: 5.0
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.1.5
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

AI autopilot for WordPress: write articles with AI, auto-publish on a schedule, and sync focus keyword & meta to Yoast SEO, Rank Math, or AIOSEO.

== Description ==

Edward is the official WordPress connector for [MeetEdward](https://meetedward.com), an AI-powered SEO content automation service. Once installed, your WordPress site can receive articles published by Edward and have them appear as native posts, with proper SEO metadata, featured images, tags, and scheduling.

[Meet Edward](https://meetedward.com) researches keywords, writes the articles, and schedules them. This plugin is the piece that puts them on your site as real WordPress posts.

The plugin exposes a small, authenticated REST API at `/wp-json/edward/v1/*` that the Edward SEO service uses to publish articles. All endpoints require a randomly-generated API key that you copy into your MeetEdward dashboard once during setup. No data leaves your WordPress site without a request from MeetEdward, authenticated with your key.

= Key features =

* Publishes articles as standard WordPress posts.
* Sets SEO title, focus keyword, meta description, canonical URL, noindex flag, Open Graph + Twitter Card tags for Yoast SEO, Rank Math, and All in One SEO, whichever you have installed.
* Attaches featured images from external URLs with explicit alt text and caption support.
* Supports tags, categories, and scheduled publishing (via WordPress's built-in scheduled-post mechanism).
* Idempotency keys prevent duplicate posts on retry.
* Slug-conflict detection avoids SEO cannibalization.
* Optional IndexNow integration for near-instant Bing/Yandex re-crawl notifications.
* Diagnostics endpoint for support troubleshooting (PHP version, WP version, SEO plugin detection, file permissions).
* Site discovery endpoints (authors, categories, tags) so the MeetEdward dashboard renders accurate dropdowns.
* Survives hosts that disable the `fileinfo` PHP extension via a four-tier mime detection ladder.
* Survives hosts that block the WordPress REST API for anonymous requests via a scoped bypass filter (Edward's own routes still require the API key).
* SSRF guard on external image URLs (blocks loopback, private IP ranges, link-local, ULA).

= What this plugin needs from you =

After installation, copy the API key from the **Tools → Edward** page in WordPress admin and paste it into your MeetEdward dashboard. That's the only setup step.

== External services ==

This plugin is the WordPress-side interface to [MeetEdward](https://meetedward.com), an AI content service hosted at https://meetedward.com. To make the integration work, MeetEdward's servers will call this plugin's REST endpoints. Every call is authenticated with the API key you generate.

**Data sent FROM your WordPress site TO MeetEdward:** none initiated by the plugin. Responses to MeetEdward's authenticated requests return information you'd expect for a publishing flow (created post IDs and URLs, your list of authors, categories and tags, basic site diagnostics), and only when MeetEdward asks for them with a valid key.

**Data sent FROM MeetEdward TO your WordPress site:** article title, body, SEO metadata, featured image URL, tags, category, schedule. These become standard WordPress posts.

**Featured image download:** when an article includes a featured image, the plugin downloads that image from the web address MeetEdward sends with the article and adds it to your Media Library. This is the one outbound request the plugin makes. It is a plain download request from your server to the server hosting the image; the image host sees your server's IP address and WordPress's standard user agent, and no other data from your site is sent. Addresses that point at private or internal networks are refused. Articles without a featured image cause no outbound request.

**IndexNow:** if you enable IndexNow via the MeetEdward dashboard, the plugin generates a key and serves it at the root of your site (e.g. `https://yoursite.com/abc123….txt`). The key is answered by the plugin itself; no file is written to your server. MeetEdward then notifies `api.indexnow.org` of new article URLs with that URL passed as the `keyLocation` parameter, so Bing/Yandex/Naver/Seznam can re-crawl them. No data leaves your site directly from this plugin for IndexNow.

MeetEdward's [terms of service](https://meetedward.com/terms-of-service) and [privacy policy](https://meetedward.com/privacy-policy).

== Installation ==

1. Upload the `edward-seo` folder to `/wp-content/plugins/` (or install via the WordPress plugin uploader).
2. Activate the plugin through the **Plugins** menu in WordPress.
3. Go to **Tools → Edward** to retrieve your API key.
4. Paste the key into your MeetEdward dashboard.

== Frequently Asked Questions ==

= Does this plugin send data to MeetEdward without my knowledge? =

No. The plugin never sends data to MeetEdward on its own. Communication only happens when MeetEdward's servers call this plugin's REST endpoints, authenticated with the API key you generate. The only outbound request the plugin makes is downloading an article's featured image from the address MeetEdward provides, which sends no data from your site. See the "External services" section above for a full data-flow breakdown.

= What happens if I lose my API key? =

Click "Generate New Key" on the Tools → Edward page. The old key stops working immediately. Update the new key in your MeetEdward dashboard.

= Does this plugin work with Yoast SEO / Rank Math / All in One SEO? =

Yes. Edward writes SEO title, meta description, focus keyword, canonical URL, noindex flag, Open Graph, and Twitter Card metadata for all three plugins. Whichever one you have active, the data lands in the right place.

= What WordPress user is set as the article's author? =

By default, the administrator whose email matches the site's Administration Email Address (Settings → General), or the first administrator account if none does. You can choose a different user on the Tools → Edward page.

= Why is my newly-published article showing as "draft" instead of "published"? =

If a post or page with the same slug already exists on your site, Edward downgrades to draft to avoid SEO cannibalization. Change the slug or delete the conflicting post, and the next publish will go live.

= How do I uninstall completely? =

Deactivate then delete the plugin from **Plugins → Installed Plugins**. The uninstall hook removes all plugin options, including the IndexNow key. Articles already published remain.

== Changelog ==

= 1.1.5 =
* Security: tightened how Edward's API works alongside security plugins and hosts that restrict the WordPress REST API.
* Security: Edward's API responses are now excluded from page caches, including LiteSpeed Cache, so they are never served to a request without a valid key.
* Fixed IndexNow verification. The key is now served from your site root, where search engines accept it, and an existing key is kept.
* Fixed backslashes being removed from published articles, which affected code samples, file paths and some block settings.
* Fixed articles being published without an author when Post Author is left on its default. They are now attributed to the site administrator.
* Fixed the edit link missing from publish responses.
* Fixed the author list skipping users when more than 200 were requested at once.
* Publish requests with invalid fields now get a clear error instead of a server error.
* Redesigned the settings page: connection status shows whether articles are arriving, recent articles are listed with their status, all defaults save with one button, and the page works on phones.
* The readme now describes the plugin's one outbound request, the featured image download.

= 1.1.2 =
* Fixed a fatal "Allowed memory size exhausted" error that stopped the Tools → Edward settings page from loading on sites with large user tables. The post-author and category dropdowns loaded every matching row at once; they now load the first 100 and add a search box for finding anyone else. Thanks to the Ticket Falcon team for the report and the diagnosis.
* The author list is now filtered by role correctly on WordPress 5.0–5.8, where the `capability` query argument does not exist and every user (subscribers and customers included) was being listed.
* The `/authors`, `/categories`, and `/tags` REST endpoints now accept `search`, `page`, and `per_page`, and return `has_more`. They previously returned every row in one response, which failed the same way on large sites. Existing response keys are unchanged, so current callers keep working; they now return the first 100 authors or 200 categories/tags per request, up to 200 authors or 500 categories/tags on request.
* Saving a post author or category that no longer exists is now rejected with an error instead of being stored. A deleted user left behind an ID that produced published posts with a blank byline and a broken author archive.

= 1.1.1 =
* Fixed All in One SEO (AIOSEO) sync. Meta description and focus keyphrase were written only as postmeta, which AIOSEO 4+ does not read, so they never appeared. They are now written through AIOSEO's own storage (the `aioseo_posts` table) via its Post model, so they show in the editor and on the front end.
* Added optional `meta_title` (SEO title) to the publish endpoint, written to Yoast SEO, Rank Math, and All in One SEO.
* All in One SEO now also receives the canonical URL, noindex flag, Open Graph / Twitter Card tags, and the SEO (TruSEO) score snapshot, matching the existing Yoast/Rank Math coverage.
* Added a "Settings" link on the Plugins list page that jumps to Tools → Edward.

= 1.1.0 =
* Publish endpoint now accepts optional `seo_score` and `readability_score` (0–100) and writes them to the Yoast (`_yoast_wpseo_linkdex`, `_yoast_wpseo_content_score`) and Rank Math (`rank_math_seo_score`) meta keys, so the SEO/Readability columns in the posts list are populated immediately on publish instead of showing "Not available". (All in One SEO TruSEO scoring is not yet covered.)

= 1.0.0 =
* Initial release.
* Publish endpoint (`POST /edward/v1/publish`) with idempotency, slug-conflict detection, SEO metadata, featured-image attach, scheduled publishing, tags, auto-excerpt.
* Verify, diagnostics, authors, categories, tags read endpoints.
* IndexNow setup + status endpoints.
* Tools → Edward admin page with API-key management, default author/category selection, test-connection button, and recent-publishes log.
* SSRF guard on external image URLs.
* Multisite-aware uninstall cleanup.

== Upgrade Notice ==

= 1.1.5 =
Security and reliability update with a redesigned settings page. Recommended for all sites.

= 1.1.2 =
Fixes a memory-exhaustion crash that prevented the settings page from loading on sites with many users. Recommended for all sites.

= 1.1.1 =
All in One SEO users: SEO title, meta description, and focus keyphrase now sync correctly into AIOSEO.

= 1.1.0 =
Published articles now show their SEO and readability scores in the posts list right away.

= 1.0.0 =
Initial release.
