Automate Publishing with n8n and LLM: From Research to WordPress
Learn how to automate research, LLM article generation, and WordPress publishing with n8n using Docker, cron, and simple API credentials.
Before you start: versions, package names and storage identifiers change over time. Check the commands against the official documentation for your setup before running them, especially anything that creates, deletes or overwrites data.
Wiring n8n to an LLM and the WordPress REST API is straightforward. Making the result worth publishing is not, and that is the part most guides skip entirely.
This covers the working pipeline — authentication, the n8n deployment, the workflow shape — and then the editorial gates that decide whether you have an automation or a liability.
Step 1: WordPress application password
Do not use your login password. WordPress has application passwords for exactly this: Users → Profile → Application Passwords, create one, copy it once.
Test it before building anything on top:
curl -u "username:APPLICATION_PASSWORD" \
"https://example.com/wp-json/wp/v2/posts?_fields=id,title&per_page=1"
A JSON array means authentication works. A 401 with rest_cannot_create usually means the application password was pasted with its spaces stripped — WordPress displays it in groups of four, and it is valid either way, but it must match what you copied.
Create a dedicated WordPress user for this with the Author role rather than reusing an administrator. An automation that can only publish posts cannot install a plugin if the credential leaks.
Step 2: Deploy n8n
Create compose.yaml:
services:
n8n:
image: docker.n8n.io/n8nio/n8n:latest
restart: unless-stopped
ports:
- "5678:5678"
environment:
- N8N_HOST=n8n.example.com
- N8N_PROTOCOL=https
- WEBHOOK_URL=https://n8n.example.com/
- GENERIC_TIMEZONE=Europe/Rome
- TZ=Europe/Rome
- N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true
volumes:
- n8n_data:/home/node/.n8n
volumes:
n8n_data:
Three corrections against older versions of this guide and others like it:
N8N_HOSTis not a bind address. It is the host name n8n runs on, used to build URLs. SettingN8N_HOST=0.0.0.0produces webhook URLs pointing at0.0.0.0. The variable for the listen address isN8N_LISTEN_ADDRESS.EXECUTIONS_PROCESSno longer exists. It was removed along with “own” mode. Main mode is the default; if you need execution isolation, that is queue mode viaEXECUTIONS_MODE=queue.- No
version:key. It is obsolete and Compose warns about it.
docker compose up -d
docker compose logs -f n8n
On first visit you create the owner account — mandatory since n8n 1.0, and not disableable.
Step 3: The workflow
The minimum viable shape is five nodes:
| Node | Does |
|---|---|
| Schedule Trigger | Fires on a cron schedule |
| HTTP Request / RSS | Pulls source material |
| Code | Builds the prompt from that material |
| HTTP Request | Calls the LLM |
| HTTP Request | POST /wp-json/wp/v2/posts |
Store the LLM and WordPress credentials in n8n’s credential store, not as literals in nodes. Credentials are encrypted with the key in /home/node/.n8n — which is also why losing that volume makes every stored credential unrecoverable.
Post to WordPress as a draft first:
{
"title": "={{ $json.title }}",
"content": "={{ $json.content }}",
"status": "draft"
}
Switch status to publish only once you have the gates below in place.
On model names
Pin a current model and revisit it. Guides that hardcode gpt-3.5-turbo are citing a model generations behind, and the cost and quality assumptions built around it no longer hold. Whatever provider you use, check its current model list rather than inheriting one from a tutorial.
Step 4: The part that actually matters
A pipeline like this will produce clean, confident, well-structured articles that are wrong. Not obviously wrong — wrong in specifics, while reading like expertise.
We can be concrete about what that looks like. During an editorial audit of an automated publishing workflow of exactly this shape, we found, among other things:
- A tutorial documenting configuration file paths that do not exist for the tool it described, alongside a CLI subcommand the tool has never had.
- An installation guide describing a natively compiled binary as a Python package installed with
pip, complete with virtual-environment instructions. - A sysadmin guide using two
pctflags that are not in the command’s option list, so the documented procedure fails at step one. - An article opening with a first-person claim about weeks of hands-on testing that never took place.
- Configuration examples built on environment variables the upstream project had removed in a major release — including one that was supposed to be providing authentication.
None of these look wrong on the page. They are fluent, well-formatted and plausible, and they were indexed and ranking for real queries.
The failure is not that the model lies at random. It is that a research step which returns thin or wrong material produces a confident article anyway, and a quality check that validates the article against that same research cannot catch it. Checking internal consistency is not fact-checking.
Gates worth building in, in rough order of value:
- Require a source URL per claim-heavy article. If the research step returned nothing substantive, stop the run — do not let the model fill the gap.
- Ban first-person experience in the prompt, explicitly. No “I tested”, “in my testing”, “after two weeks with”. The model has not used the product. Stating this negatively in the prompt works better than hoping.
- Verify against the primary source, not the draft. A separate step that checks specific factual claims — paths, commands, version numbers, requirements — against official documentation.
- Check for duplicates before writing. Query your existing posts for the topic first. Near-duplicate articles competing for one query is the fastest way to waste whatever authority the site has.
- Default to draft. Publish automatically only for categories where being wrong is cheap, and never for anything procedural that a reader will paste into a terminal.
The honest summary: automation is good at the pipeline and bad at judgment. Use it to remove the mechanical work — fetching, formatting, posting — and keep a human between the draft and the publish button for anything technical.
Troubleshooting
| Symptom | Cause |
|---|---|
401 from the WordPress API |
Application password wrong, or the user lacks the capability |
| Post created with HTML shown as text | Content sent escaped — pass raw HTML, not a JSON-escaped string |
Webhook URLs point at 0.0.0.0 |
N8N_HOST used as a bind address |
| Credentials unusable after a rebuild | The /home/node/.n8n volume — and its encryption key — was lost |
| Workflow runs but no post appears | Posting as draft; check the drafts list before debugging further |
Sources
- n8n docs — Install with Docker
- n8n docs — Deployment environment variables (
N8N_HOSTvsN8N_LISTEN_ADDRESS) - n8n docs — v1.0 migration guide (
EXECUTIONS_PROCESSand own mode removed) - WordPress REST API — Posts reference
- Docker docs — Compose file version and name
Related reading
Some links on this page may be affiliate links. If you buy through them we may earn a commission at no extra cost to you. See our affiliate disclosure.