Automatic Blog‑Post Pipeline: Git + GitLab + n8n + WordPress

Why bother?

Markdown is much easier and faster to work with than building HTML, or WordPress blocks, so my personal theory is that I might actually post more if I make it easier for myself. Also it is an excuse to play with automation and AI. Do we need more of a reason then that?

The pieces

Now, I like to self-host things. A lot. All the parts and pieces listed below I am hosting myself across a number of physical and virtual machines as well as containers. Why not play with even more tech?

Tool      | What it does.
Git       | Version control, keeps a history of your posts.
GitLab    | Host for your Git repo.
n8n       | Workflow engine that ties everything together.
markdown  | Transforms the Markdown to HTML cleanly.
WordPress | The blog that actually displays the content.

What you’ll need

  • A GitLab account and a repository for your posts (Markdown files). Self-hosted or otherwise as long as n8n can reach it, it should not be a problem.
  • A WordPress site with the REST API enabled (Application Passwords are the easiest route).
  • An n8n instance and account.
  • A little time to tinker with configurations.

Step 0 – Borrowing someone else’s homework

If you really just want to copy my design then the json is below, you will need to tweak some settings, things like where you are pulling the blog posts from, your username, etc. Linked here

Step 1 – GitLab repo

Create a new repo called blog-posts.
Now the way you structure this is up to you. To make it easy for myself I assumed that I would only be making a post once a day tops. So in my repo I have <yyyy-MM-dd>.md
The automation is built around using this format. So let’s create a test file with today’s date

 

# Hello World!

Welcome to my new blog. This is the first post, written in Markdown.

 

Commit and push.
Your repo will now holds a clean history of every article you’ll write.

Step 2 – WordPress prep

On your WordPress admin:

  1. Go to Users → Profile.
  2. At the bottom, click Generate Application Password.
  3. Name it “n8n” and copy the password.
  4. Note your WordPress URL (e.g., https://davidrusseltrask.com).

You’ll need the URL, the username (your admin user), and the password you just generated.

Step 3 – n8n workflow

Open your n8n instance and create a new workflow.
It will have four main nodes:

  1. GitLab Trigger – fires on a push to the repo.
  2. GitLab: Get File – fetches the Markdown file.
  3. Markdown – Transforms the markdown into HTML
  4. WordPress – creates a new post.

Note: There is a built in markdown to HTML converter, but it doesn’t handle tables at all

3.1 GitLab Trigger

Node type: GitLab
Event: Push
Repository: blog-posts
Branch: main

When you push a new file, this node will fire.

3.2 GitLab: Get File

We need the raw content of the Markdown file.
Node type: GitLab: Get File
Resource: File
Operation: GET
Project Owner: <your gitlab user>
Project Name: <your repo name>
File Path: {{ $now.format('yyyy-MM-dd') }}.md
As Binary Property: True
Put Output File in Field: chatInput
Reference: <the branch you want to pull from, probably "main">

Add the GitLab credential you created earlier, so the request can authenticate if required.

3.3 Markdown to HTML

3.3.1 What didn’t work

Originally I spent a bunch of time getting an AI (Ollama) to do this part, because the markdown to HTML convert can’t do tables. As I discovered with my AI generated Test blog entry. I worked at it for over a day and thought I got everything I needed configured then I wrote this entry and it completely broke the AI. My Hello World example kept sending the AI into weird loops. I’ll include the system prompt that I used (probably the problem), feel free to steal and tweak it, I spent hours on that, tuning and tweaking all for it to fail on the next blog entry. System Prompt

3.3.2 What did work

The markdown to HTML node…. Mostly.
As I said it can’t convert tables but everything else looked good. Since I don’t usually make tables on my blog that shouldn’t be a problem… Until it is, then I’ll have to manually update the post. Ugh, manual work…

3.4 WordPress

You’ll need to setup the Credentials to connect with:
Username: <your username>
Password: <your application password>
WordPress URL: your WordPress base url

Then it’s time to configure the rest of this wordpress node.

Node type: WordPress
Resource: Post
Operation: Create
Title: {{ $json.output.removeMarkdown().split("\n")[1] }}

Add additional fields:
Content: {{ $json.output.split("</h1>")[1] }}
Status: Publish

Once you save the workflow, it’s ready to roll.

Step 4 – Test it

Push a new file to blog-posts:

git checkout -b main
cat > 2025-10-04.md <<EOF

# Hello World

This is a brand‑new article. Watch the AI do its thing.
EOF
git add -A
git commit -m "Add new article for 2025-10-04"
git push

n8n will catch the push, grab the file, and create a WordPress post.
Open your blog, and you’ll see Hello World live.

Common hiccups

Problem | Fix
“401 Unauthorized” from WordPress | Double‑check the Application Password. Don't use your user account password.
“404 Not Found” on GitLab API | Verify the project ID and file path.

Note: I did have to go into GitLab and modify the webhook to point at the n8n server correctly as it had given GitLab the webhook of http://localhost:5678/webhook/....
I updated the correct URL and it worked!

Going further

  • Scheduling – add a cron node to publish drafts at a set time.
  • Images – store images in GitLab, fetch them, and upload via the WordPress media endpoint.
  • Custom fields – use the Advanced WordPress node to set custom meta.

The beauty of n8n is that every tweak is a node.
If you hate writing code, you can use the built‑in UI.
If you love code, you can export the workflow as JSON and version‑control the workflow itself.

Final thought

You’re now set up with a pipeline that turns a Markdown file in GitLab into a live WordPress post, all with a single push.
That’s the kind of automation that turns “I’ll write tomorrow” into “I’m a published author now.” Happy blogging!