=== Draft2Live Connect ===
Contributors: draft2live
Tags: ai, content-generation, publishing, polylang, multilingual
Requires at least: 6.0
Tested up to: 6.9
Requires PHP: 7.4
Stable tag: 1.2.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Publish AI-generated articles from Draft2Live to WordPress in one click, with two-way sync and multilingual support (Polylang, WPML).

== Description ==

**Draft2Live Connect** is the official bridge between your WordPress site and [Draft2Live](https://draft2live.ai), an AI content generation platform that helps you research, plan, write and publish long-form SEO articles at scale.

Once the plugin is installed and your site is paired with your Draft2Live account, you can:

* Publish articles generated in Draft2Live straight to WordPress without leaving the dashboard
* Keep content in sync both ways — edits made in WordPress flow back to Draft2Live automatically
* Assign categories, tags, featured images and authors at publish time
* Schedule publications for a future date (handled by Draft2Live's unified scheduler, so it works exactly the same for WordPress and Drupal)
* Publish multilingual content and link translations automatically if your site uses [Polylang](https://wordpress.org/plugins/polylang/) or [WPML](https://wpml.org/)
* Write SEO meta title / meta description / focus keyword through [Yoast SEO](https://wordpress.org/plugins/wordpress-seo/) or [Rank Math](https://wordpress.org/plugins/seo-by-rank-math/) when one of them is active

**One-click secure pairing.** No copy-pasting site IDs or secrets. The plugin uses WordPress's native [Application Passwords](https://make.wordpress.org/core/2020/11/05/application-passwords-integration-guide/) flow — click **Connect to Draft2Live** in the plugin settings, approve the Application Password in the standard WordPress prompt, and the pairing completes automatically.

**You stay in control.** Draft2Live never receives your WordPress login password. You can revoke access at any time by deleting the Application Password under **Users → Profile → Application Passwords**, or by deactivating the plugin.

**Open source.** The plugin source is available on our [website](https://draft2live.ai) under the GPL v2 license.

== Installation ==

1. From your WordPress admin, go to **Plugins → Add New**, search for "Draft2Live Connect" and click **Install Now**, then **Activate**. (Or upload the `draft2live-connect` folder to `/wp-content/plugins/` manually.)
2. Go to **Settings → Draft2Live**.
3. Click **Connect to Draft2Live**. You'll be redirected to the standard WordPress Application Password approval screen — review it and click **Yes, I approve**.
4. That's it. The site is now paired. You can start publishing from your Draft2Live dashboard.

If you don't have a Draft2Live account yet, you can sign up for free at [draft2live.ai](https://draft2live.ai).

== Frequently Asked Questions ==

= Is the plugin free? =

Yes. The plugin is 100% free and open source under the GPL v2 license. A Draft2Live account is required to generate content, and Draft2Live itself offers a free tier so you can try the full workflow end-to-end at no cost.

= What data does the plugin send to Draft2Live? =

Only the data needed to keep your articles in sync:

* When you publish from Draft2Live, the article content (title, HTML body, featured image, categories, tags) is received by this plugin from Draft2Live and saved as a normal WordPress post.
* When you edit, trash, untrash or delete a post that originated from Draft2Live, the plugin sends a webhook to Draft2Live with the post ID, title, new status and modification timestamp so Draft2Live's copy stays consistent. No personal information or visitor data is transmitted.
* All webhooks are signed with an HMAC-SHA256 signature using a secret that is generated during pairing and stored only on your site and on your Draft2Live account.

See the **External services** section below for the full list of endpoints.

= Do I need a Draft2Live account? =

Yes — the plugin is the WordPress side of the Draft2Live platform. You can create a free account at [draft2live.ai](https://draft2live.ai).

= How do I disconnect my site? =

The safest way is to go to **Users → Profile → Application Passwords** and revoke the "Draft2Live" entry. You can also deactivate and delete the plugin from **Plugins**. Both methods immediately stop all further communication with Draft2Live.

= Does the plugin support Polylang or WPML? =

Yes. If either plugin is active, Draft2Live will detect it automatically during site verification and offer you multilingual publishing: you can generate one article in multiple languages and publish them all in one click, linked as translations of each other. Cross-language linking uses the Polylang REST API or the WPML language field depending on which plugin is installed.

= Does the plugin support Yoast SEO or Rank Math? =

Yes. If Yoast SEO or Rank Math is active, the plugin detects it and Draft2Live will push a meta title, meta description and focus keyword to the appropriate post meta fields when you publish. If neither plugin is active, only standard WordPress post fields are written.

= Can I use a custom post type? =

Yes. The plugin supports publishing to any registered public post type, not just posts and pages.

= Does two-way sync run on every save? =

Only for posts that originated from Draft2Live (identified by a hidden post meta field the plugin writes on import). Posts you created manually in WordPress are never touched by the sync.

== Screenshots ==

1. The plugin settings page showing the one-click "Connect to Draft2Live" button.
2. The WordPress Application Password approval screen (native WordPress UI).
3. The connected state after successful pairing — the site is ready to receive content.
4. Publishing an article from Draft2Live to the paired WordPress site.

== External services ==

This plugin connects to Draft2Live — the SaaS backend that generates and manages your articles — so that your site can receive published content and keep it in sync. No data is sent until you explicitly pair the site.

**Service:** Draft2Live
**Homepage:** https://draft2live.ai
**Terms of Service:** https://draft2live.ai/en/terms
**Privacy Policy:** https://draft2live.ai/en/privacy

**What is sent and when:**

* **During pairing (one time, user-initiated):** the plugin generates a WordPress Application Password via the standard WordPress flow and sends it to Draft2Live's `/api/v1/sites/wp-callback` endpoint so the SaaS can authenticate future publish requests against your site.
* **When a post that originated from Draft2Live is updated, trashed, untrashed or permanently deleted:** the plugin sends a signed webhook to `https://<your-draft2live-instance>/api/v1/sites/webhook/{site_id}` containing the post ID, the internal Draft2Live article ID, the post title, the new post status and the modification timestamp. The webhook body is signed with HMAC-SHA256 using the secret established during pairing.
* **When Draft2Live publishes or updates an article on your site:** Draft2Live calls the plugin's REST endpoints (`/wp-json/draft2live/v1/publish`, `/wp-json/draft2live/v1/posts/{id}`, etc.) authenticated with the Application Password stored during pairing. Featured images and in-content images/videos referenced in the article payload are downloaded from the URL included in the payload into your WordPress media library — URLs are validated with `wp_http_validate_url()` before any fetch.

**What is not sent:**

* Visitor information, analytics or tracking data
* Your WordPress admin password (the plugin never receives it — Application Passwords are a one-way secret generated by WordPress itself)
* Anything about posts that did not originate from Draft2Live

You can stop all communication at any time by revoking the Application Password under **Users → Profile → Application Passwords**, or by deactivating / uninstalling the plugin.

== Changelog ==

= 1.2.2 =
* Fix: changing only the featured image on the WordPress side now propagates back to Draft2Live. The post's thumbnail id is part of the sync-loop hash, so a featured-image swap actually trips the on_post_save webhook (previously the unchanged title/content/status fooled the dedup into skipping the notification).

= 1.2.1 =
* Webhooks back to Draft2Live now also carry the post excerpt, the SEO meta description (Yoast / Rank Math / AIOSEO), the featured image URL, the post tags and the categories. Edits to any of these on the WordPress side now propagate back to the Draft2Live editor instead of getting silently dropped.

= 1.2.0 =
* Branded "update available" banner shown on every WordPress admin page (with the Draft2Live logo and an "Install update" button) so the admin spots the new version without going to Plugins → Updates.
* After WordPress finishes upgrading the plugin, the site sends a one-shot fire-and-forget notification to draft2live.ai so the platform admins can see the rollout reach real sites (used internally for monitoring; payload is just site URL + old/new version).

= 1.1.9 =
* Internal release pipeline test - no functional changes.

= 1.1.8 =
* Featured image can now be replaced (or removed) on the existing post via the update endpoint, not just at create time. Pass `featured_image_url` in the update payload — a non-empty URL replaces the thumbnail, an empty string clears it, omitting the key leaves the current thumbnail untouched.

= 1.1.7 =
* Fixed: status changes made in WordPress (e.g. publish → draft via Quick Edit) now reliably sync back to Draft2Live. Previously the first edit after a Draft2Live publish was swallowed by an over-eager sync-loop guard. The guard is now content-hash based and only suppresses WordPress's own internal save during plugin-driven updates.

= 1.1.6 =
* Strengthened REST API permissions: `/draft2live-posts` now requires `edit_others_posts`, `/posts/{id}/export` uses per-post permission check.
* Removed `load_plugin_textdomain()` — WordPress.org handles translations automatically since 4.6.
* Updated plugin URL references.

= 1.1.5 =
* New `GET /wp-json/draft2live/v1/draft2live-posts` endpoint that returns every WP post which originated from Draft2Live (has the `_draft2live_article_id` postmeta). Used by the Draft2Live dashboard to re-link existing publications after a site has been disconnected and re-paired.

= 1.1.4 =
* Tidies the native WordPress Application Password approval screen when the application being authorized is Draft2Live: hides the long redirect-URL preview lines (which overflow on small windows) and puts the Approve / Deny buttons on a single row. Other plugins that use Application Passwords are not affected — the styles are gated to apps named "Draft2Live".

= 1.1.3 =
* Cleaner settings page: removed the right-hand sidebar (Application Passwords / Help links) since the disconnect card and the rest of the page already cover everything important.

= 1.1.2 =
* New "Disconnect from Draft2Live" button on the plugin settings page so the user can clear the local pairing state without going to Draft2Live.
* Added a Settings link to the plugin row on the **Plugins → Installed Plugins** screen.

= 1.1.1 =
* Added `/wp-json/draft2live/v1/disconnect` REST endpoint so Draft2Live can clear the plugin's local pairing state when the user removes the site from their Draft2Live account. Without this, the plugin kept showing as connected after the matching site was deleted on the Draft2Live side.

= 1.1.0 =
* First public release on WordPress.org.
* Security hardening: tightened REST API permission callbacks per-route (read / publish / edit_post / delete_post / admin), per-post capability checks for update, delete and restore endpoints.
* Security: SSRF guard on remote media downloads — non-HTTP schemes and private/reserved IP ranges are rejected via `wp_http_validate_url()`.
* Security: `post_status` values are now whitelisted against `draft`, `pending`, `publish`, `future`, `private`.
* Security: Schema.org JSON-LD output re-encoded with `JSON_HEX_*` flags so stored content can't break out of the `<script>` block.
* Bug fix: the two-way sync hooks were never firing because the `post_type` default was missing from the settings defaults. Sync now works out of the box.
* Yoast SEO meta fields are only written when Yoast is actually active.
* Added `.pot` file in `/languages/` so the plugin is fully translatable.
* Replaced Unicode icon glyph with a Dashicon.
* Moved inline admin CSS into the enqueued stylesheet.
* Bumped `Tested up to` to 6.9.

= 1.0.3 =
* One-click pairing via the WordPress native Application Password authorize flow.
* New `/setup` REST endpoint that Draft2Live calls at the end of the pairing handshake to push the site_id and webhook_secret automatically.
* Hid the legacy Site ID / Webhook Secret / API URL form fields from the admin screen — these are now managed automatically by the pairing flow.
* Admin page now shows a single hero "Connect to Draft2Live" button.

= 1.0.0 =
* Initial version, distributed as a direct download from draft2live.ai.
* Publishing from Draft2Live to WordPress (title, content, featured image, categories, tags, FAQ).
* Two-way synchronization: edits in WordPress flow back to Draft2Live via signed webhooks.
* Settings page under Settings → Draft2Live.
* REST API endpoints under `/wp-json/draft2live/v1/`.

== Upgrade Notice ==

= 1.1.0 =
Security hardening release and first public WordPress.org version. Fixes a two-way sync bug where hooks were never firing — please re-save the plugin settings after upgrading to make sure `post_type` is set correctly.
