Content Pipelines
Content Pipelines is a built-in SyteOps feature that automatically runs a sequence of content-processing stages when a post is published. Each pipeline recipe defines which stages run, in what order, and under what conditions.
Getting Started
Content Pipelines is built in to SyteOps — there's nothing to upload or activate. It's available out of the box, and you'll find it in its own Content Pipelines tab in the SyteOps admin.
The Content Pipelines Tab
Open Content Pipelines from the Content Pipelines link in the SyteOps admin sidebar (or the Content Pipelines tab in SyteOps settings). The tab has several views, accessible from the quick-nav pills at the top.
Runs dashboard
The Runs dashboard shows every pipeline execution:
- Stat cards show total runs, runs in the last 7 days, posts that were changed, and error counts.
- Filter pills let you filter by recipe, status (OK, Errors, Skipped), or source (Direct — post-processing runs you trigger or that fire on publish/schedule — or each content source you've registered).
- Run now lets you trigger a pipeline manually for any post — choose a recipe, enter a Post ID, and optionally enable dry-run mode to preview changes without writing them.
- Runs table lists each execution with the source (Direct for post-processing runs, or a content source), the recipe used, post, status, which stages ran, whether the post was changed, and the trigger type.
- Click a row to expand the stage drawer, which shows the result of each stage with its message and duration.
Provider status cards
At the very top of the Runs view, above the stat cards, a row of cards shows whether each pipeline provider is wired up:
- Content sources — one card for each content source you've registered, shown by its name, indicating whether it's connected and receiving content.
- Link Engines, SEO, and GEO — the processing stages.
Each card shows a status — Ready, Off, Needs setup, or Not installed — and a link that takes you straight to that provider's settings to finish wiring it up. Use it as a quick checklist: every card should read Ready before you rely on a recipe that uses that stage.
The GEO card adds a one-click Turn on / Turn off button that enables or disables AI Search Discovery right from the card — no need to leave the page. When the LLMS Amplifier plugin is installed, the card also shows a button to switch which engine generates your llms.txt — see Choosing a GEO engine below.
Recipes
Recipes define how your pipeline behaves:
- The default recipe runs all available stages in sequence. It cannot be deleted.
- Custom recipes let you configure stage order, enable or disable individual stages, adjust LinkCentral dial-in settings, set trigger conditions (post types, tags), and define policies (skip unchanged posts, stop or continue on error, dry-run mode).
- Use the Add recipe button to open the recipe builder.
Recipe Builder
The builder walks you through four sections:
- Recipe name and priority — Give the recipe a name and set its priority (lower numbers run first when multiple recipes match).
- Stages — Enable or disable individual stages and drag them into the order you want. The Link Engines stage includes LinkCentral dial-in settings to fine-tune cross-linking behavior.
- Trigger — Choose when the recipe fires: on auto-publish or manual trigger only. Optionally restrict to specific post types or tag slugs.
- Policy — Control what happens when content hasn't changed (skip it), when a stage errors (stop or continue), and whether to run in dry-run (preview) mode.
Available Stages
| Stage | What it does |
|---|---|
| Link Engines | Adds cross-links to published content based on your LinkCentral keyword index |
| SEO | Applies Squirrly SEO metadata using your configured settings |
| GEO | Regenerates your llms.txt file to reflect the new content |
Stages that depend on other integrations (LinkCentral, Squirrly SEO) are available only when those integrations are active and configured.
Choosing a GEO engine
GEO is an either/or step — your site's llms.txt is generated by exactly one engine at a time:
- Native — the built-in generator. On by default.
- LLMS Amplifier — a richer alternative (
llms.txtplusllms-full.txt, drawing from more content sources) from the LLMS Amplifier integration, once its plugin is installed.
You don't pick the engine per recipe — it's one site-wide switch on the GEO provider status card at the top of the Runs dashboard. When the LLMS Amplifier plugin is installed, the card shows a button to switch engines: Use LLMS Amplifier engine (or Use native engine to switch back). Turning the LLMS Amplifier integration on or off from the Integrations tab has the same effect.
Turning LLMS Amplifier on takes care of the rest of the setup for you — it automatically sets Amplifier's own update frequency to Manual (so it regenerates only when your pipeline tells it to, not on a separate schedule of its own) and turns AI Search Discovery on. Turning it off switches straight back to the native engine; AI Search Discovery itself is never turned off as a side effect of switching engines.
Switching engines doesn't change the per-article Analyze GEO readiness check in the Review & Publish portal — that readiness score and the Include in llms.txt / AI answer feed toggle work the same way no matter which engine generates the file.
Social Publishing
Social Publishing's Enable Social Publishing switch and its full configuration — AI provider, voice profiles, and destinations — live together in one place on this tab. See Social Publishing for setup.
Dry-Run Mode
Enable dry-run on a recipe or on a manual run to preview what would change without actually writing to the database. Dry-run results appear in the Runs dashboard with a "Preview" badge.
Content Calendar
The Calendar view gives you a month-at-a-glance look at your content: recent, draft, scheduled, and published posts, all in one place.
Open it from the quick-nav pills at the top of the Content Pipelines tab, alongside Runs, Recipes, and Content Sources.
Each post appears as a chip with a colored bar on the left showing its status:
| Color | Status |
|---|---|
| Teal | Scheduled |
| Green | Published |
| Amber | Pending review |
| Gray | Draft |
Drafts that don't have a publish date yet appear in the Unscheduled drafts list next to the grid, instead of on a specific day.
Rescheduling and scheduling posts
- Move a scheduled post — drag its chip from one day to another to change when it goes live.
- Schedule a draft — drag a post from the Unscheduled drafts list onto a day to give it a publish date.
- Pick an exact time — click a post to open a small picker where you can choose the exact date and time instead of dragging.
A few rules apply:
- You can only move posts you have permission to edit.
- Scheduling a draft (turning it into a scheduled post) requires permission to publish, following the same Who can publish rule used in the Review & Publish portal.
- Published posts are read-only on the calendar — they can't be dragged or rescheduled.
Showing all content
By default, the calendar shows only content your pipeline has touched — posts imported from a content source, plus posts a recipe has run against. Turn on Show all content at the top of the calendar to also include every post, page, or other content type, whether or not the pipeline has touched it, so you can see everything on your editorial schedule in one view.
Content Sources
Content Sources let any external application — not just ContentPen — send finished articles into SyteOps as review-ready drafts. Each source you register gets its own Ingest URL and a webhook secret. When the app posts an article to that URL, SyteOps maps the incoming fields onto the editor and creates a draft in the Review & Publish portal, where your team reviews and publishes it.
Open the Content Sources view from the quick-nav pills at the top of the Content Pipelines tab.
Receiving content from an external app
Any external content app can deliver finished articles straight into a content source — ContentPen is the built-in example, and existing ContentPen setups are carried over for you automatically. The app posts each article to the source's Ingest URL; unless you turn verification off, it signs each request with the source's webhook secret so SyteOps can confirm the request is genuine before mapping the fields onto the editor and creating a Review & Publish draft for your team — nothing is published without a human approving it.
You can tailor how each source proves and processes its content, and every option below is set per source, so different apps can be handled differently:
- Verification secret — the shared secret used to check each request. Leave it blank and SyteOps generates one for you (shown once), or paste the sending app's own signing secret if it supplies one (for example, a ContentPen webhook secret). If a sender can't sign at all, you can turn verification off entirely (see None below).
- Signature header — choose which request header the sending app signs with, so a source can match whatever your app already sends.
- AI categories and tags — let SyteOps read each incoming article and suggest categories and tags for it.
- Author matching — match the article's stated author to one of your registered team members (by email or last name), falling back to a default author when there's no match.
- Target tag — automatically add a tag of your choosing to every post from this source, so you can find and group its content later.
- Display cleanup — tidy the article's markup when the post is shown on your site.
Register a content source
- In the Content Sources card, enter a Source name (for example, "Marketing CMS").
- Choose an Auth mode — how the sending app proves each request is genuine:
- HMAC signature (recommended) — the app signs every request with the secret.
- Bearer token — the app sends the secret in an
Authorizationheader. - HMAC or bearer — accept either.
- None (no verification) — accept requests with no signature, token, or secret at all. Choose this only for a sender that can't sign; the unguessable Ingest URL becomes the only thing protecting the source, so treat that URL like a password.
- (Optional) If the sending app supplies its own signing secret, expand the verification fields and paste it into Verification secret — leave it blank to have SyteOps generate one for you. You can also set a custom signature header here if the app signs with its own header name (for example,
X-Contentpen-Signature). These fields are hidden when Auth mode is None. - Click Add source.
What SyteOps shows next depends on how the secret was set:
- SyteOps generated the secret — a highlighted box labeled Save this secret now — it is shown only once displays the Ingest URL and the Webhook secret. Copy the secret and store it somewhere safe (a password manager, or the sending app's settings). If you ever lose it, use Rotate secret on the source to generate a new one — the old secret stops working immediately.
- You pasted your own secret, or chose None — there's no secret to reveal (you already have it, or there isn't one), so the box shows just the Ingest URL and a Done button.
Point your app at the Ingest URL
Configure the sending application's webhook to POST its article as JSON to the source's Ingest URL. How it authenticates depends on the Auth mode you chose:
| Auth mode | What the app sends |
|---|---|
| HMAC signature | An X-SyteOps-Signature header (or your chosen custom header) in the form t=<timestamp>,v1=<hex>, signed with the secret. If your secret begins with whsec_, drop that prefix and sign with the remaining characters. |
| Bearer token | An Authorization: Bearer <secret> header using the full secret string, including any whsec_ prefix. |
| None | Nothing extra — just the POST to the Ingest URL. SyteOps accepts it without any check, so keep the URL secret. |
You can copy the URL again at any time with Copy URL on the source card.
Send a sample and approve the mapping
Before content flows automatically, SyteOps needs to learn how the app's JSON maps onto editor fields (title, body, excerpt, and so on).
- Have the app send one article to the Ingest URL. SyteOps captures it and holds the source in a pending state — no draft is created yet. (You can also paste an example into the Sample payload (JSON) box on the source card.)
- Click Learn from sample. SyteOps proposes a Field mapping, filling each row's Path (a location inside the payload), an optional Transform, and a Confidence score. You can hand-write or adjust any row yourself.
- Click Test with sample to preview what each field would receive.
- When the mapping looks right, click Approve mapping.
Once approved, the source goes active: every future post to its Ingest URL becomes a Review & Publish draft automatically, using the same mapping. Any field the mapping doesn't fill is simply left blank for the reviewer to complete.
Visual payload mapper
Instead of typing a Path into a mapping row by hand, you can point and click.
Every source has a sticky Payload panel on its card that shows a real payload as a clickable tree:
- If the source has received content before, the panel shows the last payload it received — SyteOps automatically remembers the most recent one for each source. This is visible only to you in the SyteOps admin; it's never exposed anywhere public.
- If the source hasn't received anything yet, paste an example into the Sample payload (JSON) box and the panel shows that instead.
To map a field visually, use whichever is quicker:
- Dropdown (fastest): click into the Path box for the field you want to map (in Field mapping or a FlowMattic config variable — see below). A dropdown of every path in the current payload appears right there — start typing to filter it, then click a row (or use the arrow keys and Enter) to fill it in.
- Tree: click into the Path box, then in the sticky Payload panel click through the tree to find the value you want and click it.
Either way, SyteOps fills in the location of the value you picked, not the value itself. That means the mapping keeps working correctly on every future payload, even though the specific text you saw was only ever from one example — nothing is frozen to that one sample.
Clearing remembered payloads. Each source's Payload panel has a Clear button that forgets just that source's last payload. To forget them all at once, use Delete all captured payloads at the top of the Content Sources page (it appears once at least one source has a remembered payload).
Per-source settings
Expand Settings on a source card to control:
| Setting | What it does |
|---|---|
| Source name | The label shown for this source. |
| Default author | The WordPress user credited as the post author. Tick Always use this author to override whatever the payload suggests. |
| Default post status | Draft or Publish. This is set here only — the incoming payload can never publish content on its own. |
| Auth mode | Change the accepted authentication style (HMAC, Bearer, HMAC or bearer, or None). |
| Verification secret | Paste a new secret to replace the current one (for example, when the sending app rotates its own key). Leave it blank to keep the existing secret — for security it's never shown here, only a (configured) or (not set) indicator. Ignored when Auth mode is None. |
| Inbound signature header | Whether the sender signs with the standard X-SyteOps-Signature header or a custom header name of your choosing. |
Use Rotate secret to have SyteOps generate a brand-new secret (and reveal it once), Verification secret to paste one the sender gave you, Disable to pause a source without deleting it, and Delete to remove it permanently.
Choose where drafts land
By default, every source's drafts are created as regular Posts. You can point a source somewhere else instead — either when you register it, or later from its card.
- Send into an existing content type — Expand Settings on the source's card and choose from Land drafts into: Posts, Pages, or any other content type already on your site (including a type created by another content source).
- Define a brand-new content type — When registering the source, set Land drafts into to Define a new type, then fill in:
| Field | What it does |
|---|---|
| Singular name / Plural name | What the content type is called (for example "Listing" / "Listings"). |
| Supports | Which editing features it has: Title, Content editor, Excerpt, Featured image, Custom fields, Author. |
| Taxonomies | Whether it uses Categories, Tags, or both. |
SyteOps creates the content type for you, and every draft from this source lands there from then on. A new type's name, supported features, and taxonomies are locked in when the source is created and can't be changed afterward, so plan them before you register the source. (You can still switch the source to a different existing content type later from its card — only defining a brand-new type is a one-time choice.)
Add custom fields
If a source's articles carry information beyond the standard title, body, and excerpt — a SKU, a price, a source URL — expand Custom fields (post meta) on its card and add one row per field:
| Column | What it does |
|---|---|
| Field key | A short internal name (lowercase letters, numbers, underscores). |
| Label | The friendly name shown in the mapping table. |
| Type | How the value is handled: Text, Text area, Number, Yes/No, URL, or Date. |
Click Add field for each one you need, then Save custom fields. Every field you define shows up as its own row in Field mapping, so you can point it at the right location in the incoming payload just like the built-in fields. Once mapped, the values are saved as custom fields (post meta) on the draft.
FlowMattic config variables
Expand FlowMattic config variables on a source's card to define named values that automations can read for that specific source — a brand name, a campaign id, a routing tag, or anything else your workflows need.
- Enter a Key (lowercase letters, numbers, and underscores) and a Value.
- SyteOps shows the resulting FlowMattic variable name next to each entry — copy that exact name to reference it in your FlowMattic workflows.
- Click Add variable for each one you need, then Save FlowMattic variables.
Because each source's variables are named after that source, two sources can use the same key (for example, both defining a brand value) without colliding.
Dynamic FlowMattic variables
Each FlowMattic config variable row has a Source setting, so its value can either stay fixed or change with every article:
- Static — a value you type once, same as above. Good for things that never change, like a brand name or a routing tag.
- From payload — instead of typing a value, use the payload picker (the same clickable tree described in Visual payload mapper) to choose where in each incoming article the value should come from. SyteOps resolves it fresh for every article as it arrives, so something like a campaign id or a source URL that's different on every article stays accurate automatically — no manual updates needed.
From payload variables are only useful once they're actually sent somewhere, so they travel along with each mapped article to your Forward to workflow webhook (see below) — one resolved value per article, per variable. Because of that, From payload requires Forward to workflow to be turned on for the source. A Static variable doesn't have that requirement — it works whether or not forwarding is enabled.
Forward to a workflow
Expand Forward to workflow on a source's card to also send each mapped article to a FlowMattic workflow webhook, in addition to creating the Review & Publish draft.
- Turn on Enable forwarding.
- Enter the Workflow webhook URL from FlowMattic.
- Pick an Auth mode — None, Bearer token, Basic auth, or Bearer + Basic — to match what the workflow expects, and enter the matching Auth secret (leave it blank to keep whatever secret is already saved).
- Click Save forwarding settings.
Forwarding is optional and never gets in the way: SyteOps always creates the Review & Publish draft first, then sends a copy of the mapped content to your workflow in the background. A slow or unreachable workflow endpoint never delays or blocks the draft.