WordPress meets GitHub for versioned content backups
WordPress content changes fast. Then someone asks, “What did we change last week?” and you’re stuck digging through revisions, screenshots, or half-remembered edits.
Content managers feel it when approvals get messy. Marketing leads run into it when multiple people touch the same post. And agency teams get the blame when a client swears a paragraph “used to be there.” This WordPress GitHub backups workflow gives you a clean, versioned history you can actually trust.
You’ll see how the automation pulls posts from WordPress, turns them into files, checks what changed, and commits updates into GitHub so you can review diffs or roll back quickly.
The Problem: WordPress Content History Gets Fuzzy
WordPress revisions help, until they don’t. They’re hard to review at a glance, not great for team workflows, and they rarely match how you already manage “real” changes in the rest of the business. Meanwhile, content updates aren’t small. It’s a headline tweak, then a CTA swap, then a compliance edit, then suddenly the whole post reads differently. When something breaks (traffic drops, legal flags a claim, a product detail changes), you need to answer one simple question fast: what changed, and when?
The friction compounds. Here’s where it breaks down in day-to-day work.
- You end up copy-pasting posts into docs or Slack threads just to get basic review and approval.
- Small edits slip through without visibility, which means the team argues from memory instead of evidence.
- Rolling back is stressful because “revert” often means redoing other good edits that happened afterward.
- When several posts are updated in a week, tracking changes across them becomes a recurring time sink.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: WordPress meets GitHub for versioned content backups
flowchart LR
subgraph sg0["Execute Workflow Flow"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Return", 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/httprequest.dark.svg' width='40' height='40' /></div><br/>Get File"]
n2@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If file too large", pos: "b", h: 48 }
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/merge.svg' width='40' height='40' /></div><br/>Merge Items"]
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/>isDiffOrNew"]
n5@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Check Status", pos: "b", h: 48 }
n6@{ icon: "mdi:cog", form: "rounded", label: "Same file - Do nothing", pos: "b", h: 48 }
n7@{ icon: "mdi:cog", form: "rounded", label: "File is different", pos: "b", h: 48 }
n8@{ icon: "mdi:cog", form: "rounded", label: "File is new", 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/github.dark.svg' width='40' height='40' /></div><br/>Create new file"]
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/github.dark.svg' width='40' height='40' /></div><br/>Edit existing file"]
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/github.dark.svg' width='40' height='40' /></div><br/>Get file data"]
n12@{ icon: "mdi:swap-vertical", form: "rounded", label: "Globals", pos: "b", h: 48 }
n13@{ icon: "mdi:play-circle", form: "rounded", label: "Execute Workflow Trigger", pos: "b", h: 48 }
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "/", pos: "b", h: 48 }
n15@{ icon: "mdi:swap-horizontal", form: "rounded", label: "tag?", pos: "b", h: 48 }
n14 --> n12
n15 --> n14
n15 --> n12
n12 --> n11
n1 --> n3
n8 --> n9
n3 --> n4
n4 --> n5
n5 --> n6
n5 --> n7
n5 --> n8
n11 --> n2
n9 --> n0
n7 --> n10
n2 --> n1
n2 --> n3
n10 --> n0
n6 --> n0
n13 --> n3
n13 --> n15
end
subgraph sg1["Manual Flow"]
direction LR
n16@{ icon: "mdi:play-circle", form: "rounded", label: "Manual Trigger", 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/wordpress.svg' width='40' height='40' /></div><br/>Get All WP Posts"]
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/>Format JSON"]
n19@{ icon: "mdi:cog", form: "rounded", label: "Execute Workflow", pos: "b", h: 48 }
n20@{ icon: "mdi:play-circle", form: "rounded", label: "Schedule Trigger", pos: "b", h: 48 }
n18 --> n19
n16 --> n17
n17 --> n18
n20 --> n17
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 n13,n16,n20 trigger
class n2,n5,n15 decision
class n1 api
class n4,n18 code
classDef customIcon fill:none,stroke:none
class n1,n3,n4,n9,n10,n11,n17,n18 customIcon
The Solution: Sync WordPress Posts into GitHub as Versioned Files
This n8n workflow pulls your WordPress articles on a schedule (or whenever you run it manually), converts each post into a consistent JSON payload, and then stores that content inside a GitHub repository as files. Before it writes anything, it checks whether a matching file already exists, fetches the current version, and compares it to what WordPress looks like right now. If there’s no change, it does nothing. If something changed, it commits an updated file. If it’s brand new, it creates the file for the first time. The result is a Git-style content timeline you can diff, review, and roll back without guesswork.
The workflow starts with WordPress as the source of truth. Then n8n evaluates file metadata in GitHub, pulls the existing file when needed, and detects changes before deciding to create, update, or skip. Finally, it writes the result back to GitHub and returns a clean status output for your logs.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you publish or update 20 posts a month, and you “backup” content by copying it into a doc and saving a dated export. Even at roughly 10 minutes per post, that’s about 3 hours of boring work, plus the mental overhead of naming files and keeping folders organized. With this workflow, the “after” is basically zero: you let the scheduled trigger run, n8n processes posts in batches, and GitHub stores each revision automatically. You only open GitHub when you actually need to review a diff or restore an older version.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- WordPress as the source for posts and content.
- GitHub to store versioned files and diffs.
- GitHub personal access token (create it in GitHub Developer Settings).
Skill level: Intermediate. You’ll connect WordPress and GitHub, then verify repo paths, tags, and credentials.
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) starts the backup. The workflow can run from a Scheduled Start for ongoing protection, or from Manual Start when you want to test it or run a one-off catchup.
WordPress articles are retrieved and normalized. n8n pulls your posts, then a code step prepares a JSON payload so every post has the same structure before it touches GitHub.
The workflow checks what already exists in GitHub. It builds a path (including optional tag-based organization), sets repository context, pulls file metadata, and only fetches the remote file content when it’s needed for comparison.
Changes are detected and written cleanly. A comparison step decides if there’s no change, a modified file, or a totally new file, then GitHub nodes either update the existing file or create a fresh one.
You can easily modify the tag folder logic to match your categories, authors, or post types based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Trigger Type
This workflow can run manually, on a schedule, or when called as a sub-workflow. Configure all three entry points so the automation can be started from different contexts.
- Open Manual Start and keep it as the manual trigger for ad-hoc testing.
- Open Scheduled Start and set the schedule rule to run at
triggerAtHour: 17. - Open Incoming Workflow Trigger and set Input Source to
passthroughso sub-workflows can pass data into the backup flow.
Step 2: Connect WordPress
Pull all WordPress posts as the source data for the backup process.
- Add or open Retrieve WP Articles and set Operation to
getAll. - Enable Return All by setting it to
true. - Credential Required: Connect your wordpressApi credentials.
Step 3: Set Up Processing and Sub-Workflow Execution
Prepare the JSON payload and forward each record into the sub-workflow for backup handling.
- Open Prepare JSON Payload and confirm the JavaScript code adds the field
myNewFieldto each item. - Open Run Sub-Workflow (Configure Required) and keep Mode set to
eachso each item runs independently. - In Run Sub-Workflow (Configure Required), choose the target workflow in Workflow (the field is currently blank and must be set).
Step 4: Configure Tag Routing and Repository Context
Build a tag-based path and set repository identifiers used by GitHub operations.
- Open Check Tag Presence and verify it checks
{{ $json.tags[0] }}for existence using two outputs (tagandnone). - In Build Tag Path, set tags[0].name to
{{ $('Incoming Workflow Trigger').item.json.tags[0].name }}/. - In Set Repository Context, set repo.owner to
[YOUR_ID]and repo.name to[YOUR_ID]. - In Set Repository Context, set repo.path to
=workflows/{{ $json.tags[0].name }}so files are saved under the tag folder.
Step 5: Retrieve and Compare Repository Content
Check GitHub for existing files, fetch any remote content, then compare it with the incoming data.
- Open Retrieve File Metadata and set File Path to
{{ $json.repo.path }}{{ $('Incoming Workflow Trigger').item.json.id }}.json. - Credential Required: Connect your githubApi credentials in Retrieve File Metadata.
- Open Evaluate File Size and keep the conditions that check
{{ $json.content }}is empty and{{ $json.error }}does not exist. - Open Fetch Remote File and set URL to
{{ $json.download_url }}. - Open Combine Records to merge the GitHub file data with the incoming workflow data.
- Open Detect Changes and keep the JavaScript that sets
github_statustosame,different, ornew. - Open Route Status and confirm Value 1 is
{{ $json.github_status }}with routes forsame,different, andnew.
Step 6: Configure GitHub File Actions
Based on the detected status, update, create, or skip repository changes.
- Leave No Change Action as a no-op branch for the
samestatus. - Open Modify Repository File and set File Path to
{{ $('Set Repository Context').item.json.repo.path }}{{ $('Incoming Workflow Trigger').first().json.id }}.json. - In Modify Repository File, set File Content to
{{ $('Detect Changes').item.json["n8n_data_stringy"] }}and Commit Message to{{ $('Incoming Workflow Trigger').first().json.name }} ({{ $json.github_status }}). - Credential Required: Connect your githubApi credentials in Modify Repository File.
- Open Create Repository File and set File Path to
{{ $('Set Repository Context').item.json.repo.path }}{{ $('Incoming Workflow Trigger').first().json.id }}.json. - In Create Repository File, set File Content to
{{ $('Detect Changes').item.json["n8n_data_stringy"] }}and Commit Message to{{ $('Incoming Workflow Trigger').first().json.name }} ({{ $json.github_status }}). - Credential Required: Connect your githubApi credentials in Create Repository File.
- In Finalize Output, set Done to
trueto indicate completion.
Step 7: Test and Activate Your Workflow
Validate the workflow end-to-end, then turn on scheduled execution.
- Click Manual Start and run the workflow to generate a test backup.
- Confirm Route Status routes to No Change Action, Modify Repository File, or Create Repository File based on
github_status. - Check your GitHub repository for the file at
workflows/<tag>/<workflow-id>.jsonand ensure commits match the expected status. - Once confirmed, activate the workflow so Scheduled Start runs automatically at the configured time.
Common Gotchas
- GitHub credentials can expire or need specific permissions. If things break, check your token scopes in GitHub Developer Settings first (repo access is usually the missing piece).
- If you’re using Wait-like behavior implicitly (batching, large posts, or slower GitHub responses), processing times vary. Bump up timing or reduce batch size if downstream nodes fail on empty responses.
- The default “Prepare JSON Payload” logic may not match how you want files stored. Add your preferred fields and naming early, or you’ll be reorganizing the repository later.
Frequently Asked Questions
About 30–60 minutes if your WordPress and GitHub access is ready.
No. You’ll connect accounts and adjust a few repo and path settings. The only “technical” part is being comfortable creating a GitHub token and pasting it into n8n.
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 GitHub costs if you require private repos on paid tiers.
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 one of the best tweaks you can make. You can adjust the tag/category routing around “Check Tag Presence” and the path-building logic in “Build Tag Path” so posts land in folders like /category/seo/ or /author/jamie/. Many teams also customize file naming to use the post slug, and they add extra fields in “Prepare JSON Payload” (like custom fields or featured image URLs) so the repo becomes a complete content archive.
Usually it’s an expired token or missing repo permissions. Regenerate your GitHub personal access token, confirm it can access the target repository, then update the credential inside n8n. If failures happen only on bigger posts, also look at the “Evaluate File Size” decision and confirm the workflow is allowed to fetch the remote file content via the HTTP Request step.
Most small sites can run hundreds of posts per run without trouble.
For this use case, n8n is a better fit more often than not. You need conditional logic (check for file, compare content, then create vs update vs skip), plus you may need to fetch and merge remote file data before you can detect changes. Zapier and Make can do parts of it, but it tends to get expensive or awkward once you add branching and file comparison. n8n also gives you a self-host option, which is handy if you want unlimited runs and full control. If you’re unsure, Talk to an automation expert and you’ll get a straight recommendation based on your volume and team workflow.
Once this is running, your WordPress edits stop being a mystery and start being a timeline. The workflow handles the repetitive tracking so you can focus on the content itself.
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.