
It’s been quite a while since I wrote my very first article on this WordPress blog, and I remember using tools to make editing and publishing easier. I recall one called ‘Write’ (if I’m not mistaken). Today, many years later, and as you can imagine, I now rely on AI to help me with editing and publishing — the tool we were all looking for back then 😀
If you work with AI assistants to produce technical content, connecting a Custom GPT directly to your WordPress.com site allows you to create draft posts automatically — no copy-paste, no friction.
This guide walks you through:
- ✅ Creating a WordPress.com developer app
- ✅ Getting ApiKey and/or OAuth2 tokens
- ✅ Using a clean OpenAPI 3.1.0 spec in your GPT Actions
- ✅ Uploading media and creating drafts
- ✅ Configuring your Custom GPT description and instructions
- ✅ Troubleshooting & security best practices
🛠️ Prerequisites
| Requirement | Details |
|---|---|
| WordPress.com account | Editor/Author/Admin role with publishing rights |
| Site | e.g., elguerre.com |
| Tools | curl (Linux/macOS/WSL) or PowerShell equivalent |
| Security | Ability to manage Application Passwords and developer apps |
🆕 Step 1: Create a WordPress.com Developer App
Go to developer.wordpress.com/apps and create an app. Save your client_id and client_secret.
🔑 Step 2: Generate an Application Password (for development)
Create an Application Password at wordpress.com/me/security. Copy the 24-character password and store it securely.
🔐 Use Application Passwords for non-interactive clients. Works even with 2FA enabled.
🎟️ Step 3: Get an Access Token
curl -X POST "https://public-api.wordpress.com/oauth2/token" \
-d "client_id=<CLIENT_ID>" \
-d "client_secret=<CLIENT_SECRET>" \
-d "grant_type=password" \
-d "username=<YOUR_EMAIL>" \
-d "password=<APPLICATION_PASSWORD>"
🏷️ Step 4: Verify Token and Get Site ID
# Validate token
curl "https://public-api.wordpress.com/oauth2/token-info?client_id=<CLIENT_ID>&token=<ACCESS_TOKEN>"
# List sites and IDs
curl -H "Authorization: Bearer <ACCESS_TOKEN>" \
"https://public-api.wordpress.com/rest/v1.1/me/sites"
Use either the numeric site_id or the domain (e.g., elguerre.com) in API calls.
📄 Step 5: Paste the OpenAPI 3.1.0
Before we configure the Custom GPT itself, we need to provide it with the right schema. Copy the following OpenAPI 3.1.0 specification into the Actions section of the GPT Builder. This schema exposes the WordPress.com endpoints (posts, media, categories, tags) that your GPT will later use to create and manage drafts.
{
"openapi": "3.1.0",
"info": {
"title": "WordPress.com Publishing API",
"version": "1.0.2"
},
"servers": [
{
"url": "https://public-api.wordpress.com"
}
],
"components": {
"securitySchemes": {
"bearerAuth": {
"type": "http",
"scheme": "bearer",
"bearerFormat": "JWT"
}
},
"schemas": {
"PostCreate": {
"type": "object",
"properties": {
"title": {
"type": "string"
},
"content": {
"type": "string",
"description": "HTML or Markdown"
},
"status": {
"type": "string",
"enum": [
"draft",
"publish",
"future",
"pending",
"private"
]
},
"slug": {
"type": "string"
},
"excerpt": {
"type": "string"
},
"categories": {
"type": "array",
"items": {
"type": "integer"
}
},
"tags": {
"type": "array",
"items": {
"type": "integer"
}
},
"featured_media": {
"type": "integer"
}
},
"required": [
"title",
"content",
"status"
]
},
"MediaUpload": {
"type": "object",
"properties": {
"file": {
"type": "string",
"format": "binary"
},
"title": {
"type": "string"
},
"caption": {
"type": "string"
},
"alt_text": {
"type": "string"
}
},
"required": [
"file"
]
}
}
},
"security": [
{
"bearerAuth": []
}
],
"paths": {
"/wp/v2/sites/{site}/posts": {
"post": {
"operationId": "createPost",
"summary": "Create a post (draft by default)",
"parameters": [
{
"name": "site",
"in": "path",
"required": true,
"description": "Your site domain or site ID, e.g. elguerre.com OR numeric site id",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PostCreate"
}
}
}
},
"responses": {
"201": {
"description": "Created"
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
}
}
}
},
"/wp/v2/sites/{site}/media": {
"post": {
"operationId": "uploadMedia",
"summary": "Upload media and return media id",
"parameters": [
{
"name": "site",
"in": "path",
"required": true,
"description": "Your site domain or site ID, e.g. elguerre.com OR numeric site id",
"schema": {
"type": "string"
}
}
],
"requestBody": {
"required": true,
"content": {
"multipart/form-data": {
"schema": {
"$ref": "#/components/schemas/MediaUpload"
}
}
}
},
"responses": {
"201": {
"description": "Created"
},
"400": {
"description": "Bad Request"
},
"401": {
"description": "Unauthorized"
}
}
}
},
"/wp/v2/sites/{site}/categories": {
"get": {
"operationId": "listCategories",
"summary": "List categories",
"parameters": [
{
"name": "site",
"in": "path",
"required": true,
"description": "Your site domain or site ID, e.g. elguerre.com OR numeric site id",
"schema": {
"type": "string"
}
},
{
"name": "per_page",
"in": "query",
"schema": {
"type": "integer",
"default": 100
}
},
{
"name": "search",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "Unauthorized"
}
}
}
},
"/wp/v2/sites/{site}/tags": {
"get": {
"operationId": "listTags",
"summary": "List tags",
"parameters": [
{
"name": "site",
"in": "path",
"required": true,
"description": "Your site domain or site ID, e.g. elguerre.com OR numeric site id",
"schema": {
"type": "string"
}
},
{
"name": "per_page",
"in": "query",
"schema": {
"type": "integer",
"default": 100
}
},
{
"name": "search",
"in": "query",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "OK"
},
"401": {
"description": "Unauthorized"
}
}
}
}
}
}
✅ Step 6: Smoke Tests
Run these tests in the GPT Builder or with cURL:
- List categories
- Upload media
- Create a draft post
⚙️ Configuring Your Custom GPT
Once the Actions are defined, you still need to configure the GPT correctly so that it behaves as your WordPress Tech Publisher:
- Description: Example: “You are TechBlog GPT – .NET & Cloud Writer. You draft SEO-ready technical articles about .NET, C#, ASP.NET Core, Azure, Kubernetes, Docker, DevOps, and Angular. You can publish drafts to WordPress.com using configured Actions.”
- prompt for your use case — then copy and refine that into the Description field here.
- Conversation starters: Provide simple entry points like:
- “Draft a tutorial about deploying .NET Aspire apps on AKS.”
- “Generate a blog post about GitHub Actions CI/CD for ASP.NET Core.”
- “Help me prepare a comparison between Dapr and gRPC for .NET microservices.”
- Instructions: Include workflow principles (accuracy, reproducibility, SEO, guardrails). Be explicit about using
status: draftwhen creating posts. Of course, to get the best results from your GPT, you’ll need a well-crafted prompt. Think of the description as the foundation of your assistant’s personality and workflow. If you’re not sure how to phrase it, you can even ask ChatGPT itself to propose an optimized - Actions: Paste the full OpenAPI spec, configure Bearer token auth, and test endpoints.
- Testing: Run a first conversation to generate a short test post, push it as Draft, and confirm it appears in WordPress.com dashboard.
💻 cURL toolbox
curl -X POST -H "Authorization: Bearer <ACCESS_TOKEN>" \
-F "media=@cover.png" \
"https://public-api.wordpress.com/wp/v2/sites/<SITE>/media"
curl -X POST -H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"title": "Custom GPT — .NET Tech Blog Writer & WordPress Publisher (WordPress-ready)",
"content": "<p>Draft content…</p>",
"status": "draft",
"slug": "custom-gpt-dotnet-tech-blog-writer-wordpress-ready",
"excerpt": "AI-assisted publishing to WordPress.com."
}' \
"https://public-api.wordpress.com/wp/v2/sites/<SITE>/posts"
🐞 Troubleshooting
| Error | Cause | Fix |
|---|---|---|
401 Unauthorized | Expired or invalid token | Refresh or regenerate token |
400 Bad Request | Malformed JSON | Ensure required fields |
redirect_uri mismatch | Wrong URL in OAuth app | Update app redirect URI |
🔐 Security Best Practices
- ✅ Always revoke unused tokens
- ✅ Store secrets in a password manager or secret vault
- ✅ Use least-privilege WordPress.com roles (Author/Editor)
- ✅ For production: prefer Authorization Code flow with refresh tokens
🎁 Bonus: Strengthening Your GPT Instructions
When defining the Instructions of your Custom GPT, it’s very useful to include an additional guideline that ensures your drafts are always published in the correct WordPress Gutenberg block format.
This way, your GPT will automatically generate posts that:
- Preserve the structure (headings, lists, code, tables, quotes).
- Open links in a new tab securely.
- Avoid the common problem of being published in Classic editor mode.
👉 Copy and paste the following block directly into the Instructions of your GPT Builder:
## When publishing content through WordPress.com Actions, always follow these rules:
Use raw mode for content
Send the post body (content) in raw mode.
This avoids truncation and ensures full fidelity of the article.
Use Gutenberg blocks, not Classic editor
Wrap every section in proper Gutenberg block syntax (<!-- wp:... -->).
Example for a heading:
<!-- wp:heading -->
<h2>Step 1: Create a WordPress.com Developer App</h2>
<!-- /wp:heading -->
Code blocks
Always wrap code in <!-- wp:code --> blocks:
<!-- wp:code -->
<pre class="wp-block-code"><code>curl -X POST "https://..."</code></pre>
<!-- /wp:code -->
Lists, tables, quotes
Use specific Gutenberg blocks:
- Lists → <!-- wp:list --> ... <!-- /wp:list -->
- Tables → <!-- wp:table --> ... <!-- /wp:table -->
- Quotes → <!-- wp:quote --> ... <!-- /wp:quote -->
Links
For all external links, add:
target="_blank" rel="noopener noreferrer"
Example:
<a href="https://developer.wordpress.com/apps/" target="_blank" rel="noopener noreferrer">WordPress.com Developer Apps</a>
📝 Conclusion
With this setup, your Custom GPT can securely publish draft posts into WordPress.com. You now have:
- A working OAuth2 flow with Application Passwords
- A clean OpenAPI spec for GPT Actions
- Verified media upload and draft creation
- A configured GPT with description, conversation starters, and proper guardrails
🚀 Next: run your GPT workflow, generate a tech article, and let the Action push it as a draft.
📚 References
PS: ⚠️ This article was drafted with the support of my custom GPT assistant. I’ve been fine-tuning and configuring it along the way, so this post is also part of that journey.
This article provides a clear guide on using custom GPT with OpenAPI to publish WordPress drafts. It’s a great resource for automating content creation and improving workflow efficiency. Very useful!
Me gustaLe gusta a 1 persona