Publishing content to WordPress manually consumes 4–6 hours weekly for most marketing teams, according to 2024 Content Marketing Institute data. n8n, the Berlin-based workflow automation platform founded in 2019 by Jan Oberhauser, eliminates this bottleneck by connecting 350+ applications — including WordPress — through a visual node editor that supports custom Python code. With $253.5 million raised across four funding rounds and a $2.5 billion valuation as of October 2025, n8n has become the preferred source-available alternative to Zapier for technical teams needing self-hosted control. This guide walks you through building a production-ready n8n workflow that uses Python to fetch, transform, and publish content to WordPress via its REST API, covering authentication, error handling, and scheduling so you can deploy once and publish forever.
Quick Answer: Create an n8n workflow with an HTTP Request node for WordPress REST API authentication (Application Passwords), a Python Code node to transform content, and a WordPress node to publish posts. Schedule via Cron node. Test with a draft post first, then enable production scheduling.
Why Automate WordPress Publishing with n8n and Python
Eliminate Manual Bottlenecks at Scale
WordPress powers 22.52% of the top one million websites as of December 2024, yet its native editor requires manual copy-pasting for every post. n8n's visual workflow editor connects to WordPress's REST API (introduced in WordPress 4.7, December 2016) to automate the entire publish pipeline. Python adds data transformation capabilities — cleaning HTML, injecting SEO metadata, resizing images — that native n8n nodes cannot handle alone. A 2023 n8n community survey found 68% of users combine code nodes with third-party APIs for custom logic.
Self-Hosted Control Beats SaaS Lock-In
Unlike Zapier or Make, n8n runs on your infrastructure (Docker, Kubernetes, or bare metal). This means zero per-task fees, full data sovereignty, and the ability to run Python scripts with any library (requests, BeautifulSoup, pandas) without vendor restrictions. The platform's Node.js/TypeScript core executes Python in isolated sandboxes, preventing dependency conflicts. For teams publishing 50+ posts monthly, self-hosted n8n saves $200–$500 monthly versus Zapier's Professional plan.
Prerequisites: WordPress REST API Setup and n8n Installation
Enable WordPress Application Passwords
WordPress 5.6+ (December 2020) includes Application Passwords for REST API authentication without plugins. Navigate to Users → Profile → Application Passwords, generate a new password named "n8n-automation", and store it securely. The REST API base URL follows the pattern https://yoursite.com/wp-json/wp/v2/. Test with curl -u "username:app_password" https://yoursite.com/wp-json/wp/v2/posts — a 200 response confirms access.
Deploy n8n with Python Support
Use the official Docker image docker.n8n.io/n8nio/n8n:latest which includes Python 3.11+. For Kubernetes, the Helm chart n8n/n8n (version 0.12.0+) exposes pythonEnabled: true in values.yaml. Self-hosted instances require setting NODE_FUNCTION_ALLOW_EXTERNAL=* and N8N_PYTHON_PACKAGES=requests,beautifulsoup4,lxml environment variables. Cloud users enable Python in Settings → Code → Python Packages.
Build the Core Workflow: Fetch, Transform, Publish
Step 1: Trigger and Fetch Source Content
- Add a Cron node: Every day at 06:00 UTC (adjust for your timezone).
- Add an HTTP Request node: GET your content source (API, RSS, database). Example:
https://api.example.com/articles?status=pendingwith HeaderAuthorization: Bearer YOUR_TOKEN. - Add an IF node: Check
{{ $json.length > 0 }}to proceed only when content exists.
Step 2: Transform Content with Python
- Add a Code (Python) node. Paste this template:
import re, html
from bs4 import BeautifulSoup
items = $json
for item in items:
# Clean HTML
soup = BeautifulSoup(item['content'], 'html.parser')
for tag in soup(['script', 'style', 'iframe']):
tag.decompose()
item['clean_content'] = str(soup)
# Generate slug
item['slug'] = re.sub(r'[^a-z0-9]+', '-', item['title'].lower()).strip('-')
# SEO meta
item['yoast_meta'] = {
'title': item['title'][:60],
'description': soup.get_text()[:155]
}
return items
This runs in n8n's Python sandbox with BeautifulSoup4 pre-installed. Output feeds directly to the next node.
Step 3: Publish to WordPress via REST API
- Add an HTTP Request node: POST to
{{ $credentials.wordpressApiUrl }}/posts. - Authentication: Select "Header Auth", name
Authorization, valueBasic {{ $credentials.wordpressAuth }}(base64 encodedusername:app_password). - Body (JSON): Map fields from Python output:
{
"title": "{{ $json.title }}",
"content": "{{ $json.clean_content }}",
"slug": "{{ $json.slug }}",
"status": "draft",
"meta": {{ $json.yoast_meta }}
}
Set status to "draft" for review, "publish" for immediate live. Add a Slack node to notify editors on success/failure.
Advanced: Media Handling, Taxonomies, and Error Recovery
Upload Featured Images via Python
WordPress media endpoint (/wp/v2/media) requires multipart/form-data. Python's requests handles this natively:
import requests, base64
image_url = item['featured_image']
resp = requests.get(image_url)
media = requests.post(
f"{wp_url}/media",
headers={'Authorization': f'Basic {auth}'},
files={'file': (item['slug']+'.jpg', resp.content, 'image/jpeg')},
data={'alt_text': item['title']}
)
item['featured_media_id'] = media.json()['id']
Include featured_media: {{ $json.featured_media_id }} in the post creation body. Test with a 2MB JPEG — n8n's default 16MB payload limit covers most needs.
Assign Categories and Tags Programmatically
Fetch existing taxonomies once via GET /wp/v2/categories?per_page=100 and /tags, cache in n8n's WorkflowStaticData, then map in Python:
cat_map = {c['name'].lower(): c['id'] for c in $static.categories}
item['categories'] = [cat_map.get(c.lower()) for c in item['category_names'] if c.lower() in cat_map]
This avoids creating duplicate terms. For new terms, POST to /categories with name and parent fields.
Implement Retry Logic and Dead Letter Queue
Add an Error Trigger node connected to a Set node that captures {{ $error.message }}, {{ $node["HTTP Request"].parameter.url }}, and {{ $json }}. Write to a Google Sheet or PostgreSQL table for manual reprocessing. Configure the HTTP Request node's "Retry On Fail" to 3 attempts with 30-second exponential backoff — handles transient 5xx errors from shared hosting.
Comparison: n8n vs. Zapier vs. Make vs. Custom Scripts
Choosing the right automation platform depends on volume, technical capacity, and budget. The table below reflects 2025 pricing and capabilities for a team publishing 100 posts/month.
n8n wins on cost at scale and Python flexibility; Zapier leads for non-technical users; Make balances both; custom scripts offer maximum control but highest maintenance.
| Feature | n8n (Self-Hosted) | Zapier Professional | Make Core | Custom Python + Cron |
|---|---|---|---|---|
| Monthly Cost (100 posts) | $0 (infrastructure only) | $73.50 | $29 | $5–$20 (VPS) |
| Python Support | Native (3.11+, any library) | Code step (limited libs) | No (JS only) | Full control |
| WordPress Nodes | Community + REST API | Official (limited actions) | Community | Manual requests |
| Data Sovereignty | Full (your server) | US cloud only | EU/US cloud | Full |
| Learning Curve | Medium (visual + code) | Low (no-code) | Medium (visual) | High (code only) |
| Error Visibility | Full logs, retry UI | Dashboard + email | Execution history | Custom logging |
Common Mistakes That Break Production Workflows
Mistake: Hardcoding Credentials in Workflow JSON
Why It Hurts: Exported workflows leak secrets; rotation requires re-deploying every workflow. Fix: Use n8n's Credentials system (Settings → Credentials → New Credential → Header Auth). Reference via {{ $credentials.credentialName.property }} in nodes. Rotate Application Passwords quarterly without touching workflow logic.
Mistake: Skipping Idempotency Keys
Why It Hurts: Cron re-runs or retries create duplicate posts. Fix: Generate a deterministic hash from source content (hashlib.sha256(title+date).hexdigest()[:12]) and store in WordPress post meta _n8n_source_hash. Before publishing, query GET /posts?meta_key=_n8n_source_hash&meta_value=HASH — skip if exists.
Mistake: Ignoring WordPress Rate Limits
Why It Hurts: Shared hosts enforce 30–60 requests/minute; bursts trigger 429 errors and IP blocks. Fix: Add a Loop Over Items node with "Batch Size: 1" and "Delay Between Batches: 2000ms". For high volume, implement token bucket in Python: time.sleep(max(0, 1.2 - (now - last_request))).
Mistake: Not Validating HTML Before Publish
Why It Hurts: Malformed HTML from source breaks Gutenberg blocks, causing editor crashes. Fix: Python's lxml.html.clean.Cleaner(safe_attrs_only=True) strips unsafe tags. Run html5lib validation: html5lib.parseFragment(content) raises on fatal errors — catch and route to dead letter queue.
Pro Tips from Production Deployments
- Use n8n's Workflow Static Data to cache taxonomy IDs and API tokens — survives restarts, reduces external calls by 90%.
- Enable n8n's Execution Data Encryption (
N8N_ENCRYPTION_KEY) — protects PII in workflow logs per GDPR Article 32. - Schedule health checks: Daily workflow calling
GET /wp-json/wp/v2/users/me— fails fast on credential expiry. - Version control workflows: Export JSON to Git via n8n CLI (
n8n export:workflow --all --output=./workflows) — enables code review and rollback. - Monitor with n8n's Prometheus metrics (
/metricsendpoint) — alert onn8n_workflow_execution_failed_totalspikes.
FAQ
What is the WordPress REST API and why does n8n use it?
The WordPress REST API (introduced in WordPress 4.7, December 2016) exposes posts, pages, media, and taxonomies as JSON endpoints. n8n uses it because it's built into core WordPress, requires no plugins, and supports full CRUD operations via standard HTTP verbs. Authentication uses Application Passwords (WordPress 5.6+) or OAuth 1.0a for third-party apps.
How does n8n's Python node differ from Zapier's Code step?
n8n's Python node runs Python 3.11+ in a sandboxed environment with any PyPI library installable via environment variables. Zapier's Code step uses a restricted Python 3.8 environment with a curated allowlist of ~50 libraries. n8n allows binary processing (images, PDFs); Zapier blocks file I/O. n8n self-hosted has no execution time limit; Zapier caps at 300 seconds.
Can I automate WooCommerce product publishing with this same workflow?
Yes. Replace /wp/v2/posts with /wc/v3/products (WooCommerce REST API, requires WooCommerce 3.5+). Authentication uses Consumer Key/Secret (Base64 encoded). Product fields map differently: name instead of title, description and short_description for content, images array for media. Categories and tags use WooCommerce endpoints /wc/v3/products/categories.
Why do my scheduled posts publish immediately instead of at the scheduled time?
WordPress's date field sets publication time in UTC. If your n8n server timezone differs, convert in Python: from datetime import datetime, timezone; item['date'] = datetime.fromisoformat(item['publish_at']).astimezone(timezone.utc).isoformat(). Also ensure status: "future" (not "publish") in the POST body. WordPress cron (wp-cron.php) must run — trigger via system cron every 5 minutes for reliability.
What happens when n8n adds AI nodes for content generation in 2025?
n8n's 2024 roadmap includes native LLM nodes (OpenAI, Anthropic, local Ollama) for content generation, summarization, and SEO optimization within workflows. This will let you replace the "Fetch Source Content" step with an AI node that generates drafts from prompts, then passes to your existing Python transform/publish pipeline. Beta access opened Q3 2024; general availability expected Q1 2025 per n8n's public changelog.
Conclusion
Automating WordPress publishing with n8n and Python transforms a manual, error-prone process into a reliable, scalable pipeline. The combination of n8n's visual workflow engine (350+ integrations, self-hosted, $0 marginal cost) and Python's unlimited data transformation power handles everything from HTML sanitization to WooCommerce product syncs. Start with the core three-node pattern — Cron → Python → WordPress REST API — then layer idempotency, media handling, and observability. Teams publishing 50+ posts monthly typically recoup setup time within two weeks. Version-control your workflows, encrypt execution data, and monitor via Prometheus to keep the pipeline running unattended for years.
- Use WordPress Application Passwords + n8n Credentials for secure, rotatable auth.
- Python transforms handle what visual nodes cannot: HTML cleaning, slug generation, SEO meta.
- Idempotency keys prevent duplicate posts on retries — essential for cron reliability.
- Self-hosted n8n eliminates per-task fees; a $20 VPS handles 10,000+ posts/month.
0 comments:
Post a Comment