=== Artificial Poets Reusable Components CDN ===
Contributors:      artificialpoets
Tags:              rest-api, sync, json, cache, headless
Requires at least: 6.0
Tested up to:      7.0
Requires PHP:      8.0
Stable tag:        0.1.0
License:           GPL-2.0-or-later
License URI:       https://www.gnu.org/licenses/gpl-2.0.html

Turn your WordPress site into a content delivery network for reusable components — JSON, text, and files — shared across sites.

== Description ==

**Artificial Poets Reusable Components CDN** lets one WordPress site act as a Host that publishes a Library of named pieces of content — a logo, a tagline, a social-links JSON blob, a privacy notice — and any number of other sites act as Receivers that subscribe to that Host and consume those components instantly.

Every component has a stable slug, a type (`json`, `text`, or `file`), a per-component cache TTL, and an auto-incrementing version number that becomes its HTTP `ETag`. Subscribers fetch the latest version on demand and revalidate cheaply with `304 Not Modified` for unchanged content.

A single site can also act as **both** Host and Receiver — publish your own Library while subscribing to one or more remote Hosts.

= Use cases =

* Keep brand assets (logo, favicon, tagline, contact info) in sync across a fleet of WordPress sites without copy-paste.
* Centralise structured data (footer links, locations, pricing tables) so updating once propagates everywhere.
* Serve component content from a dedicated CDN subdomain via a thin reverse-proxy layer.
* Pull versioned content into a headless frontend (Next.js, Astro, Vercel) with stable cache semantics.

= Key features =

* **Three component types** — JSON, plain text, and file (proxies URLs through the REST endpoint).
* **Two independent capabilities** — publish your Library and/or subscribe to a remote Host. Toggle each side on or off in Settings.
* **HTTP cache headers** — every `/raw` response sends `ETag`, `Last-Modified`, and `Cache-Control: public, max-age=<TTL>, must-revalidate`. Conditional requests get `304 Not Modified`.
* **Per-IP rate limiting** — 120 requests per 60 seconds on the host endpoints.
* **CORS control** — open, allowlist, or denylist by domain (with `*.example.com` wildcard support).
* **Optional authentication** — require Application Passwords on either side independently.
* **Source connection tester** — verify a Host URL from the Settings page before saving.
* **Native admin UI** — built on WordPress admin patterns, fully translatable.

= REST endpoints (Host mode) =

* `GET /wp-json/wp-components/v1/components` — list all published components
* `GET /wp-json/wp-components/v1/components/{slug}` — fetch one as JSON metadata
* `GET /wp-json/wp-components/v1/components/{slug}/raw` — fetch with type-appropriate `Content-Type` (text/plain, application/json, or proxied file bytes)

== Installation ==

1. Install the plugin from **Plugins → Add New** and search for *Artificial Poets Reusable Components CDN*, or upload the `.zip` via **Plugins → Add New → Upload Plugin**.
2. Activate **Artificial Poets Reusable Components CDN** under **Plugins → Installed Plugins**.
3. Open **Components** in the admin menu; the onboarding screen asks how you want this site to participate.
4. **Publish only** to expose a Library via REST. **Subscribe only** to pull from another Host. **Both** to do both.
5. If subscribing, enter the Host URL under **Components → Settings → Source Subscription** and click *Test Connection*.

== Frequently Asked Questions ==

= Does this work for headless WordPress / Next.js / Astro frontends? =

Yes. The Host's `/wp-json/wp-components/v1/components/{slug}/raw` endpoint returns the content with the right `Content-Type` header and proper `Cache-Control` / `ETag`, so a frontend can `fetch()` it directly. For images, an `<img src="">` works without any client-side glue.

= Can one site be both Host and Receiver? =

Yes. Set **Publish Library** and **Subscribe to Source** both ON in Settings. You'll see your own Library and the remote Source in separate tabs in the admin menu.

= How is the cache invalidated when I update a component? =

Every save bumps the component's version, which is also the `ETag`. The next request from a subscriber gets a fresh response; subsequent requests with `If-None-Match` get a fast `304 Not Modified`.

= Does the plugin require an external service? =

No. All data stays on your own WordPress sites. There are no calls to third-party servers, no telemetry, no SaaS dependencies.

= Can I require authentication between Host and Receiver? =

Yes. On the Host: **Components → Settings → Library Publishing → Access** can require an Application Password. On the Receiver: **Settings → Source Subscription → Authentication** lets you send Application Password credentials when fetching.

= What does it cost? =

Nothing. The plugin is GPL-2.0-or-later and free to use commercially.

== Screenshots ==

1. Onboarding — pick how this site participates: Publish, Subscribe, or Both.
2. Library — list of components published from this site, with version, cache TTL, and the live REST endpoint.
3. Component editor — slug, name, type, value (or file URL), cache TTL.
4. Sources — components pulled from a remote Host, refreshable on demand.
5. Settings — capability toggles, CORS policy, authentication, and connection test.

== Changelog ==

= 0.1.0 =
* First public release.
* Host / Receiver / Both modes via two independent capability toggles.
* JSON, text, and file component types.
* Per-component cache TTL with ETag-based revalidation and `304 Not Modified` support.
* Per-IP fixed-window rate limiting on host endpoints.
* CORS open / allowlist / denylist with subdomain wildcards.
* Independent Application Password auth on the publish and subscribe sides.
* Source connection test in Settings.

== Upgrade Notice ==

= 0.1.0 =
First public release on WordPress.org.
