{"id":318891,"date":"2026-08-07T05:54:48","date_gmt":"2026-08-07T05:54:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/components\/"},"modified":"2026-08-07T05:54:30","modified_gmt":"2026-08-07T05:54:30","slug":"artificial-poets-reusable-components-cdn","status":"publish","type":"plugin","link":"https:\/\/lij.wordpress.org\/plugins\/artificial-poets-reusable-components-cdn\/","author":23274321,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"0.1.0","stable_tag":"0.1.0","tested":"7.0.3","requires":"6.0","requires_php":"8.0","requires_plugins":null,"header_name":"Artificial Poets Reusable Components CDN","header_author":"Artificial Poets","header_description":"Turn your WordPress site into a content delivery network for reusable components \u2014 JSON, text, and files \u2014 shared across sites via the REST API, with per-component caching and ETag-based revalidation.","assets_banners_color":"","last_updated":"2026-08-07 05:54:30","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/artificialpoets.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":58,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"0.1.0":{"tag":"0.1.0","author":"artificialpoets","date":"2026-08-07 05:54:30"}},"upgrade_notice":{"0.1.0":"<p>First public release on WordPress.org.<\/p>"},"ratings":[],"assets_icons":[],"assets_banners":[],"assets_blueprints":{},"all_blocks":[],"tagged_versions":["0.1.0"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Onboarding \u2014 pick how this site participates: Publish, Subscribe, or Both.","2":"Library \u2014 list of components published from this site, with version, cache TTL, and the live REST endpoint.","3":"Component editor \u2014 slug, name, type, value (or file URL), cache TTL.","4":"Sources \u2014 components pulled from a remote Host, refreshable on demand.","5":"Settings \u2014 capability toggles, CORS policy, authentication, and connection test."}},"plugin_section":[],"plugin_tags":[146,141196,1118,23853,1558],"plugin_category":[52],"plugin_contributors":[241942],"plugin_business_model":[],"class_list":["post-318891","plugin","type-plugin","status-publish","hentry","plugin_tags-cache","plugin_tags-headless","plugin_tags-json","plugin_tags-rest-api","plugin_tags-sync","plugin_category-performance","plugin_contributors-artificialpoets","plugin_committers-artificialpoets"],"banners":[],"icons":{"svg":false,"icon":"https:\/\/s.w.org\/plugins\/geopattern-icon\/artificial-poets-reusable-components-cdn.svg","icon_2x":false,"generated":true},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>WP Components<\/strong> lets one WordPress site act as a Host that publishes a Library of named pieces of content \u2014 a logo, a tagline, a social-links JSON blob, a privacy notice \u2014 and any number of other sites act as Receivers that subscribe to that Host and consume those components instantly.<\/p>\n\n<p>Every component has a stable slug, a type (<code>json<\/code>, <code>text<\/code>, or <code>file<\/code>), a per-component cache TTL, and an auto-incrementing version number that becomes its HTTP <code>ETag<\/code>. Subscribers fetch the latest version on demand and revalidate cheaply with <code>304 Not Modified<\/code> for unchanged content.<\/p>\n\n<p>A single site can also act as <strong>both<\/strong> Host and Receiver \u2014 publish your own Library while subscribing to one or more remote Hosts.<\/p>\n\n<h4>Use cases<\/h4>\n\n<ul>\n<li>Keep brand assets (logo, favicon, tagline, contact info) in sync across a fleet of WordPress sites without copy-paste.<\/li>\n<li>Centralise structured data (footer links, locations, pricing tables) so updating once propagates everywhere.<\/li>\n<li>Serve component content from a dedicated CDN subdomain via a thin reverse-proxy layer.<\/li>\n<li>Pull versioned content into a headless frontend (Next.js, Astro, Vercel) with stable cache semantics.<\/li>\n<\/ul>\n\n<h4>Key features<\/h4>\n\n<ul>\n<li><strong>Three component types<\/strong> \u2014 JSON, plain text, and file (proxies URLs through the REST endpoint).<\/li>\n<li><strong>Two independent capabilities<\/strong> \u2014 publish your Library and\/or subscribe to a remote Host. Toggle each side on or off in Settings.<\/li>\n<li><strong>HTTP cache headers<\/strong> \u2014 every <code>\/raw<\/code> response sends <code>ETag<\/code>, <code>Last-Modified<\/code>, and <code>Cache-Control: public, max-age=&lt;TTL&gt;, must-revalidate<\/code>. Conditional requests get <code>304 Not Modified<\/code>.<\/li>\n<li><strong>Per-IP rate limiting<\/strong> \u2014 120 requests per 60 seconds on the host endpoints.<\/li>\n<li><strong>CORS control<\/strong> \u2014 open, allowlist, or denylist by domain (with <code>*.example.com<\/code> wildcard support).<\/li>\n<li><strong>Optional authentication<\/strong> \u2014 require Application Passwords on either side independently.<\/li>\n<li><strong>Source connection tester<\/strong> \u2014 verify a Host URL from the Settings page before saving.<\/li>\n<li><strong>Native admin UI<\/strong> \u2014 built on WordPress admin patterns, fully translatable.<\/li>\n<\/ul>\n\n<h4>REST endpoints (Host mode)<\/h4>\n\n<ul>\n<li><code>GET \/wp-json\/wp-components\/v1\/components<\/code> \u2014 list all published components<\/li>\n<li><code>GET \/wp-json\/wp-components\/v1\/components\/{slug}<\/code> \u2014 fetch one as JSON metadata<\/li>\n<li><code>GET \/wp-json\/wp-components\/v1\/components\/{slug}\/raw<\/code> \u2014 fetch with type-appropriate <code>Content-Type<\/code> (text\/plain, application\/json, or proxied file bytes)<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Install the plugin from <strong>Plugins \u2192 Add New<\/strong> and search for <em>Artificial Poets Reusable Components CDN<\/em>, or upload the <code>.zip<\/code> via <strong>Plugins \u2192 Add New \u2192 Upload Plugin<\/strong>.<\/li>\n<li>Activate <strong>Artificial Poets Reusable Components CDN<\/strong> under <strong>Plugins \u2192 Installed Plugins<\/strong>.<\/li>\n<li>Open <strong>Components<\/strong> in the admin menu; the onboarding screen asks how you want this site to participate.<\/li>\n<li><strong>Publish only<\/strong> to expose a Library via REST. <strong>Subscribe only<\/strong> to pull from another Host. <strong>Both<\/strong> to do both.<\/li>\n<li>If subscribing, enter the Host URL under <strong>Components \u2192 Settings \u2192 Source Subscription<\/strong> and click <em>Test Connection<\/em>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"does%20this%20work%20for%20headless%20wordpress%20%2F%20next.js%20%2F%20astro%20frontends%3F\"><h3>Does this work for headless WordPress \/ Next.js \/ Astro frontends?<\/h3><\/dt>\n<dd><p>Yes. The Host's <code>\/wp-json\/wp-components\/v1\/components\/{slug}\/raw<\/code> endpoint returns the content with the right <code>Content-Type<\/code> header and proper <code>Cache-Control<\/code> \/ <code>ETag<\/code>, so a frontend can <code>fetch()<\/code> it directly. For images, an <code>&lt;img src=\"\"&gt;<\/code> works without any client-side glue.<\/p><\/dd>\n<dt id=\"can%20one%20site%20be%20both%20host%20and%20receiver%3F\"><h3>Can one site be both Host and Receiver?<\/h3><\/dt>\n<dd><p>Yes. Set <strong>Publish Library<\/strong> and <strong>Subscribe to Source<\/strong> both ON in Settings. You'll see your own Library and the remote Source in separate tabs in the admin menu.<\/p><\/dd>\n<dt id=\"how%20is%20the%20cache%20invalidated%20when%20i%20update%20a%20component%3F\"><h3>How is the cache invalidated when I update a component?<\/h3><\/dt>\n<dd><p>Every save bumps the component's version, which is also the <code>ETag<\/code>. The next request from a subscriber gets a fresh response; subsequent requests with <code>If-None-Match<\/code> get a fast <code>304 Not Modified<\/code>.<\/p><\/dd>\n<dt id=\"does%20the%20plugin%20require%20an%20external%20service%3F\"><h3>Does the plugin require an external service?<\/h3><\/dt>\n<dd><p>No. All data stays on your own WordPress sites. There are no calls to third-party servers, no telemetry, no SaaS dependencies.<\/p><\/dd>\n<dt id=\"can%20i%20require%20authentication%20between%20host%20and%20receiver%3F\"><h3>Can I require authentication between Host and Receiver?<\/h3><\/dt>\n<dd><p>Yes. On the Host: <strong>Components \u2192 Settings \u2192 Library Publishing \u2192 Access<\/strong> can require an Application Password. On the Receiver: <strong>Settings \u2192 Source Subscription \u2192 Authentication<\/strong> lets you send Application Password credentials when fetching.<\/p><\/dd>\n<dt id=\"what%20does%20it%20cost%3F\"><h3>What does it cost?<\/h3><\/dt>\n<dd><p>Nothing. The plugin is GPL-2.0-or-later and free to use commercially.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>0.1.0<\/h4>\n\n<ul>\n<li>First public release.<\/li>\n<li>Host \/ Receiver \/ Both modes via two independent capability toggles.<\/li>\n<li>JSON, text, and file component types.<\/li>\n<li>Per-component cache TTL with ETag-based revalidation and <code>304 Not Modified<\/code> support.<\/li>\n<li>Per-IP fixed-window rate limiting on host endpoints.<\/li>\n<li>CORS open \/ allowlist \/ denylist with subdomain wildcards.<\/li>\n<li>Independent Application Password auth on the publish and subscribe sides.<\/li>\n<li>Source connection test in Settings.<\/li>\n<\/ul>","raw_excerpt":"Turn your WordPress site into a content delivery network for reusable components \u2014 JSON, text, and files \u2014 shared across sites.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/318891","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=318891"}],"author":[{"embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/artificialpoets"}],"wp:attachment":[{"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=318891"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=318891"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=318891"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=318891"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=318891"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/lij.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=318891"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}