PostgreSQL + WordPress: SEO drafts ready to publish
Your content calendar looks full. Your draft folder doesn’t. The real blocker is the messy middle: keyword picking, research, outlines, internal links, images, metadata, and then the final WordPress upload that somehow still takes an hour.
This PostgreSQL WordPress drafts automation hits content marketers first, honestly. But SEO agency owners and small business operators feel it too, because “write more” turns into “do five different jobs” every week.
This workflow turns scored keywords in PostgreSQL into WordPress-ready drafts with research, images, internal links, and SEO metadata already filled in. You’ll see what it fixes, how the flow works, and what you need to run it reliably.
How This Automation Works
See how this solves the problem:
n8n Workflow Template: PostgreSQL + WordPress: SEO drafts ready to publish
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields1", pos: "b", h: 48 }
n1["<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/markdown.dark.svg' width='40' height='40' /></div><br/>Markdown"]
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/wordpress.svg' width='40' height='40' /></div><br/>Create a post"]
n3@{ icon: "mdi:robot", form: "rounded", label: "Preliminary Plan1", pos: "b", h: 48 }
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/perplexity.dark.svg' width='40' height='40' /></div><br/>Message a model1"]
n5@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields8", pos: "b", h: 48 }
n6@{ icon: "mdi:swap-vertical", form: "rounded", label: "Split Out4", pos: "b", h: 48 }
n7@{ icon: "mdi:cog", form: "rounded", label: "Aggregate7", pos: "b", h: 48 }
n8["<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/>Merge1"]
n9@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields13", pos: "b", h: 48 }
n10@{ icon: "mdi:robot", form: "rounded", label: "Structured Output Parser3", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields15", pos: "b", h: 48 }
n12@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model8", pos: "b", h: 48 }
n13@{ icon: "mdi:cog", form: "rounded", label: "Aggregate8", pos: "b", h: 48 }
n14@{ icon: "mdi:robot", form: "rounded", label: "Intro1", pos: "b", h: 48 }
n15@{ icon: "mdi:robot", form: "rounded", label: "conclusion1", pos: "b", h: 48 }
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/merge.svg' width='40' height='40' /></div><br/>Merge3"]
n17@{ icon: "mdi:cog", form: "rounded", label: "Aggregate9", pos: "b", h: 48 }
n18@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields16", pos: "b", h: 48 }
n19@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields19", pos: "b", h: 48 }
n20@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields21", pos: "b", h: 48 }
n21@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields22", pos: "b", h: 48 }
n22@{ icon: "mdi:robot", form: "rounded", label: "header post1", pos: "b", h: 48 }
n23["<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/>Code8"]
n24@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields2", pos: "b", h: 48 }
n25@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields24", pos: "b", h: 48 }
n26@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields25", pos: "b", h: 48 }
n27@{ icon: "mdi:cog", form: "rounded", label: "Aggregate1", pos: "b", h: 48 }
n28["<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/>select blog table1"]
n29@{ icon: "mdi:cog", form: "rounded", label: "limit to ", pos: "b", h: 48 }
n30["<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/>blog table1"]
n31@{ icon: "mdi:robot", form: "rounded", label: "create plan for dev1", pos: "b", h: 48 }
n32["<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/>Log blog link for future int.."]
n33@{ icon: "mdi:robot", form: "rounded", label: "FAQ section1", pos: "b", h: 48 }
n34@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields26", pos: "b", h: 48 }
n35@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger3", pos: "b", h: 48 }
n36@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model10", pos: "b", h: 48 }
n37@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model11", pos: "b", h: 48 }
n38@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model12", pos: "b", h: 48 }
n39@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model13", pos: "b", h: 48 }
n40@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model14", pos: "b", h: 48 }
n41@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model15", pos: "b", h: 48 }
n42@{ icon: "mdi:robot", form: "rounded", label: "Basic LLM Chain", pos: "b", h: 48 }
n43@{ icon: "mdi:brain", form: "rounded", label: "OpenRouter Chat Model", pos: "b", h: 48 }
n44["<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/>Create Image1"]
n45["<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/>Get Result1"]
n46@{ icon: "mdi:cog", form: "rounded", label: "10 Seconds1", pos: "b", h: 48 }
n47@{ icon: "mdi:cog", form: "rounded", label: "5 Seconds1", pos: "b", h: 48 }
n48@{ icon: "mdi:robot", form: "rounded", label: "Basic LLM Chain1", pos: "b", h: 48 }
n49@{ icon: "mdi:brain", form: "rounded", label: "OpenRouter Chat Model1", pos: "b", h: 48 }
n50@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields", pos: "b", h: 48 }
n51["<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/>Create Image3"]
n52["<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/>Get Result3"]
n53@{ icon: "mdi:cog", form: "rounded", label: "10 Seconds3", pos: "b", h: 48 }
n54@{ icon: "mdi:cog", form: "rounded", label: "5 Seconds3", pos: "b", h: 48 }
n55@{ icon: "mdi:robot", form: "rounded", label: "dev 2", pos: "b", h: 48 }
n56@{ icon: "mdi:robot", form: "rounded", label: "dev 1", pos: "b", h: 48 }
n23 --> n1
n56 --> n19
n55 --> n20
n14 --> n18
n8 --> n13
n16 --> n17
n1 --> n0
n29 --> n3
n47 --> n45
n54 --> n52
n27 --> n8
n7 --> n8
n13 --> n14
n13 --> n56
n13 --> n55
n13 --> n15
n13 --> n22
n13 --> n33
n17 --> n24
n6 --> n5
n46 --> n45
n53 --> n52
n50 --> n8
n45 --> n9
n45 --> n47
n52 --> n50
n52 --> n54
n30 --> n26
n15 --> n21
n0 --> n2
n24 --> n23
n5 --> n7
n33 --> n34
n22 --> n16
n44 --> n46
n51 --> n53
n2 --> n25
n9 --> n8
n11 --> n31
n18 --> n16
n19 --> n16
n20 --> n16
n21 --> n16
n25 --> n32
n26 --> n27
n34 --> n16
n42 --> n44
n48 --> n51
n4 --> n6
n4 --> n11
n4 --> n30
n3 --> n4
n3 --> n48
n35 --> n28
n12 -.-> n31
n28 --> n29
n36 -.-> n22
n37 -.-> n14
n38 -.-> n56
n39 -.-> n15
n40 -.-> n55
n41 -.-> n33
n31 --> n42
n31 --> n8
n43 -.-> n42
n49 -.-> n48
n10 -.-> n31
end
subgraph sg1["Schedule Flow"]
direction LR
n57@{ icon: "mdi:cog", form: "rounded", label: "Aggregate2", pos: "b", h: 48 }
n58@{ icon: "mdi:swap-vertical", form: "rounded", label: "Edit Fields3", pos: "b", h: 48 }
n59@{ icon: "mdi:robot", form: "rounded", label: "Structured Output Parser", pos: "b", h: 48 }
n60["<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/>Insert rows in a table"]
n61["<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/>Select rows from a table1"]
n62["<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/>Select rows from a table2"]
n63@{ icon: "mdi:swap-vertical", form: "rounded", label: "Split Out2", pos: "b", h: 48 }
n64["<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/>Code4"]
n65["<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/>Code5"]
n69["<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/>Fetch Keywords1"]
n70@{ icon: "mdi:database", form: "rounded", label: "Select rows from a table in ..", pos: "b", h: 48 }
n71@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n72@{ icon: "mdi:robot", form: "rounded", label: "Choose keywords, Intent, etc", pos: "b", h: 48 }
n73["<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/>Primary keywords"]
n74["<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/>Used secondary"]
n77@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Model1", pos: "b", h: 48 }
n78@{ icon: "mdi:cog", form: "rounded", label: "Limit2", pos: "b", h: 48 }
n64 --> n74
n65 --> n73
n78 --> n58
n57 --> n72
n63 --> n62
n58 --> n57
n69 --> n78
n71 --> n69
n77 -.-> n72
n59 -.-> n72
n61 --> n65
n62 --> n64
n72 --> n60
n72 --> n61
n72 --> n63
n70 -.-> n72
end
subgraph sg2["Flow 3"]
direction LR
n66["<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/>Select rows from a table"]
n67["<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/>Score Keywords"]
n68@{ icon: "mdi:swap-vertical", form: "rounded", label: "Loop Over Items", pos: "b", h: 48 }
n75["<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/>Update score"]
n76@{ icon: "mdi:cog", form: "rounded", label: "All scored", pos: "b", h: 48 }
n75 --> n68
n67 --> n75
n68 --> n76
n68 --> n67
n66 --> n68
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 n35,n71 trigger
class n3,n10,n14,n15,n22,n31,n33,n42,n48,n55,n56,n59,n72 ai
class n12,n36,n37,n38,n39,n40,n41,n43,n49,n77 aiModel
class n28,n30,n32,n60,n61,n62,n69,n70,n73,n74,n66,n75 database
class n44,n45,n51,n52 api
class n23,n64,n65,n67 code
classDef customIcon fill:none,stroke:none
class n1,n2,n4,n8,n16,n23,n28,n30,n32,n44,n45,n51,n52,n60,n61,n62,n64,n65,n69,n73,n74,n66,n67,n75 customIcon
The Challenge: Publishing SEO content consistently without burning out
The frustrating part of “SEO writing” usually isn’t the writing. It’s everything around it. You start with a keyword list, then second-guess difficulty, chase sources, build an outline, draft six sections, find (or create) images, write alt text, craft the title and meta description, add internal links, then paste it all into WordPress and fix formatting. Do that a few times a week and it becomes the thing you dread, which means the site goes quiet, rankings stall, and suddenly you’re “behind” again.
The friction compounds. Here’s where it breaks down in real life.
- Keyword selection turns into endless debating, and you still sometimes pick terms you can’t realistically win.
- Research and citations take about an hour per post if you want it to be credible.
- Internal linking is easy to skip, so older posts stop getting traffic boosts from new content.
- WordPress drafting becomes a formatting chore, and the “I’ll publish later” pile grows.
The Fix: PostgreSQL-scored keywords turned into WordPress drafts
This workflow runs as a PostgreSQL-backed content system: it keeps your keyword pipeline organized, picks the next best topic, researches it, generates the full article in multiple parts, creates images, and then posts a complete draft into WordPress with metadata already filled. It starts by querying your database tables for available keywords and clusters, then applies scoring logic (volume, competition, CPC, relevance, and usage tracking) so you don’t keep reusing the same terms or cannibalizing pages. Next, the AI research phase pulls supporting information and sources, which are then used to generate a structured article: intro, development sections, conclusion, FAQ, plus the SEO header fields. Finally, the workflow generates two contextual images through fal.ai (Nano Banana), writes the alt text, and publishes everything as a WordPress draft ready for review.
The workflow starts on a schedule (every few days is typical), pulls the best keyword candidate from PostgreSQL, and uses AI to plan and write sections in parallel. Then it adds citations, internal links, images, and WordPress metadata so the end result is a clean draft instead of a half-finished document.
What Changes: Before vs. After
| What This Eliminates | Impact You’ll See |
|---|---|
|
|
Real-World Impact
Say you publish 10 posts per week. Manually, a realistic breakdown is about 1 hour for keyword choice and research, about 2 hours to draft and tighten the sections, and another 30 minutes for WordPress formatting, images, alt text, and metadata. Call it roughly 3 to 4 hours per post. With this workflow, you’re mostly reviewing: maybe 20 minutes to skim, adjust tone, and hit “publish” from a draft. That’s about 30 hours back in a busy week, while still keeping quality guardrails like citations and topic tracking.
Requirements
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- PostgreSQL for keyword scoring and usage tracking.
- WordPress REST API to create drafts and set metadata.
- API keys (get them from OpenAI, Anthropic, Perplexity, OpenRouter, and fal.ai dashboards).
Skill level: Intermediate. You’ll be connecting APIs, importing the workflow JSON, and pasting a provided PostgreSQL schema.
Need help implementing this? Talk to an automation expert (free 15-minute consultation).
The Workflow Flow
Scheduled run pulls the next opportunity. The workflow starts on a timer (every couple of days is common) and queries PostgreSQL for the best available keyword or cluster based on your scoring and “already used” flags.
Research is collected and shaped. An AI research step gathers supporting points and sources, then the workflow merges that into a content plan so the draft doesn’t read like generic filler.
Content is generated in parallel. Multiple AI models handle different parts (planning, section drafting, and FAQ), which is how teams get to 10–15 posts a week without waiting for one long, sequential prompt to finish.
Publishing assets are produced and attached. The workflow generates two 16:9 images with fal.ai, writes alt text, sets the SEO fields (title, slug, meta description, tags), and creates a WordPress draft via the REST API.
You can easily modify the scoring weights to match your niche and adjust the content length per section based on your site. See the full implementation guide below for customization options.
Watch Out For
- WordPress REST API credentials can expire or lack author permissions. If drafts stop appearing, check your WordPress user role and the application password/token settings first.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- fal.ai and AI model prompts are only “good defaults.” Add your brand voice and style rules early, or you will spend your saved time rewriting intros and conclusions.
Common Questions
Plan on about 2 hours if your API keys and WordPress access are ready.
Yes, but you’ll want one person comfortable with copy-pasting SQL and API keys. Day-to-day use is hands-off once it’s running.
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 AI API usage (often a few dollars per post, depending on model choice) and fal.ai image generation costs.
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.
You’ll mainly adjust the PostgreSQL scoring query, the AI prompt text, and the WordPress fields mapping. Common customizations include changing the relevance terms for your niche, shortening or expanding the section lengths, swapping the image model or aspect ratio, and changing how internal links are selected (for example, only linking to “money pages” or pillar posts).
Usually it’s an expired or revoked application password, or the WordPress user doesn’t have permission to create posts. Also check that your site blocks REST API access behind a security plugin, because that can make requests fail even when credentials look correct.
It comfortably supports 10–15 posts per week, and you can push higher if your API limits allow it.
For this kind of multi-phase content pipeline, n8n is usually the better fit. You need branching logic (scoring, dedupe checks, retries), database queries, and long-running steps like research and image generation, which means you don’t want a fragile chain of small zaps. n8n also gives you a real self-hosted option, so higher volume doesn’t automatically mean higher bills. Zapier or Make can still work for simpler “sheet to WordPress” publishing, but once you add PostgreSQL tracking plus multi-model AI, they get fiddly fast. If you want an opinion on your setup, Talk to an automation expert.
You set the pipeline once, then you get drafts that are actually publishable. The workflow handles the repetitive parts so you can spend your time on strategy and final edits.
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.