WordPress + OpenAI, SEO posts published on autopilot
Your content calendar looks fine on paper. Then the week starts, client work piles up, and posting “just one SEO article” turns into a messy chain of drafts, images, categories, WordPress logins, and second-guessing.
Content managers feel it first. A small business owner running marketing solo feels it right after. And agency leads get stuck reviewing half-finished docs at 9pm. This WordPress OpenAI automation fixes the bottleneck by drafting and publishing for you, on a schedule, with clean structure and the right category every time.
You’ll see how the workflow picks a category intelligently, generates a real SEO-ready post (not a flimsy blob of text), uploads a featured image, and publishes via the WordPress API. Then you can decide how hands-off you want it.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: WordPress + OpenAI, SEO posts published on autopilot
flowchart LR
subgraph sg0["Scheduled Run Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Scheduled Run Trigger", pos: "b", h: 48 }
n1@{ icon: "mdi:swap-vertical", form: "rounded", label: "Set Domain Config", pos: "b", h: 48 }
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Fetch WP Categories"]
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Filter Category IDs"]
n4["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Query Recent Categories"]
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Select Least Used"]
n6["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Retrieve Recent Titles"]
n7@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Mini Model", pos: "b", h: 48 }
n8@{ icon: "mdi:robot", form: "rounded", label: "Generate SEO Title", pos: "b", h: 48 }
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Format New Title"]
n10["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Combine Title Data"]
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Aggregate Post Metadata"]
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/postgres.svg' width='40' height='40' /></div><br/>Upsert Category Usage"]
n13@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Main Model", pos: "b", h: 48 }
n14@{ icon: "mdi:robot", form: "rounded", label: "Draft Article Content", pos: "b", h: 48 }
n15["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Extract Article Blocks"]
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Build Placeholder Image"]
n17["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Fetch Placeholder Image"]
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Upload Media to WP"]
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/merge.svg' width='40' height='40' /></div><br/>Merge Content Streams"]
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Assemble Post Payload"]
n21["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Publish WordPress Post"]
n22@{ icon: "mdi:cog", form: "rounded", label: "Finalize Workflow", pos: "b", h: 48 }
n19 --> n20
n1 --> n2
n21 --> n22
n10 --> n11
n17 --> n18
n3 --> n4
n2 --> n3
n5 --> n6
n5 --> n10
n0 --> n1
n4 --> n5
n15 --> n19
n9 --> n10
n13 -.-> n14
n20 --> n21
n12 --> n14
n12 --> n19
n18 --> n19
n7 -.-> n8
n6 --> n8
n14 --> n16
n14 --> n15
n16 --> n17
n8 --> n9
n11 --> n12
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0 trigger
class n8,n14 ai
class n7,n13 aiModel
class n4,n6,n12 database
class n2,n17,n18,n21 api
class n3,n5,n9,n11,n15,n16,n20 code
classDef customIcon fill:none,stroke:none
class n2,n3,n4,n5,n6,n9,n10,n11,n12,n15,n16,n17,n18,n19,n20,n21 customIcon
The Problem: Consistent SEO publishing breaks down in the last mile
Writing is only half the job. The other half is the repetitive “publishing tax”: pick a category (and don’t overuse the same one), format headings, build a table of contents, add a CTA, create a cover image, upload it, set it as featured, paste everything into WordPress, then realize you forgot to tag the right category and now your site navigation looks sloppy. Do that a few times a week and you burn hours on tasks that don’t improve rankings. Worse, the work is error-prone, which means fixes, re-uploads, and broken consistency.
It adds up fast. Here’s where it breaks down.
- You lose about 30–45 minutes per post just moving content from “draft” to “published.”
- Categories get reused because nobody remembers what was used last, so your content mix gets lopsided.
- Featured images turn into a scavenger hunt, which slows publishing and hurts visual consistency.
- Formatting and SEO blocks get skipped when you’re rushing, so posts go live “good enough” and stay that way.
The Solution: Auto-generate and publish structured SEO posts to WordPress
This n8n workflow runs on a schedule and behaves like a careful editor who never forgets the details. It starts by pulling your WordPress categories, then checks a PostgreSQL table that tracks which categories have been used recently. Instead of guessing, it selects the least-used category so your site stays balanced and you avoid accidental repeats. Next, it asks OpenAI (GPT-4-mini or better) to generate an SEO-friendly title, validates and formats that title, and then generates a fully formatted article with headings, a table of contents, lists, a CTA, and Yoast-style blocks. Finally, it creates a placeholder cover image, uploads it to WordPress Media, attaches it as the featured image, and publishes the post via the WordPress REST API.
The workflow kicks off from a scheduled trigger. From there, category rotation and title generation happen before the long-form draft, so the post is “born” with the right structure. Publishing is handled programmatically through /wp-json/wp/v2/posts, which means it lands in WordPress already categorized and ready to be found.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish 3 SEO posts a week. Manually, a typical “last mile” looks like 10 minutes to format, 10 minutes to hunt or create an image, and 10–15 minutes to upload, categorize, and double-check, which is roughly 2 hours weekly just on publishing tasks. With this workflow, you spend about 5 minutes setting the topic direction (or approving the output), then the scheduled run handles drafting and posting while you do other work. Even if you still review before going live, you’re no longer doing the repetitive uploading and setup.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- WordPress for publishing posts and media via API
- OpenAI to generate titles and SEO article content
- PostgreSQL credentials (create in n8n; DB stores used categories)
Skill level: Intermediate. You’ll connect credentials, run a short SQL setup, and test a few nodes before scheduling.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A scheduled run kicks everything off. You decide the cadence (daily, a few times a week, whatever fits), and n8n starts the workflow automatically without anyone logging in.
Category rotation happens before writing. The workflow fetches categories from WordPress, checks a PostgreSQL table of recently used categories, and selects the least-used one so your content stays evenly distributed.
OpenAI generates title and article content. First it creates a title based on what you’ve posted recently, then drafts a full SEO article with the structure you’d normally build by hand (headings, TOC, lists, CTAs, and Yoast-style blocks).
WordPress publishing is automatic. A placeholder cover image is created and uploaded to WordPress Media, then the final post payload is assembled and published through the WordPress REST API with the correct category and featured image set.
You can easily modify the article prompt to match your brand voice based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Scheduled Trigger
This workflow runs on a schedule and initializes domain settings before retrieving WordPress data.
- Add or open Scheduled Run Trigger and set the schedule rule to run every hour (the node uses the interval field with hours).
- Open Set Domain Config and set domain to
https://yourdomain.com. - Confirm the connection from Scheduled Run Trigger → Set Domain Config.
https://) so downstream API calls resolve correctly.Step 2: Connect WordPress Category Data
These nodes pull categories from WordPress and filter out excluded IDs before choosing the least-used category.
- In Fetch WP Categories, set URL to
={{ $json.domain }}/wp-json/wp/v2/categories?per_page=100. - Review Filter Category IDs and keep the exclude list in jsCode as provided (e.g.,
[1, 11, 12, 13, 15, 17, 18, 36, 37, 38, 39]). - Open Query Recent Categories and confirm the SQL query is set to
SELECT category_id, MAX(used_at) AS last_used_at FROM used_categories GROUP BY category_id ORDER BY last_used_at ASC;. - Credential Required: Connect your postgres credentials in Query Recent Categories.
- Ensure the flow continues to Select Least Used to pick the next category.
used_categories table is empty, Select Least Used defaults to the first category returned. Verify your WordPress categories are populated.Step 3: Set Up Title Generation with AI
This section generates a unique SEO title using recent titles and category context. Select Least Used outputs to both Retrieve Recent Titles and Combine Title Data in parallel.
- In Retrieve Recent Titles, keep the SQL query set to
SELECT name, description FROM used_categories WHERE category_id = {{ $json.id }} ORDER BY used_at DESC LIMIT 10;. - Credential Required: Connect your postgres credentials in Retrieve Recent Titles.
- Open OpenAI Mini Model and verify the model selection (e.g.,
gpt-4.1-mini-2025-04-14). - Credential Required: Connect your openAiApi credentials in OpenAI Mini Model. This model is connected as the language model for Generate SEO Title, so add credentials to OpenAI Mini Model, not the agent node.
- In Generate SEO Title, keep the text prompt exactly as configured to enforce uniqueness and formatting.
- In Format New Title, leave the jsCode to map output into
{ "title": $input.first().json.output }. - Confirm Format New Title and the direct path from Select Least Used both feed into Combine Title Data, then into Aggregate Post Metadata.
Step 4: Maintain Category Usage Records
This step merges metadata and updates your usage table before content generation begins. Aggregate Post Metadata combines title and category details for the database update.
- In Aggregate Post Metadata, keep the jsCode that merges all incoming JSON into one object.
- In Upsert Category Usage, verify the table is
used_categoriesand matchingColumns includescategory_id. - Confirm the column mappings in Upsert Category Usage use expressions like
={{ $json.name }},={{ $json.title }}, and={{ new Date().toISOString() }}. - Credential Required: Connect your postgres credentials in Upsert Category Usage.
Step 5: Generate Article Content and Media in Parallel
After usage is updated, Upsert Category Usage outputs to both Draft Article Content and Merge Content Streams in parallel. Then Draft Article Content outputs to Build Placeholder Image and Extract Article Blocks in parallel.
- Open OpenAI Main Model and confirm the model is set (e.g.,
gpt-4.1-2025-04-14). - Credential Required: Connect your openAiApi credentials in OpenAI Main Model. This model is connected as the language model for Draft Article Content, so add credentials to OpenAI Main Model, not the agent node.
- In Draft Article Content, keep the text prompt as provided to enforce WordPress block output and CTA link usage.
- In Extract Article Blocks, keep the jsCode mapping the AI output to
content. - In Build Placeholder Image, keep the generated image URL template and ensure it references
$('Upsert Category Usage').first().json.name. - In Fetch Placeholder Image, set URL to
={{ $json.image_url }}and keep the response format as a file. - In Upload Media to WP, set URL to
={{ $('Set Domain Config').first().json.domain }}/wp-json/wp/v2/mediaand keep inputDataFieldName asimagedownloaded. - Credential Required: Connect your wordpressApi credentials in Upload Media to WP.
imagedownloaded.Step 6: Assemble and Publish the WordPress Post
This stage merges title, category, content, and media into a single payload and publishes to WordPress.
- Confirm Merge Content Streams has numberInputs set to
3to accept category metadata, content blocks, and uploaded media. - In Assemble Post Payload, keep the jsCode that sets
status: 'publish', assignscategories, and addsfeatured_media. - In Publish WordPress Post, set URL to
={{ $('Set Domain Config').first().json.domain }}/wp-json/wp/v2/posts. - Verify the body parameters in Publish WordPress Post map title, content, status, featured_media, and categories[0] using expressions like
={{ $json["title"] }}and={{ $json.content }}. - Credential Required: Connect your wordpressApi credentials in Publish WordPress Post.
- Leave Finalize Workflow as a terminal node for clean completion.
Step 7: Test & Activate Your Workflow
Run the workflow once manually to validate category selection, AI outputs, media upload, and post publishing.
- Click Execute Workflow and monitor each node’s output, especially Generate SEO Title, Draft Article Content, and Publish WordPress Post.
- Successful execution should show a new post created in WordPress with a featured image and structured block content.
- If the post is missing a category or image, re-check Assemble Post Payload inputs from Merge Content Streams.
- Once verified, toggle the workflow to Active to run on the schedule configured in Scheduled Run Trigger.
Common Gotchas
- WordPress credentials can expire or need specific permissions. If things break, check your Application Password (or user role permissions) in WordPress first, then re-test the /media and /posts requests.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 30 minutes once your WordPress and database credentials are ready.
No. You’ll mostly copy credentials into n8n and run the provided SQL once.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs, which are usually a few cents per post depending on length and model.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and it’s a smart change if you want a human review step. In the “Publish WordPress Post” HTTP request, switch the post status from publish to draft (or pending) so WordPress holds it for review. You can also tweak the “Draft Article Content” prompt to enforce your outline, internal link rules, or a stricter tone guide. Common customizations include adding a “brand voice” paragraph, injecting product CTAs, and limiting topics to a specific cluster.
Usually it’s WordPress auth. Re-check the username/application password you’re using, confirm the user has permission to upload media and publish posts, and then re-test the two endpoints used here (/wp-json/wp/v2/media and /wp-json/wp/v2/posts). If it fails only sometimes, you may be hitting security plugins, rate limits, or blocking rules, so look at your WordPress server logs for the request response code and message.
On n8n Cloud Starter, you can typically run enough scheduled posts for a small site (think a post a day or a few per week). If you self-host, there’s no execution cap from n8n, so volume mainly depends on your server resources and how quickly WordPress and OpenAI respond.
Often, yes. This workflow does more than a simple trigger-action chain: it fetches categories, queries a database to prevent duplicates, merges multiple streams (title, article, image), then publishes through the WordPress API with a correct payload. Zapier and Make can handle parts of that, but multi-step logic and database checks get awkward (and can get expensive) as soon as you add branching and retries. n8n also gives you the self-hosted option, which some teams prefer for cost control and data handling. If you’re only doing “send a prompt, get text, paste it into WordPress as a draft,” the simpler tools may be fine. Talk to an automation expert if you want help choosing.
Set it up once, then let the workflow handle the repetitive publishing work week after week. You keep the editorial control, but you stop losing time to the same upload-and-format routine.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.