---
title: "n8n and WordPress: What Is Actually Worth Wiring Together"
url: https://adityaarsharma.com/n8n-wordpress-what-to-automate/
date: 2026-09-13
modified: 2026-09-03
author: "Aditya Sharma"
description: "There is no WordPress Trigger node in n8n, and that single absence decides most of what is worth building. Real nodes, real webhook setup, honest limits."
categories:
  - "Automation"
  - "WordPress"
image: https://adityaarsharma.com/wp-content/uploads/2026/09/0b4663fa-1969-49d7-bf93-ac592083b3d9_2912x1632-1024x574.webp
word_count: 2366
---

# n8n and WordPress: What Is Actually Worth Wiring Together

The n8n documentation index at docs.n8n.io/llms.txt lists 309 app node pages. Search the whole index for WordPress and you get exactly two hits: the WordPress node, and the WordPress credential. There is no WordPress Trigger.

![n8n can call WordPress. WordPress cannot call n8n.](https://adityaarsharma.com/wp-content/uploads/2026/09/0b4663fa-1969-49d7-bf93-ac592083b3d9_2912x1632-scaled.png)![309 app node pages in the n8n docs index, two hits for WordPress, zero WordPress trigger nodes.](https://adityaarsharma.com/wp-content/uploads/2026/09/7a331023-ce69-4088-b48a-1e801d266a83_2912x1632-scaled.png)Built from docs.n8n.io/llms.txt, read 2 September 2026.

### What the missing trigger decides

That single absence decides most of what is worth building. n8n can talk to WordPress whenever it wants to.

WordPress cannot start an n8n workflow unless you make it, which means every idea of the shape "when a post is published, do X" needs code on the WordPress side before n8n is involved at all.

Once you have written that code, a fair number of the automations people reach for stop needing n8n.

Here is what actually earns its place, what does not, and the parts of the setup that are not obvious.

## What the WordPress node can and cannot do
Per the node documentation, the operations are Post create, get, get all and update; Pages create, get, get all and update; User create, get, get all and update. That is the whole surface.

### The fields the node accepts

The fields on a post are worth listing, because the gap is where people lose an afternoon.

From `PostDescription.ts` in the n8n source, post create takes title, plus optional Author ID, Content, Slug, Password, Status, Date, Comment Status, Ping Status, Format, Sticky, Categories, Tags and Post Template.

Status includes Future, so the node can schedule.

### The three fields that are missing

What is not there: **no featured image, no excerpt, no custom fields.** There is no `featured_media` field and no `meta` field.

A workflow that publishes a finished article with a cover image cannot be built with this node alone, and no amount of configuration will change that.

### The way around it

The way through is the HTTP Request node with the same credential. From the n8n docs: in the HTTP Request node select **Authentication > Predefined Credential Type**, then the service, then your credential.

So you get Application Password auth for free while calling any endpoint the node does not cover, including `/wp/v2/media`.

At that point you are writing raw REST calls in a workflow editor, which is a reasonable moment to ask whether [a script that publishes to WordPress directly](https://adityaarsharma.com/publish-to-wordpress-from-a-script/) would be shorter.

## Credentials, and the part the docs get sideways
The WordPress credential page in the n8n docs is written for WordPress.com. It walks you through enabling Two-Step Authentication on wordpress.com and generating an application password there.

For a self-hosted site none of that applies: you generate the Application Password in your own admin, under Users, your profile, Application Passwords, which core has shipped since 5.6.

### The four fields, and the one to leave alone

Four fields to fill in, per the docs: Username, Password, WordPress URL, and Ignore SSL Issues. Leave Ignore SSL Issues off. The docs are explicit that the OAuth2 option is WordPress.com only, so for self-hosted, basic auth is the only path.

Test it before you build anything on it, from a shell rather than from n8n, so you know which side is broken:

`curl -s -u "aditya:abcd EFGH ijkl MNOP qrst UVWX" \
"https://example.com/wp-json/wp/v2/users/me?context=edit" | jq '{id,name}'`
## Making WordPress start a workflow
Two options, and they are not equivalent.

![The WordPress feed carries ten items by default, set by posts_per_rss.](https://adityaarsharma.com/wp-content/uploads/2026/09/3195f573-05e5-4036-8a48-8057b38bd4d2_2400x2400.png)WordPress Settings, Reading. n8n RSS Feed Trigger documentation, read 2 September 2026.

### Option one: poll the feed

**Option one: poll the feed.** The RSS Feed Trigger node points at `https://example.com/feed/` and fires on new items. Zero code on the WordPress side, which is the entire appeal.

The limits are real though. The feed carries published posts only, so nothing about drafts, scheduled posts or updates reaches you.

It carries the number of items set by `posts_per_rss` in Settings, Reading, which is 10 by default, so a burst of eleven publications inside one polling window loses one.

And it gives you the rendered feed content, not the post ID, so the first thing your workflow does is guess which post this was.

### Option two: fire a webhook

**Option two: fire a webhook from WordPress.** More honest, and about twenty lines in `wp-content/mu-plugins/notify-n8n.php`. The shape is a hook, two guards and one outbound request.

`add_action( 'transition_post_status', 'aas_notify_n8n', 10, 3 );

function aas_notify_n8n( $new_status, $old_status, $post ) {
if ( 'publish' !== $new_status || 'publish' === $old_status ) { return; }
if ( 'post' !== $post->post_type ) { return; }
$response = wp_remote_post( N8N_HOOK_URL, $args );
}`Constants go in `wp-config.php`, not in the file above, so the key is not sitting in a directory that ships with a theme export:

`define( 'N8N_HOOK_URL', 'https://n8n.example.com/webhook/wp-published' );
define( 'N8N_HOOK_KEY', 'a-long-random-string' );`
### Four decisions in that snippet

Four decisions in that snippet worth explaining, because the defaults are all wrong.

- `transition_post_status` rather than `publish_post`, and the `'publish' === $old_status` guard, so editing an already-live post does not re-fire. Without that guard every typo fix reposts to your channels.- `'blocking' => true` with a 5 second timeout. Non-blocking is faster and it makes every delivery failure invisible, which is exactly the trap that makes WP-Cron so hard to debug. Five seconds in the editor's save request, once per publication, is a fair price for knowing.- `'data_format' => 'body'`. Without it, `wp_remote_post()` treats the body array as form fields. You want the raw JSON string to arrive as the body.- A shared secret in a header. In n8n, set the Webhook node's **Authentication** to **Header Auth** and create the matching credential. The node supports Basic auth, Header auth, JWT auth or None. Leaving it on None gives anyone who guesses your URL the ability to trigger the workflow with whatever payload they like.- The `$args` array is `timeout` 5, `blocking` true, `headers` carrying `Content-Type: application/json` and `X-Webhook-Key`, `body` set to the encoded payload, and `data_format` set to `body`.- The payload is `wp_json_encode()` of the post `id`, `slug`, `title`, `permalink` from `get_permalink()`, `author`, `categories` from `wp_get_post_categories()`, `date_gmt`, and `was`, which carries the old status.- On `is_wp_error( $response )`, log the message and return. Otherwise read `wp_remote_retrieve_response_code()` and log anything outside the 2xx range with the response body.
### The two webhook URLs, which are not the same

On the n8n side, the Webhook node hands you two URLs and they are different: the test URL only listens while you have pressed Listen for Test Event or are executing the workflow manually, and the production URL only exists once the workflow is published.

Half of all "my webhook does not fire" is a test URL in `wp-config.php` and nobody sitting on the canvas.

Set the Path field to something you chose, like `wp-published`, rather than keeping the random one, and pick Respond: Immediately so WordPress is not held open while the workflow runs.

## Worth wiring

### The test I use

The test I use: does the work cross a boundary that WordPress has no business knowing about, and would doing it in PHP mean storing someone else's credentials in `wp-config.php`? If yes, n8n is genuinely the right place.

- **Fan-out on publish.** One post goes live, and five systems need to hear about it: a Slack channel, a newsletter tool, a social scheduler, a Google Sheet you actually read, a search engine ping. Webhook node in, Code node to shape the payload, then parallel branches. Adding a sixth destination later is a node, not a deployment.- **Inbound content from somewhere with no WordPress plugin.** A form provider, a client's Airtable, a transcription service. n8n creates the draft through the WordPress node and a human presses publish. This is the case the node's field list actually fits, because a draft does not need a featured image yet.- **Scheduled reporting that reads several systems.** Schedule Trigger, a few reads, a Merge node, one summary somewhere you will see it. Nothing is written back to WordPress, so the blast radius is zero, which makes it the right first workflow to build while you are learning where the sharp edges are.- **Anything you want an execution log for.** n8n stores each run with its input and output per node. For a job that runs weekly and fails silently three months later, that log is worth more than the code being tidy.

Newsletter

## Automating the boring half

I publish one researched piece a week on putting agents to work on real sites. What I built, what broke, and the commands to check it yourself.

Email address

Get it weekly

Free. One email a week. Unsubscribe in one click, and I do not send anything else.

## Not worth wiring
- **Anything that happens entirely inside one WordPress site.** Auto-tagging on publish, sending an email when an order completes, setting a default category. That is an `add_action()` and five lines, running in the same process, with no network hop and no second system to keep up. When I wanted a refund button inside a support desk I built it as [a one-click EDD refund button inside Fluent Support](https://adityaarsharma.com/fluent-support-one-click-refund-button/) rather than as a workflow, and it has needed no maintenance since, because there is nothing between the button and the API.- **Bulk edits.** n8n will loop 400 HTTP requests at you happily. What it will not give you is a dry run you can read before anything is written, a diff, or a verification pass. Those are the three things that make a bulk edit survivable, and they are why [bulk editing over the REST API](https://adityaarsharma.com/bulk-edit-wordpress-rest-api/) belongs in a script with a plan file rather than on a canvas.- **Publishing finished articles with images.** The node cannot set `featured_media`. You end up doing the media upload through an HTTP Request node, base64 handling and all, which is more code than the script version and harder to test.- **Replacing WP-Cron.** Pointing a Schedule Trigger at `wp-cron.php` puts a whole workflow platform in the path of something a crontab line does better. [Disabling WP-Cron and running it from system cron](https://adityaarsharma.com/wordpress-missed-schedule-wp-cron/) is the fix, and it has one moving part.- **Sending a few hundred personalised emails.** If the data already lives in a spreadsheet, [sending them from Gmail with Apps Script](https://adityaarsharma.com/how-to-send-mass-email-in-bulk-with-gmail-using-sheets/) needs no server, no credentials in a third system, and no monthly execution limit.
## Three settings that decide whether it survives
![A 09:00 Schedule Trigger fires at 18:30 in India when the workflow timezone is left on the default.](https://adityaarsharma.com/wp-content/uploads/2026/09/4f27beeb-d399-460f-a712-a463c94d3cc5_2400x2400.png)n8n Schedule Trigger documentation, read 2 September 2026.

### Timezone

**Timezone.** The Schedule Trigger uses the workflow timezone if set, otherwise the instance timezone, and the n8n docs state the self-hosted default is `America/New_York`.

If you are in India and you set a trigger for 09:00 without touching workflow settings, it fires at 18:30 your time. Set the workflow timezone explicitly, on every workflow, and never rely on the instance default.

### Missed executions

**Missed executions.** The Schedule Trigger's Settings tab has an **If Execution Is Missed** option with three values: don't run missed executions, which is the default, run the most recent missed execution, or run the most recent missed execution per rule.

Read the caveat in the docs carefully. These options exist from n8n 2.36, only on Schedule Trigger nodes added from that version on, and they only do anything when the instance runs the durable scheduler.

The default in-memory scheduler never runs missed executions. So on a stock self-hosted instance, a restart at 08:59 means the 09:00 run never happened and nothing tells you.

### Error workflow

**Error workflow.** Build one workflow whose first node is an Error Trigger, then set it under Options, Settings, Error workflow on every workflow you care about.

The payload gives you `execution.id`, `execution.url`, `execution.error.message` and `execution.lastNodeExecuted`, which is enough to send yourself a message naming the workflow, the node and a link.

Two things from the docs worth knowing before you trust it: you cannot test an error workflow by running a workflow manually, because the Error Trigger only fires on automatic executions, and when the failure is in the trigger node itself the payload has a `trigger` object instead of a populated `execution` object, so code that reads `execution.error.message` throws inside your error handler.

## Batching, when you do loop
If a workflow does end up making many WordPress calls, the node is Loop Over Items, type `n8n-nodes-base.splitInBatches`, still labelled Split In Batches in older workflows.

Set Batch Size, wire the **loop** output through the work and back into the node, and take the **done** output for whatever happens at the end.

The Reset option restarts the accumulation, which is how you page an unknown number of pages with an If node as the exit condition.

The docs carry a warning that is not decorative: without a termination condition that actually becomes true, the execution loops forever.

### When to reach for it

Most n8n nodes already process every input item, so reach for this node when you specifically need to slow something down or when a node only handles the first item.

For the WordPress REST API the practical ceiling is not the API, it is whatever your host's rate limiting does at 40 requests a second from one IP.

## The honest summary of the split
n8n is a good integration layer and a poor application layer. Use it where two systems that do not know about each other have to exchange a message, and where you would otherwise be storing a third party's API key inside WordPress.

Do not use it as a place to keep logic that belongs in one system, because a workflow is harder to read than the function it replaced, it is not in version control by default, and it adds a second thing that can be down.

### The same test on the tools next to it

The same test applies to the tools next to it. Pulling [YouTube video details into a Google Sheet](https://adityaarsharma.com/how-to-import-youtube-video-details-in-google-sheets/) or [saving search results to a sheet on a schedule](https://adityaarsharma.com/save-tweets-in-google-sheets-with-twitter-search/) needs a spreadsheet and a script, not a workflow engine.

Reach for the engine when the count of systems goes above two.

## Build this one first
The mu-plugin above, a Webhook node with Header Auth, and one branch that posts the title and permalink into a Slack channel. Nothing writes back to WordPress, so the worst failure is a missing message.

Publish a test post and watch the execution appear. If it does not, you now know whether the request left WordPress, because you made the call blocking and put the status code in the error log.

## More on wordpress automation
- [Scheduling WordPress Content Properly: Why Posts Miss Their Schedule and How to Fix It for Good](https://adityaarsharma.com/wordpress-missed-schedule-wp-cron/)- [Bulk Editing WordPress Content Over the REST API Without Breaking Anything](https://adityaarsharma.com/bulk-edit-wordpress-rest-api/)- [Publishing to WordPress From a Script: The Complete, Correct Way](https://adityaarsharma.com/publish-to-wordpress-from-a-script/)
## Resources
- [WordPress node documentation](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.wordpress/), the full operation list- [WordPress credentials in the n8n docs](https://docs.n8n.io/integrations/builtin/credentials/wordpress/), including the OAuth2 restriction- [Webhook node documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.webhook/), test versus production URLs and the auth methods- [Schedule Trigger documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.scheduletrigger/), timezone behaviour and the missed execution options- [Error Trigger documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.errortrigger/), with the exact error payload shape- [Loop Over Items documentation](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.splitinbatches/)- [wp_remote_post() in the code reference](https://developer.wordpress.org/reference/functions/wp_remote_post/), for the argument list used above