Google Sheets to WordPress, drafts ready to publish
Your content calendar is probably lying to you. Not on purpose. But when ideas live in a Google Sheet, drafts live in Google Docs, and “published” lives in someone’s memory, things slip fast.
This Sheets WordPress automation hits content managers hardest, but solo founders and agency leads feel it too. You end up rewriting the same prompts, copying the same blocks, and double-checking the same statuses, week after week.
This workflow turns a single spreadsheet row into a planned post, then a draft, then a publish-ready WordPress draft you can review before it goes live. You’ll see how it works, what you need, and where teams usually trip up.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Google Sheets to WordPress, drafts ready to publish
flowchart LR
subgraph sg0["Schedule Flow"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Settings", pos: "b", h: 48 }
n1@{ icon: "mdi:play-circle", form: "rounded", label: "ScheduleTrigger", pos: "b", h: 48 }
n2@{ icon: "mdi:play-circle", form: "rounded", label: "ManualTrigger", pos: "b", h: 48 }
n3@{ icon: "mdi:database", form: "rounded", label: "Schedule", 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/code.svg' width='40' height='40' /></div><br/>Config"]
n5@{ icon: "mdi:database", form: "rounded", label: "fetchConfig", pos: "b", h: 48 }
n6@{ icon: "mdi:brain", form: "rounded", label: "AgentLLM", pos: "b", h: 48 }
n7@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfScheduledNow", 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/code.svg' width='40' height='40' /></div><br/>PreparedData"]
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/>RecombinedDataRow"]
n10@{ icon: "mdi:database", form: "rounded", label: "SaveBackToSheet", pos: "b", h: 48 }
n11@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfActionPublish", pos: "b", h: 48 }
n12@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfTakeAction", pos: "b", h: 48 }
n13@{ icon: "mdi:swap-horizontal", form: "rounded", label: "IfPromptExists", pos: "b", h: 48 }
n14@{ icon: "mdi:robot", form: "rounded", label: "Basic LLM Chain", 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/httprequest.dark.svg' width='40' height='40' /></div><br/>CreatePost"]
n16@{ icon: "mdi:database", form: "rounded", label: "SetToPublish", pos: "b", h: 48 }
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/code.svg' width='40' height='40' /></div><br/>PrepareXmlPost"]
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/code.svg' width='40' height='40' /></div><br/>HandleXMLRPCResponse"]
n19@{ icon: "mdi:swap-horizontal", form: "rounded", label: "PostingSuccessful", pos: "b", h: 48 }
n20@{ icon: "mdi:database", form: "rounded", label: "LogStatus", pos: "b", h: 48 }
n21@{ icon: "mdi:database", form: "rounded", label: "LogPublished", pos: "b", h: 48 }
n6 -.-> n14
n3 --> n8
n0 --> n5
n0 --> n3
n20 --> n10
n15 --> n18
n5 --> n4
n12 --> n11
n21 --> n19
n8 --> n12
n2 --> n0
n13 --> n14
n7 --> n17
n17 --> n15
n14 --> n9
n11 --> n7
n11 --> n13
n1 --> n0
n19 --> n16
n9 --> n20
n18 --> n21
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 n1,n2 trigger
class n14 ai
class n6 aiModel
class n7,n11,n12,n13,n19 decision
class n3,n5,n10,n16,n20,n21 database
class n15 api
class n4,n8,n9,n17,n18 code
classDef customIcon fill:none,stroke:none
class n4,n8,n9,n15,n17,n18 customIcon
The Problem: Your content workflow is stuck in “almost done”
Planning content in a spreadsheet is fine… until you try to scale it. You draft in one place, paste into WordPress, realize the formatting is off, and then update the sheet again so your calendar doesn’t look wrong. Next week, someone asks what’s ready to publish and you’re piecing together clues from timestamps and half-updated statuses. The worst part is the mental load. You spend real focus on admin tasks, then try to switch gears and write something good. It’s exhausting.
The friction compounds. Here’s where it breaks down in real life.
- You lose time doing “tiny” copy-paste steps that add up to a few hours every week.
- Status fields drift out of sync, so you can’t trust what “draft” or “scheduled” actually means.
- Prompts and brand guidelines get inconsistently applied, which means more rewrites and weaker output.
- Publishing becomes a brittle manual checklist, so work slows down whenever the one “WordPress person” is busy.
The Solution: A staged Google Sheets → WordPress pipeline you control
This automation uses your Google Sheet as the single source of truth, then moves each topic through clear stages: plan, draft, final, and publish. It starts on a schedule (hourly) or whenever you manually trigger it in n8n. The workflow reads your “Schedule” sheet, checks each row’s Status and Action, and decides what needs to happen next. If a topic needs planning or drafting, it pulls prompt settings from a “Config” sheet, runs your chosen LLM, and writes the generated content back into the same row. Then it stops and hands control back to you, so you can edit the output and decide the next Action. When you set a row to publish, it creates a WordPress post via XML-RPC and logs the result so you can see what happened.
The flow is simple to live with. Your spreadsheet becomes the control panel. n8n does the repeatable work in the background, and WordPress only gets involved when a post is actually ready to become a draft or go live.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish 4 posts per week. Manually, you might spend about 20 minutes generating an outline, 45 minutes producing a first draft with AI prompts, then another 15 minutes copying into WordPress and fixing formatting, so roughly 5 hours weekly just to get drafts “in the system.” With this workflow, you update one row in Google Sheets (a minute or two), let the LLM run in the background, then review a WordPress draft when it’s ready. Realistically, you’re down to about 2 hours of review and edits per week, not 5 hours of repetitive handling.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Google Sheets to manage your schedule and prompts.
- WordPress to receive drafts and publish posts.
- OpenRouter API key (get it from your OpenRouter dashboard).
Skill level: Intermediate. You’ll connect accounts, copy a spreadsheet template, and paste a few IDs and URLs into n8n settings.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
A schedule or manual run kicks things off. The workflow runs hourly by default, but you can also trigger it on demand when you want to process new topics immediately.
Your spreadsheet becomes the “router.” n8n reads the Schedule sheet (topics, scheduled date, current Status, and next Action) and also loads the Config sheet, which stores your prompts, context, and even which LLM model to use.
AI generates the next stage only when needed. If a row’s Action says “plan,” “draft,” or “final,” the LLM chain runs and writes the output back into the right columns, along with status logs so you can see what changed.
Publishing happens only when you say so. When you change the Action to “publish,” the workflow composes an XML-RPC payload, sends it to WordPress, validates success, then marks the row as published and appends a publish log entry.
You can easily modify the Status/Action names to match your internal process based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Scheduled Trigger
Set up how the workflow starts, either on a schedule or manually for testing.
- Open Scheduled Automation Trigger and set the Rule to run every hour (interval field
hours). - Keep Manual Start Trigger connected to Config Variables for manual testing runs.
- Verify that both triggers connect into Config Variables so scheduled and manual runs share the same configuration path.
Step 2: Connect Google Sheets
Define spreadsheet parameters and connect all Google Sheets nodes that read schedules, configs, and logs.
- In Config Variables, set the spreadsheet and WordPress values: urlSpreadsheet to
https://docs.google.com/spreadsheets/d/[YOUR_ID]/edit?gid=0#gid=0, sheetSchedule to=Schedule, sheetConfig toConfig, and sheetLog toLog. - Confirm Config Variables outputs to both Retrieve Config Sheet and Read Schedule Sheet in parallel.
- Open Read Schedule Sheet and set Document to
{{ $('Config Variables').item.json.urlSpreadsheet }}and Sheet Name to{{ $('Config Variables').item.json.sheetSchedule }}. - Open Retrieve Config Sheet and set Document to
{{ $('Config Variables').item.json.urlSpreadsheet }}and Sheet Name to{{ $('Config Variables').item.json.sheetConfig }}. - Credential Required: Connect your
googleSheetsOAuth2Apicredentials to Read Schedule Sheet, Retrieve Config Sheet, Write Back to Sheet, Append Status Log, Append Publish Log, and Mark As Published.
Step 3: Set Up Processing and AI Generation
Transform schedule rows into AI prompts, generate content, and merge outputs back into the row data.
- Keep Build Config Map connected after Retrieve Config Sheet to assemble configuration key/value pairs for prompts and models.
- In Prepare Row Payload, keep Mode set to
runOnceForEachItemto generate per-row prompt and model settings. - Verify Verify Action Needed checks
{{ $json.takeAction }}so only rows with new actions proceed. - Confirm Check Publish Action compares
{{ $json.row.Action }}to{{ $('Config Variables').item.json.actionPublish }}, and note that Check Publish Action outputs to both Check Schedule Time and Confirm Prompt Present in parallel. - Open Confirm Prompt Present and ensure it validates
{{ $json.prompt }}is not empty before running AI. - In LLM Prompt Chain, set Text to
{{ $json.prompt }}and keep Prompt Type set todefine. LLM Chat Model is connected as the language model for LLM Prompt Chain — ensure credentials are added to LLM Chat Model. - Credential Required: Connect your
openAiApicredentials to LLM Chat Model and keep Model set to{{ $json.model }}. - In Merge Generated Output, keep Mode set to
runOnceForEachItemto normalize and merge AI outputs back into the schedule row.
prompt_* and prompt_*_model entries.Step 4: Configure Publishing Output to WordPress
Build the XML payload, send it to WordPress via XML-RPC, and validate the response.
- In Check Schedule Time, keep the comparison between
{{ DateTime.now().ts }}and{{ DateTime.fromFormat($json.row.Scheduled, "yyyy-MM-dd HH:mm:ss").ts }}so only due posts publish. - In Compose XML Post, keep the XML-RPC payload generation that sets the post title and content from
$json.row.Titleand$json.row.final. - In WordPress XML-RPC Call, set URL to
=https://{{ $('Config Variables').item.json.urlWordpress }}/xmlrpc.php, Method toPOST, Body to{{ $json.xmlRequestBody }}, and Raw Content Type totext/xml. - Keep Parse XML-RPC Reply connected to capture
postIdor XML-RPC faults. - In Validate Post Success, confirm it checks
{{ $('Parse XML-RPC Reply').item.json.postId }}before proceeding to updates. - In Mark As Published, confirm Status is set to
{{ $('Config Variables').item.json.actionPublish }}and the row is matched by{{ $('Prepare Row Payload').item.json.row.row_number }}.
wordpressUsername and wordpressApplicationPassword, or the XML-RPC call will return a fault.Step 5: Configure Logging and Sheet Updates
Log status changes and write generated content back to the schedule sheet.
- In Append Status Log, keep Operation set to
appendand the Message formula set to=Status {{ $json.Status }} for row {{ $('Prepare Row Payload').item.json.row.row_number }}. - In Write Back to Sheet, keep Operation set to
updateand Matching Columns set torow_numberso the row is updated correctly. - In Append Publish Log, keep Type set to
{{ $json.errorCode ? 'error' : 'info' }}and Message set to=Publishing row {{ $('Prepare Row Payload').item.json.row.row_number }}: {{ $json.postId }}{{ $json.errorCode }}{{ $json.error }}.
Step 6: Test and Activate Your Workflow
Run a manual test, confirm expected results, and enable the scheduled automation.
- Click Execute Workflow on Manual Start Trigger to test with a known schedule row.
- Check that Append Status Log and Append Publish Log add rows in the
Logsheet. - Confirm the schedule row is updated by Write Back to Sheet and, if published, by Mark As Published.
- Verify a post is created in WordPress when Parse XML-RPC Reply returns a
postId. - When satisfied, toggle the workflow to Active so Scheduled Automation Trigger runs hourly in production.
Common Gotchas
- Google Sheets credentials can expire or lack access to the specific spreadsheet copy. If rows stop updating, check the Google connection in n8n and confirm the spreadsheet is shared with the right account.
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- WordPress XML-RPC publishing can fail if your app password is wrong or your user role can’t publish. Check your WordPress application password settings and confirm XML-RPC is allowed by your host or security plugin.
Frequently Asked Questions
About an hour if your spreadsheet and WordPress access are ready.
No. You will connect accounts and paste a few values into the Settings node. The workflow already includes the logic for reading rows, writing back, and publishing.
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 OpenRouter API costs, which depend on the model you select.
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, but you’ll want a clean separation. The simplest approach is duplicating the workflow and pointing each copy to a different WordPress URL and app password in the Settings node. Some teams also duplicate the spreadsheet per site, which keeps prompts and schedules from getting tangled. If you prefer one spreadsheet, add a “Site” column and route rows through an extra If node before the WordPress XML-RPC call.
Usually it’s an app password issue or blocked XML-RPC. Regenerate your WordPress application password, update it in the workflow, and confirm your WordPress user has permission to create posts. If you use a security plugin or managed host, check their settings because some disable XML-RPC by default. Also confirm the WordPress URL in the Settings node is the exact base URL your XML-RPC endpoint expects.
On n8n Cloud Starter, you can run a healthy amount of hourly checks for a small calendar, and higher plans handle more volume. If you self-host, there’s no execution cap, it mostly depends on your server and your LLM speed. Practically, most teams run this hourly and process anywhere from a few rows to a few dozen rows per run. If you start generating hundreds of drafts, you’ll hit LLM rate limits before you hit n8n limits.
Often, yes. This workflow relies on branching logic (Status + Action checks), writing structured results back into the sheet, and handling WordPress publishing responses with validation and logs, which is frankly where simpler tools get awkward or expensive. n8n also gives you the self-hosting option, so you’re not paying more every time you run hourly checks. Zapier or Make can still be a better fit if you only want a basic “new row → create draft” flow and you don’t care about multi-stage approvals. If you’re unsure, Talk to an automation expert and describe your calendar process.
Once this is in place, your spreadsheet stops being a messy checklist and starts acting like a real production pipeline. The workflow takes the repetitive work. You make the calls.
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.