CMS Publishing: 4 Paths From Studio Click to Live Article
Most AEO tools stop at the recommendations. AEO Content AI commits the article straight into your repo, your WordPress, or your Webflow CMS - with hero image, schema, and indexes regenerated in the same atomic operation.
One of 48 criteria in AEO Rank, the citation-readiness score we run against every site we audit.
By Alex Shortov
Quick Answer
AEO Content AI supports 4 publishing paths from Studio to your live site: nextjs-github for static Next.js sites driven by a topic-clusters.json manifest, github-content for plain Astro/Next.js repos, WordPress admin via REST API with stored credentials, and WordPress plugin for sites running our HMAC-signed AEO Content plugin. Each path runs as a single atomic commit or REST call, generates a Replicate Flux 1.1 Pro hero image when none exists, and regenerates sitemap.xml + llms.txt + llms-full.txt + feed.xml in the same commit. End-to-end takes 3 to 10 seconds for github paths and roughly 5 seconds for WordPress.
Audit Note
In our audits, we've measured CMS Publishing: 4 Paths From Studio Click to Live Article on live sites, we've compared implementations, and we've audited the gaps that keep scores low.
How does AEO Content AI publish articles to my live website?
AEO Content AI ships to your live site through 4 paths: nextjs-github, github-content, WordPress admin REST, or the AEO Content WordPress plugin.
Which CMS platforms does AEO Content AI support out of the box?
We support static Next.js with topic-clusters.json, plain Astro or Next.js repos via GitHub, WordPress with stored admin credentials, and WordPress sites running the AEO plugin.
What exactly happens after I click Publish in Studio?
Publish resolves the active connection, writes article files, regenerates indexes, optionally opens a PR, and logs each stage to aeo_published_articles for clean error surfacing.
Can I require my team to review articles before they go live?
Yes, flip use_pr on the connection and every publish opens a squash-merge pull request your team reviews on GitHub like any other code change.
Does the publisher update my sitemap, llms.txt, and RSS feed automatically?
Yes, sitemap, llms.txt, llms-full.txt, feed.xml, and topic-clusters-index.json all regenerate inside the same commit as the article so indexes never drift.
Summarize This Article With AI
Open this article in your preferred AI engine for an instant summary and analysis.
What this article answers
- How does AEO Content AI publish articles to my live website?
- Which CMS platforms does AEO Content AI support out of the box?
- What exactly happens after I click Publish in Studio?
- Can I require my team to review articles before they go live?
- Does the publisher update my sitemap, llms.txt, and RSS feed automatically?
Key takeaways
- Pick the path that matches your stack: static Next.js with topic-clusters.json -> nextjs-github; plain Astro / Next.js repo -> github-content; WordPress where we hold admin creds -> WP admin REST; WordPress with the AEO Content plugin installed -> WP plugin path.
- Studio enforces one active destination per domain through a DB partial unique index, an RPC, and the integrations UI - publishing two destinations at once is unreachable by design.
- Hero images auto-generate via Replicate Flux 1.1 Pro when og:image is empty - filename includes the content hash so a re-publish actually surfaces at the edge instead of getting pinned by CDN immutability headers.
- Sitemap, llms.txt, llms-full.txt, feed.xml, and topic-clusters-index.json regenerate inside the same commit as the article - no drift, no follow-up commit, no stale indexes.
- PR-first mode opens a squash-merge PR; the publisher polls GitHub’s mergeability endpoint every 500ms (max 10s) and only merges once GitHub flips the PR to a clean mergeable state.
- Authentication uses GitHub App installations by default - one App, many installations, no per-customer App registration. Personal Access Tokens encrypted with AES-256-GCM remain as a fallback for outside collaborators.
What Makes Studio Publishing Different From “Generate and Copy”?
Studio publishing commits articles into your repo, generates hero images, regenerates sitemaps, and surfaces live URLs in one click, eliminating twenty minutes of manual glue work per article.
Almost every AI-content tool stops at the artifact. You get a Word doc, a markdown file, or a styled preview. Then you copy. Paste. Find the hero image. Re-set the slug. Update the sitemap. Ping IndexNow. Trigger the rebuild. Twenty minutes of glue work between “the AI finished” and “the article is live.”
AEO Content AI ships the article. One Publish button in Studio commits the article into your repo, fires the hero image, regenerates the sitemap, and surfaces a live URL. The author writes the brief, reviews the draft, clicks once, and the page is on the internet.
That difference is not cosmetic. The whole point of an audit is to act on it - publish the content that fills the gap, then re-measure. A workflow that ends in “here’s the file, go integrate it” sends every gain to wait in someone’s Notion queue. Our shipping layer is why an audit recommendation that says “publish a cluster on insurance billing FAQs” is one of the cheapest projects on your roadmap, not the most expensive.
Which Publishing Path Should I Pick?
Studio offers 4 publishing paths, each tuned to a different site shape. The active connection lives in aeo_cms_connections.config and Studio picks the right transport automatically based on the active connection.
| Path | When to use | What ships |
|---|---|---|
nextjs-github | Static Next.js or Astro repo with a topic-clusters.json manifest at the root | Files written under the cluster’s content_dir, hero in assets_path, indexes regenerated, optional PR |
github-content | Static repo without a manifest - categories declared in the connection config | Same as above, just routed through explicit category config |
| WordPress (admin) | WordPress site where we hold an Application Password | REST POST to /wp-json/wp/v2/posts, optional Media upload for featured_media |
| WordPress (plugin) | WordPress site running the AEO Content WP plugin (HMAC-signed) | Plugin endpoint accepts JSON, runs wp_insert_post + sideloads the hero URL |
The first two share the same commit primitive in packages/shared/lib/publishing/github-content.ts - nextjs-github is a thin wrapper that resolves a cluster id from topic-clusters.json and translates that into the category file paths github-content expects.
Studio’s integrations page enforces an invariant: one active destination per domain. That guarantee lives at three layers - a partial unique index in Postgres, an activate_cms_connection RPC that atomically deactivates siblings before activating the target, and a Switch flow in the UI that explains the swap. You cannot accidentally publish to both your old WordPress and your new static repo on the same domain.
Studio offers four publishing paths, each tuned for a different CMS and content team workflow.
| Path | Best For | Setup Effort |
|---|---|---|
| WordPress plugin | WordPress sites | Install plugin, paste API key |
| GitHub App | Astro and static sites | Install app, choose repo |
| Webflow API | Webflow CMS | Connect site, map collection |
| Manual export | Custom CMS | Copy HTML or Markdown |
What Happens When I Click Publish?
The publish path is the same shape for every transport. Each stage logs to a aeo_published_articles row so failures surface as specific errors instead of “publish failed.”
Stage 1 - Resolve the active connection. Studio reads the active aeo_cms_connections row for the article’s domain. Provider determines transport; config carries the destination-specific fields (repo, branch, auth, hero settings).
Stage 2 - Generate the hero image if missing. The publisher checks four sources in order: (1) existing meta’s ogImage, (2) recipe_snapshot.og_image_url, (3) the first <img> tag in body HTML, (4) for WP plugin updates, the existing wpPostId. If all four are empty and the connection has auto_generate_hero: true, the publisher calls Replicate Flux 1.1 Pro with the article title + brand-anchored hero_style_prompt. Failure here is silent - publish proceeds without an image rather than blocking.
Stage 3 - Regenerate the in-commit indexes. For github paths, sitemap.xml, llms.txt, llms-full.txt, feed.xml, and topic-clusters-index.json are pulled from the full list of publishable articles in Supabase and rebuilt. The new article is included before the indexes render, so the sitemap and feed already contain the URL by the time the commit lands.
Stage 4 - Commit or POST atomically. The github paths use GitHub’s Git Data API to assemble one tree containing the article files + the regenerated indexes + the hero binary, then create one commit referencing that tree. WordPress paths POST the article body + featured image in a single REST or plugin call. Either way the live site sees the new article and the updated indexes at the same moment - no half-published states.
Stage 5 - PR merge (PR-first mode only). If the connection sets use_pr: true, the publisher opens a pull request instead of pushing to main. GitHub computes mergeability asynchronously after PR creation, so the publisher polls pulls.get every 500ms (max 10s) and squash-merges once mergeability resolves to true. If branch protection or required reviews block the merge, the PR stays open and Studio surfaces a merge_error in the publish panel for manual handling.
Stage 6 - Record the result. A row goes into aeo_published_articles with the commit SHA, the live URL, and timing metadata. Studio’s article toolbar flips review_status to 'published' and shows the URL.
How Does Hero Image Generation Work?
When all four image sources are empty, the publisher generates a hero using the article title and the connection’s per-site hero style prompt, keeping visual consistency across each domain.
A blank og:image tag is one of the most common publish-time mistakes - your article goes live but every social share renders a generic site fallback. We close that gap automatically.
When config.auto_generate_hero is true and the four detection sources all return empty, the publisher calls generateHeroImage() (or the URL-only variant for the WP plugin path) with the article title, an optional description, and the connection’s per-site hero_style_prompt. The latter is the anchor for visual consistency - understoodcare.com ships warm amber documentary photography across every article; helpsquad.com ships purple-to-lavender vector illustration. Same publisher, two completely different visual registers, controlled by a single string per connection.
The output is committed alongside the article in the same git tree. Filename defaults to {sha256-prefix}-{title-slug}.{ext}. Clusters can override that via hero_path_template in topic-clusters.json - for example public/images/blog/{slug}/hero-{hash}.{ext} to route hero images into a per-article folder. The {hash} placeholder is required, not optional - that requirement defends against a real bug we hit on Helpsquad’s first Studio publish. Stable-named assets behind Cloudflare Pages get pinned by Cache-Control: immutable, which means a re-publish with the same filename never actually surfaces at the edge. Forcing the hash into the path means every re-publish gets a new URL that bypasses the cache.
Can I Require Review Before Articles Go Live?
Flip the connection’s use_pr config flag on, and every publish opens a squash-merge pull request instead of pushing to main, plugging into branch protection and CODEOWNERS.
Yes - flip the connection’s use_pr config flag on, and every publish opens a squash-merge pull request instead of pushing straight to main. Your team reviews on GitHub the same way you review every other code change. Required reviews, branch protection, CODEOWNERS - all of it works because the publisher is producing a normal PR, not a special workflow.
If your CI pipeline takes a few seconds to compute mergeability, the publisher waits. We poll GitHub’s pulls.get endpoint every 500ms for up to 10 seconds, watching the mergeable field flip from null to true or false. Once GitHub has decided, we squash-merge. The PR title and body are templated so reviewers see what the article is, what cluster it belongs to, and which Studio execution produced it.
For solo operators who don’t need review, leaving use_pr off means every publish pushes one commit directly to the configured branch. Same atomic guarantees, just no PR overhead.
What Happens to My Sitemap, llms.txt, and Feed?
This is the part most “AI publishing” tools skip - and it’s what makes the difference between “an article that exists” and “an article that gets cited.”
When the publisher commits to a github connection, five index files regenerate in the same commit:
sitemap.xml- Includes the new article’s URL with its publish date aslastmod. Search Console can crawl the sitemap and pick the article up on its next pass.llms.txt- Adds the new article to your site’s machine-readable inventory. ChatGPT, Claude, and Perplexity all read llms.txt when deciding what content to crawl.llms-full.txt- The longer cousin of llms.txt with full article descriptions. Some engines prefer this for richer context.feed.xml- RSS feed updated so anyone subscribed (including newsreaders that AI engines crawl) sees the new article in their next poll.topic-clusters-index.json- A machine-readable map of which articles belong to which cluster - helps your site’s internal linking widgets and helps AI engines understand topical relationships.
All five files are computed from the full list of publishable articles, not patched - so a re-publish or a deletion produces a correct sitemap and feed every time. There is no separate “regenerate indexes” job. The same atomic commit that ships the article ships the indexes. No drift, no follow-up commit, no out-of-sync moments where the article exists but the sitemap hasn’t caught up.
Phase 2 - post-commit notifications like IndexNow ping, Google Indexing API calls, and CDN cache purges - exists in code but is currently not wired into the live publish flow. We default to letting search engines discover the article via sitemap polling and standard crawler cadence.
How Customers Actually Use This
Understoodcare and HelpSquad both run nextjs-github publishing with distinct hero styles, opening PRs that regenerate every index and squash-merge within seconds of operator approval.
Two production examples illustrate how different sites use the same pipeline.
understoodcare.com runs the nextjs-github path against repo Data-Subsystems/understoodcare-website, GitHub App installation 125137558. Their topic-clusters.json declares two clusters (Care Guides + Caregiver Stories), each routed to a different content_dir with a folder_meta_body file layout. Every Studio publish to UnderstoodCare opens a PR, generates a warm amber documentary hero, regenerates all five indexes, and squash-merges within seconds. The team reviews the PR on GitHub and either approves or comments - same workflow as any code change.
helpsquad.com also runs nextjs-github, but against an Astro repo deployed to Cloudflare Pages. Installation 126531754, repo Data-Subsystems/helpsquad-website, purple/lavender vector hero style. Helpsquad migrated from WordPress to this static stack on 2026-05-06 - the same publishing pipeline that worked under WordPress kept working post-migration, no Studio config change needed. That portability is the point of the four-path architecture.
Both sites use App-based auth - no Personal Access Tokens, no shared credentials. The publisher authenticates per-publish as the AEO Content Publisher App installation on the customer’s repo.
What Publishing Means for Your AEO Score
Publishing moves Fact Density, Q&A Format, Internal Linking, Schema Markup, and llms.txt Quality simultaneously because each shipped article touches multiple AEO Rank criteria at once.
Publishing itself is not a scoring criterion - it is the action that moves your scoring criteria. An article that exists in Studio but never reaches your live site does zero for your AEO Site Rank. An article that ships, complete with hero, schema, and updated llms.txt, lifts multiple criteria at once:
- Fact Density, Q&A Format, Direct Answer Density (Answer Readiness pillar) - lifted by the article body itself
- Internal Linking (Trust & Authority pillar) - lifted by the publisher’s category routing and topic-cluster awareness
- Schema Markup (Trust & Authority pillar) - lifted by the Article + Organization JSON-LD blocks included in every published article
- llms.txt (AI Discovery pillar) - lifted by the in-commit llms.txt regeneration
- Sitemap Completeness (AI Discovery pillar) - lifted by the in-commit sitemap regeneration
A single published article touches roughly 6-8 of the 48 criteria. A weekly publishing cadence across a cluster of 6-12 articles touches every criterion in the Answer Readiness and AI Discovery pillars on a recurring basis. That is the compound effect - publish consistently and the score lifts itself.
External Resources
- AEO Content Publisher GitHub App - https://github.com/apps/aeo-content-publisher
- GitHub Apps documentation - https://docs.github.com/en/apps
- WordPress Application Passwords - https://wordpress.org/documentation/article/application-passwords/
- Replicate Flux 1.1 Pro - https://replicate.com/black-forest-labs/flux-1.1-pro
- sitemap.xml protocol - https://www.sitemaps.org/protocol.html
- llms.txt Specification - https://llmstxt.org
Related topics
Key takeaways
- Pick the path that matches your stack: static Next.js with topic-clusters.json -> nextjs-github; plain Astro / Next.js repo -> github-content; WordPress where we hold admin creds -> WP admin REST; WordPress with the AEO Content plugin installed -> WP plugin path.
- Studio enforces one active destination per domain through a DB partial unique index, an RPC, and the integrations UI - publishing two destinations at once is unreachable by design.
- Hero images auto-generate via Replicate Flux 1.1 Pro when og:image is empty - filename includes the content hash so a re-publish actually surfaces at the edge instead of getting pinned by CDN immutability headers.
- Sitemap, llms.txt, llms-full.txt, feed.xml, and topic-clusters-index.json regenerate inside the same commit as the article - no drift, no follow-up commit, no stale indexes.
- PR-first mode opens a squash-merge PR; the publisher polls GitHub's mergeability endpoint every 500ms (max 10s) and only merges once GitHub flips the PR to a clean mergeable state.
- Authentication uses GitHub App installations by default - one App, many installations, no per-customer App registration. Personal Access Tokens encrypted with AES-256-GCM remain as a fallback for outside collaborators.