WordPress to Google Sheets, always accurate content reports
Your content report is only as good as your last export. And honestly, exports get forgotten, overwritten, or quietly go stale while everyone keeps making decisions from them.
This WordPress Sheets sync problem hits marketing managers first, but content strategists and agency owners feel it too. You want one spreadsheet that always reflects what’s live on your site, without chasing teammates for “the latest version.”
This workflow connects WordPress to Google Sheets and keeps posts, categories, tags, and media updated automatically. You’ll see how it works, what you need, and what results to expect.
How This Automation Works
Here’s the complete workflow you’ll be setting up:
n8n Workflow Template: WordPress to Google Sheets, always accurate content reports
flowchart LR
subgraph sg0["Scheduled Run Flow"]
direction LR
n0@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Page Limit Check", pos: "b", h: 48 }
n1@{ icon: "mdi:swap-vertical", form: "rounded", label: "Init Page Variables", 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/code.svg' width='40' height='40' /></div><br/>Advance Page Counter"]
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/httprequest.dark.svg' width='40' height='40' /></div><br/>Fetch WP Articles"]
n4@{ icon: "mdi:swap-vertical", form: "rounded", label: "Expand Post Items", pos: "b", h: 48 }
n5@{ icon: "mdi:play-circle", form: "rounded", label: "Scheduled Run Trigger", pos: "b", h: 48 }
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/httprequest.dark.svg' width='40' height='40' /></div><br/>Retrieve WP Categories"]
n7@{ icon: "mdi:database", form: "rounded", label: "Sync Category Sheet", pos: "b", h: 48 }
n8@{ icon: "mdi:database", form: "rounded", label: "Sync Posts Sheet", 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/httprequest.dark.svg' width='40' height='40' /></div><br/>Fetch Media Library"]
n10@{ icon: "mdi:swap-vertical", form: "rounded", label: "Expand Media Items", pos: "b", h: 48 }
n11@{ icon: "mdi:database", form: "rounded", label: "Sync Media Sheet", pos: "b", h: 48 }
n12@{ icon: "mdi:swap-vertical", form: "rounded", label: "Init Media Variables", pos: "b", h: 48 }
n13["<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/>Advance Media Counter"]
n14@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Media Page Check", 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/>Fetch WP Tags"]
n16@{ icon: "mdi:swap-vertical", form: "rounded", label: "Expand Tag Items", pos: "b", h: 48 }
n17@{ icon: "mdi:database", form: "rounded", label: "Sync Tag Sheet", pos: "b", h: 48 }
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/webhook.dark.svg' width='40' height='40' /></div><br/>Incoming Webhook Trigger"]
n0 --> n6
n0 --> n12
n0 --> n15
n0 --> n2
n14 --> n13
n18 --> n1
n9 --> n10
n3 --> n4
n2 --> n3
n4 --> n8
n1 --> n2
n13 --> n9
n10 --> n11
n16 --> n17
n12 --> n13
n15 --> n16
n11 --> n14
n8 --> n0
n6 --> n7
n5 --> n1
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 n5 trigger
class n0,n14 decision
class n7,n8,n11,n17 database
class n3,n6,n9,n15,n18 api
class n2,n13 code
classDef customIcon fill:none,stroke:none
class n2,n3,n6,n9,n13,n15,n18 customIcon
Why This Matters: Content Reporting That People Actually Trust
Content reporting breaks in boring ways. Someone exports posts from WordPress, pastes them into a sheet, and calls it a dashboard. A week later, categories have changed, tags were cleaned up, and five new posts went live. Now your “content inventory” is quietly wrong. That’s when you waste hours arguing about numbers, re-checking URLs, and rebuilding reports you already built once. The real cost isn’t the export itself. It’s the constant second-guessing and the missed opportunities when you can’t see what’s actually happening on the site.
It adds up fast. Here’s where it breaks down in day-to-day work.
- Teams lose about 1–2 hours a week re-exporting and cleaning lists of posts and metadata.
- Category and tag changes don’t make it into reporting, so SEO audits start from bad assumptions.
- Media tracking is usually missing entirely, which makes it hard to spot old assets or broken links.
- Different people keep their own spreadsheets, and nobody knows which one is “the source of truth.”
What You’ll Build: A Live WordPress Content Database in Google Sheets
You’ll set up an n8n workflow that pulls content directly from the WordPress REST API and writes it into a structured Google Sheet. It can run on a schedule (like nightly) or start instantly via a webhook when you need a fresh snapshot for a meeting. The workflow fetches posts in pages, expands the results into individual rows, and updates your “Posts” tab. Then it does the same for categories and tags, so your taxonomy reporting stays accurate. Finally, it syncs your media library into a “Media” tab, which is a surprisingly useful view when you’re cleaning up old assets or building a content refresh plan.
The workflow starts with a scheduled trigger or an incoming webhook. From there, it loops through WordPress endpoints with pagination logic, updating Google Sheets as it goes. When it finishes, you have a sheet that matches what’s in WordPress right now, not what was true last month.
What You’re Building
| What Gets Automated | What You’ll Achieve |
|---|---|
|
|
Expected Results
Say your site publishes 20 posts a month and you run a weekly content report. Manually, you might export posts, categories, and tags, then clean and paste it all, which is easily about 45 minutes each time (and longer when someone changed categories). That’s about 3 hours a month, plus the occasional “wait, why is this missing?” debugging. With this workflow, your weekly refresh is basically zero effort: let the schedule run overnight, or hit the webhook and wait a few minutes for the sync to finish.
Before You Start
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- WordPress site with REST API accessible
- Google Sheets to store Posts, Categories, Tags, Media tabs
- WordPress Application Password (create it in WP Users → Profile)
Skill level: Beginner. You’ll connect accounts, paste your site URL, and confirm your sheet tabs match the workflow.
Want someone to build this for you? Talk to an automation expert (free 15-minute consultation).
Step by Step
Choose how it starts (schedule or on-demand). The workflow can run from a Scheduled Trigger (for example, every night) or from an Incoming Webhook Trigger when you want a refresh right now.
Initialize paging so you don’t miss anything. It sets page variables, then uses a counter and “page limit” checks to loop through WordPress results until everything is retrieved.
Pull posts, then write clean rows into Sheets. n8n calls the WordPress posts endpoint with an HTTP Request, splits the list into individual post items, then syncs those into your Google Sheets “Posts” tab.
Repeat the same pattern for categories, tags, and media. Categories and tags are fetched and synced to their own tabs, while media runs through its own pagination loop so larger libraries still complete reliably.
You can easily modify the per-page limit and sheet columns to match your reporting style. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Trigger Type
This workflow can start on a schedule or via a webhook to initialize paging variables for WordPress data syncing.
- Open Scheduled Run Trigger and set the schedule rule to run every
3days using the existing interval configuration. - Open Incoming Webhook Trigger and confirm the Path is
4c34beca-b5d7-48bd-bd11-f24f760c039dfor manual or external triggering. - Connect both triggers to Init Page Variables so either trigger initializes the paging state.
Step 2: Connect WordPress (HTTP Basic Auth)
HTTP requests pull posts, categories, tags, and media from WordPress. Each request uses HTTP Basic Authentication.
- In Fetch WP Articles, set URL to
{{$json.base_url}}and enable Send Query. - Set query parameters in Fetch WP Articles to:
per_page={{$json.per_page}},page={{ $json.current_page }},_embed=wp:featuredmedia,wp:term,_fields={{$json.fields}},orderby=date,order=desc. - Credential Required: Connect your httpBasicAuth credentials in Fetch WP Articles.
- In Retrieve WP Categories set URL to
https://ozwebexpert.com/wp-json/wp/v2/categoriesand keep Execute Once enabled. - Credential Required: Connect your httpBasicAuth credentials in Retrieve WP Categories, Fetch Media Library, and Fetch WP Tags.
- In Fetch WP Tags confirm the URL is
https://ozwebexpert.com/wp-json/wp/v2/tagswith query parametersper_page=100and_fields=id,name,slug.
Step 3: Set Up Paging and Post Sync Logic
This section initializes paging variables, fetches posts in pages, and keeps iterating until all pages are processed.
- In Init Page Variables, set JSON Output to
{ "base_url": "https://ozwebexpert.com/wp-json/wp/v2/posts", "fields": "id,slug,link,date,title,excerpt,categories,tags,featured_media,_embedded", "per_page": 10, "current_page": 0 }. - Keep the code in Advance Page Counter as-is to increment
current_pagefor each loop. - Connect Advance Page Counter to Fetch WP Articles so each increment fetches a new page of posts.
- In Expand Post Items, set Field to Split Out to
bodyand Include toallOtherFields. - In Page Limit Check, keep the condition comparing
{{ $('Advance Page Counter').item.json.current_page }}to{{ $('Fetch WP Articles').item.json.headers['x-wp-totalpages'] }}to stop looping at the last page.
Page Limit Check outputs to both Retrieve WP Categories, Init Media Variables, and Fetch WP Tags in parallel.
Step 4: Configure Media and Tag Sync Branches
Two additional branches pull media and tag data and iterate through their pages independently.
- In Init Media Variables, set JSON Output to
{ "base_url": "https://ozwebexpert.com/wp-json/wp/v2/media", "per_page": 10, "current_page": 0 }. - Keep the code in Advance Media Counter to increment
current_pagefor media pagination. - In Fetch Media Library, set URL to
{{$json.base_url}}with query paramsper_page={{ $json.per_page }},page={{ $json.current_page }}, andparent_exclude=0. - In Expand Media Items, set Field to Split Out to
body. - Keep the Media Page Check condition comparing
{{ $('Advance Media Counter').item.json.current_page }}to{{ $('Fetch Media Library').item.json.headers['x-wp-totalpages'] }}for loop control. - In Expand Tag Items, set Field to Split Out to
bodyto unpack tag results from Fetch WP Tags.
Step 5: Configure Google Sheets Output Nodes
Each dataset is appended or updated in its own sheet using matching IDs.
- In Sync Posts Sheet, keep Operation set to
appendOrUpdate, Document ID set tohttps://docs.google.com/[YOUR_ID], and Sheet Name set toPosts. - Map columns in Sync Posts Sheet to the post fields, such as
id={{ $json.body.id }},title={{ $json.body.title.rendered }}, andcategories={{ $json.body.categories[0] }}. - In Sync Category Sheet, keep Operation set to
appendOrUpdate, Sheet Name set toCategories, and match oncategory_id. - In Sync Media Sheet, keep Operation set to
appendOrUpdate, Sheet Name set toMedia, and map values likeurl={{ $json.source_url }}andmedia_id={{ $json.id }}. - In Sync Tag Sheet, keep Operation set to
appendOrUpdate, Sheet Name set toTags, and match ontag_id. - Credential Required: Connect your googleSheetsOAuth2Api credentials in Sync Posts Sheet, Sync Category Sheet, Sync Media Sheet, and Sync Tag Sheet.
⚠️ Common Pitfall: Ensure each Google Sheet has the exact column headers defined in the node mappings (e.g., id, category_id, tag_id, media_id) or append/update will not match correctly.
Step 6: Test and Activate Your Workflow
Validate that each branch runs and writes data to your Google Sheets before enabling the schedule.
- Click Execute Workflow to test with the Scheduled Run Trigger or send a request to the Incoming Webhook Trigger URL.
- Confirm that Sync Posts Sheet, Sync Category Sheet, Sync Media Sheet, and Sync Tag Sheet each append or update rows in your target spreadsheet.
- Verify that Page Limit Check and Media Page Check stop looping after the final page based on the response headers.
- Once verified, toggle the workflow to Active to enable scheduled runs in production.
Troubleshooting Tips
- WordPress HTTP Basic Auth credentials can expire or lack access. If requests start failing, check your WordPress Application Password and user role permissions 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.
- Google Sheets OAuth2 can silently lose access after password or admin changes. Reconnect the Google account in n8n credentials, then reselect the spreadsheet ID in each Sheets node.
Quick Answers
About 30 minutes if your WordPress and Google accounts are ready.
No. You will connect credentials, update a few URLs, and paste your spreadsheet ID.
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 any hosting cost if you self-host, plus normal Google/WordPress account 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.
Yes, and you should. Most people start by changing the WordPress endpoint URL in the HTTP Request nodes (for example, to include custom post types) and adjusting the per_page setting to speed up large syncs. You can also swap the Scheduled Trigger for webhook-only runs, depending on how you report. Finally, update the Google Sheets nodes to map extra fields you care about, like author, slug, or last modified date.
Usually it’s an incorrect Application Password or the wrong REST API base URL. Regenerate the Application Password in WordPress, update the HTTP Basic Auth credential in n8n, and double-check you’re calling /wp-json/wp/v2/ on the right domain. If it works in a browser but not in n8n, permissions are the next suspect. Rate limits can show up too if you run the sync too often on a large site.
For most small to mid-sized sites, it can comfortably sync thousands of posts and media items per run, because it paginates results and keeps looping until it’s done.
Often, yes. This workflow needs pagination, looping, and multi-tab writes (posts, tags, categories, media), and n8n handles that without turning into a pile of separate zaps/scenarios. Self-hosting is also a big deal if you expect frequent syncs. That said, if you only need a simple “new post → add one row” setup, Zapier or Make can be faster to click together. Talk to an automation expert if you want help picking the cleanest option for your reporting stack.
Once this is running, your content sheet stays current without you babysitting it. The workflow handles the repetitive syncing so you can focus on decisions, not exports.
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.