WP Webhooks / Automations / Review and approve pending WordPress posts with Gemini and Slack

Review and approve pending WordPress posts with Gemini and Slack

When a writer submits a post for review, WordPress sends its ID to one n8n webhook. In n8n, the post is checked against your rules and reviewed by Gemini. An editor then gets it in Slack with one Review button: publish it, or send it back with a note that goes to the author by email.

Why it goes through n8n

WordPress has a Pending status but nothing that acts on it: someone has to remember to look. This build sends the moment of submission out, so the review starts right away and the editor never has to check the posts list.

n8n holds the WordPress, Gemini, Slack and email connections, so WordPress only ever talks to one URL. Change the house style, the word count or the review channel in n8n, and nothing changes in WordPress.

What you need first

  1. In n8n, import the template Review and approve pending WordPress posts with Gemini and Slack. In its Settings node, set the review channel, your house style, the minimum word count, whether a featured image or excerpt is required, how long the editor has to answer and the sender address.
  2. Connect WordPress (an administrator or editor account with an application password, because a pending post is not public), Gemini (an API key from Google AI Studio), Slack (a bot token with chat:write, invited to the review channel) and SMTP inside n8n.
  3. Open the Review Request Webhook node, add a Header Auth credential with the name X-Webhook-Token and a long random token as the value, and copy the node's production URL.
  4. Import this build. The webhook arrives disabled: replace its endpoint URL with that production URL, give the import the same token when it asks for the credential, then enable it. The token lives in the Credentials Vault and is never part of a shared build.

What gets sent

{
  "post_id": 123
}

Only the ID travels. wp_after_insert_post hands over the post ID, the post, an update flag and the post as it was before the save; args.0 becomes post_id and nothing else is sent. n8n reads the post and its author back through the WordPress API, so it always sees the saved version.

Three conditions decide when it fires: args.1.post_status equals pending, args.3.post_status does not equal pending, and args.1.post_type equals post. A post fires once, when it moves to Pending. Saving it again while it waits, and revisions, send nothing.

Why this hook

The block editor saves the post first and its featured image, categories and custom fields after. transition_post_status and save_post fire in between, so n8n would read a post with no featured image yet. wp_after_insert_post fires last, when everything is stored.

If a delivery fails

Delivery is asynchronous, so the writer never waits on n8n. A failed POST is retried 5 times (1m, 2m, 4m, 8m) and every attempt is kept in the delivery log. If n8n was down for the whole ladder, hit Replay once it's back and the post goes to review as if it had just been submitted.

A 200 from the webhook node only means n8n accepted the post. Check n8n's own execution list to see what happened next. If Gemini is down, the editor still gets the post, marked for review by hand. Before publishing, n8n checks the post is still pending, so a post someone already published by hand is left alone.

/ The conversation

This build was not assembled by hand. Its author described what they wanted in Build with AI, and the agent read the site, planned the work and applied it. This is that conversation.

model gemini-3.7-flash via hosted AI credits
Author

When a writer submits a post for review, send its ID to my n8n webhook at https://n8n.flowsystems.pl/webhook/cd59e65c-51ed-4f71-af9a-b1045957df7c, using the "n8n post review webhook token" from the vault as the X-Webhook-Token header. Only for posts, only at the moment the post moves to Pending (not when it's saved again while it's already pending), and send just the post ID as post_id.

Build with AI

Checking the trigger payload schema for post submissions and locating the vault credential...

Build with AI

I'll create the webhook for the wp_after_insert_post trigger to capture the moment a post is submitted for review.

Here is how this will be configured:

  • Trigger & Filter: Using wp_after_insert_post, filtering with args.1.post_type equals post, args.1.post_status equals pending, and args.3.post_status not_equals pending. This triggers strictly when a post first enters pending review (ignoring subsequent saves while already pending, autosaves, and other post types).
  • Payload Mapping: Mapping args.0 to post_id and dropping unmapped fields so only {"post_id": ...} is sent.
  • Authentication: Attaching stored vault credential n8n post review webhook token (X-Webhook-Token header).
  • Delivery Mode: Background (asynchronous) mode is selected so post saves in WordPress are not delayed.

Since the trigger schema was read from the reference library, we'll verify the outgoing payload with a test dispatch before enabling the webhook.

Published by the author on purpose. Tool output and raw payloads never travel with a shared build, and secrets never leave the site they were created on.

/ Abilities used (6)

  1. create_webhook Create disabled webhook for post review submissions
  2. assign_credential Attach the n8n post review token vault credential
  3. set_conditions Filter for posts transitioning into pending status
  4. set_mapping Map post ID to post_id and drop unmapped fields
  5. test_dispatch Send test delivery to verify the payload and authentication with n8n
  6. enable_webhook Enable the webhook to go live

Each of these is a real ability the agent can call — see the docs for what each one does.

/ What runs

Post Submitted for Review → n8n
WordPress fires
wp_after_insert_post
Only when
3 conditions match
Field mapping
1 field mapped
Queued, then sent
POST https://n8n.flowsystems.pl/webhook/cd59e65c-51ed-4f71-af9a-b1045957df7c with your credential

Every attempt is retried on its own schedule and written to the delivery log.

WordPress fires the action wp_after_insert_post, if the conditions below match, the payload is mapped and sent as POST to n8n.flowsystems.pl. The delivery is queued and sent in the background, so the visitor never waits. Along the way authentication comes from a credential you supply on import.

/ How it is configured

Post Submitted for Review → n8n
wp_after_insert_post

/ Only when

  • args.1.post_type equals post
  • and args.1.post_status equals pending
  • and args.3.post_status does not equal pending
  • ↳ otherwise the delivery is skipped, and logged as skipped

/ Field mapping

args.0 post_id

/ Authentication

This build authenticates with a credential you supply on import. The shared file carries the name and type only — never the secret.

  • n8n post review webhook token — api_key

/ Use this build

Download the file, then in WordPress open Webhook Actions → Webhooks → Import and drop it in. Anything needing authentication asks you to pick or create a credential as it imports — see Import & Export for what travels with a build and what does not.

A like sends 20 AI credits to whoever published this.

/ Published by

Flow Systems

/ Questions

Do I need a paid plan for this build? +
No. Everything a build can contain — webhooks, triggers, field mapping, conditions, retries, chains and Code Glue snippets — is in the free plugin from 3.0.0 on. A paid plan buys hosted AI credits and external cron, neither of which an imported build needs.
How do I use it on my own site? +
Download the JSON, then in WordPress open Webhook Actions → Webhooks → Import and drop the file in. Anything that needs authentication asks you to pick or create a credential during the import — secrets are never part of a shared build.
Does the build contain the author's API keys? +
No. Export carries credential metadata only — the name, the type and a masked hint — never the secret itself. The Credentials Vault is write-only over the API by design.
Publish

Publish your automation and get 50 AI credits,
+20 for each like.

$ wp plugin install flowsystems-webhook-actions --activate