wordpress-uploader
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWordPress Uploader Skill
WordPress 上传工具 Skill
Operator Context
操作上下文
This skill operates as an operator for WordPress content publishing, configuring Claude's behavior for secure, deterministic REST API operations. It wraps three Python scripts that handle post creation, media uploads, and post editing. LLMs orchestrate. Scripts execute. All WordPress operations go through scripts, never raw API calls.
本技能作为WordPress内容发布的操作器,配置Claude的行为以实现安全、确定性的REST API操作。它封装了三个Python脚本,分别处理文章创建、媒体上传和文章编辑。大语言模型(LLM)负责编排,脚本负责执行。所有WordPress操作均通过脚本完成,绝不使用原生API调用。
Hardcoded Behaviors (Always Apply)
硬编码行为(始终适用)
- CLAUDE.md Compliance: Read and follow repository CLAUDE.md before any upload
- Draft by Default: Always create posts as drafts unless explicitly told to publish
- Credential Security: Never log, display, or echo the Application Password
- HTTPS Required: Only connect to WordPress sites over HTTPS
- Script Execution Only: All WordPress API calls go through the Python scripts, never via curl or raw requests
- Show Full Output: Display complete script output; never summarize or truncate results
- CLAUDE.md 合规性:在执行任何上传操作前,阅读并遵循仓库中的CLAUDE.md
- 默认草稿模式:除非明确要求发布,否则始终将文章创建为草稿
- 凭证安全性:绝不记录、显示或回显应用密码
- 强制HTTPS:仅通过HTTPS连接WordPress站点
- 仅脚本执行:所有WordPress API调用均通过Python脚本完成,绝不使用curl或原生请求
- 显示完整输出:显示脚本的完整输出;绝不总结或截断结果
Default Behaviors (ON unless disabled)
默认行为(启用状态,除非手动禁用)
- Confirm Before Publish: Ask for user confirmation before setting status to publish
- Title Extraction: Extract title from markdown H1 if is not provided
--title - Human-Readable Mode: Use flag for all script invocations
--human - Post-Upload Verification: Confirm success by checking the returned URL and post ID
- 发布前确认:在设置发布状态前,请求用户确认
- 标题提取:如果未提供参数,则从markdown的H1标题中提取文章标题
--title - 人类可读模式:所有脚本调用均使用参数
--human - 上传后验证:通过检查返回的URL和文章ID确认操作成功
Optional Behaviors (OFF unless enabled)
可选行为(禁用状态,除非手动启用)
- Direct Publish: Publish immediately instead of draft (requires explicit user request)
- Batch Upload: Upload multiple files in sequence
- Featured Image Workflow: Upload image then attach to post in a single workflow
- 直接发布:立即发布文章而非保存为草稿(需要用户明确请求)
- 批量上传:按顺序上传多个文件
- 特色图片工作流:单次工作流中完成图片上传并关联至文章
What This Skill CAN Do
本技能可执行的操作
- Create new WordPress posts from markdown files
- Upload images and media to the WordPress media library
- Edit existing posts (title, content, status, featured image, categories, tags)
- Convert markdown to HTML automatically during upload
- Generate Gutenberg blocks for: headings, paragraphs, lists (ordered and unordered), blockquotes, images, separators, fenced code blocks, and button links
- Validate Gutenberg block HTML for structural correctness (flag)
--validate - Set post status: draft, publish, pending, private
- Assign categories and tags by NAME (script looks up IDs via REST API)
- Create tags on the fly if they don't exist in WordPress
- Auto-parse YAML frontmatter for title, categories, tags, slug, excerpt
- Delete old drafts after replacement upload (flag)
--delete - List existing drafts (flag)
--list-drafts - Retrieve existing post details for inspection before editing
- 从markdown文件创建新的WordPress文章
- 上传图片和媒体至WordPress媒体库
- 编辑现有文章(标题、内容、状态、特色图片、分类、标签)
- 上传时自动将markdown转换为HTML
- 为以下内容生成Gutenberg区块:标题、段落、列表(有序和无序列表)、引用、图片、分隔符、代码块和按钮链接
- 验证Gutenberg区块HTML的结构正确性(使用参数)
--validate - 设置文章状态:草稿、发布、待审、私有
- 通过名称分配分类和标签(脚本通过REST API查找对应ID)
- 如果WordPress中不存在指定标签,则自动创建
- 自动解析YAML前置元数据,提取标题、分类、标签、slug、摘要
- 替换上传后删除旧草稿(使用参数)
--delete - 列出所有现有草稿(使用参数)
--list-drafts - 编辑前检索现有文章详情进行检查
What This Skill CANNOT Do
本技能不可执行的操作
- Work without Application Password authentication configured in
~/.env - Connect to non-HTTPS WordPress sites
- Write or edit article prose (use blog-post-writer or anti-ai-editor)
- Upload to any CMS other than WordPress
- 未在中配置应用密码认证的情况下无法工作
~/.env - 无法连接非HTTPS的WordPress站点
- 无法撰写或编辑文稿内容(请使用blog-post-writer或anti-ai-editor)
- 无法上传至WordPress以外的任何内容管理系统(CMS)
Instructions
操作指南
Phase 1: VALIDATE ENVIRONMENT
阶段1:验证环境
Goal: Confirm credentials and target file exist before any API call.
Step 1: Check credentials
Verify contains the required WordPress variables:
~/.envbash
python3 -c "
import os
from pathlib import Path
env = Path(os.path.expanduser('~/.env')).read_text()
required = ['WORDPRESS_SITE', 'WORDPRESS_USER', 'WORDPRESS_APP_PASSWORD']
missing = [v for v in required if v + '=' not in env]
print('OK' if not missing else f'MISSING: {missing}')
"Step 2: Verify source file
If uploading content, confirm the markdown file exists and is non-empty.
Gate: All environment variables present, source file exists. Proceed only when gate passes.
目标:在进行任何API调用前,确认凭证和目标文件存在。
步骤1:检查凭证
验证文件是否包含所需的WordPress变量:
~/.envbash
python3 -c "
import os
from pathlib import Path
env = Path(os.path.expanduser('~/.env')).read_text()
required = ['WORDPRESS_SITE', 'WORDPRESS_USER', 'WORDPRESS_APP_PASSWORD']
missing = [v for v in required if v + '=' not in env]
print('OK' if not missing else f'MISSING: {missing}')
"步骤2:验证源文件
如果上传内容,确认markdown文件存在且非空。
准入条件:所有环境变量均已配置,源文件存在。仅当满足条件时才可继续。
Phase 2: UPLOAD / EXECUTE
阶段2:上传 / 执行
Goal: Run the appropriate script for the requested operation.
For new posts:
bash
python3 ~/.claude/scripts/wordpress-upload.py \
--file <path-to-markdown> \
--title "Post Title" \
--humanFor media uploads:
bash
python3 ~/.claude/scripts/wordpress-media-upload.py \
--file <path-to-image> \
--alt "Descriptive alt text" \
--humanFor editing existing posts:
bash
python3 ~/.claude/scripts/wordpress-edit-post.py \
--id <post-id> \
--human \
[--title "New Title"] \
[--content-file updated.md] \
[--featured-image <media-id>] \
[--status draft|publish|pending|private]For inspecting a post before editing:
bash
python3 ~/.claude/scripts/wordpress-edit-post.py \
--id <post-id> \
--get \
--humanGate: Script returns with a valid post/media ID. Proceed only when gate passes.
"status": "success"目标:根据请求的操作运行对应的脚本。
创建新文章:
bash
python3 ~/.claude/scripts/wordpress-upload.py \
--file <markdown文件路径> \
--title "文章标题" \
--human媒体上传:
bash
python3 ~/.claude/scripts/wordpress-media-upload.py \
--file <图片文件路径> \
--alt "描述性替代文本" \
--human编辑现有文章:
bash
python3 ~/.claude/scripts/wordpress-edit-post.py \
--id <文章ID> \
--human \
[--title "新标题"] \
[--content-file updated.md] \
[--featured-image <媒体ID>] \
[--status draft|publish|pending|private]编辑前检查文章详情:
bash
python3 ~/.claude/scripts/wordpress-edit-post.py \
--id <文章ID> \
--get \
--human准入条件:脚本返回并附带有效的文章/媒体ID。仅当满足条件时才可继续。
"status": "success"Phase 3: VERIFY
阶段3:验证
Goal: Confirm the operation succeeded and report results to the user.
Step 1: Parse script output for post_id, post_url, or media_id
Step 2: Report the result with all relevant URLs (post URL, edit URL, media URL)
Step 3: If this was a publish operation, confirm the post is accessible
Step 4: If part of a multi-step workflow (e.g., image + post + featured image), confirm all steps completed
Gate: User has received confirmation with URLs and IDs. Operation is complete.
目标:确认操作成功并向用户报告结果。
步骤1:解析脚本输出,获取文章ID、文章URL或媒体ID
步骤2:向用户报告结果,包含所有相关URL(文章URL、编辑URL、媒体URL)
步骤3:如果是发布操作,确认文章可正常访问
步骤4:如果是多步骤工作流(如图片上传+文章创建+特色图片关联),确认所有步骤均已完成
准入条件:用户已收到包含URL和ID的确认信息。操作完成。
Phase 4: POST-UPLOAD (Optional)
阶段4:上传后操作(可选)
Goal: Handle multi-step workflows that combine operations.
Full article with featured image workflow:
bash
undefined目标:处理组合多个操作的多步骤工作流。
完整文章+特色图片工作流:
bash
undefined1. Upload the featured image
1. 上传特色图片
python3 ~/.claude/scripts/wordpress-media-upload.py
--file images/photo.jpg
--alt "Description"
--human
--file images/photo.jpg
--alt "Description"
--human
python3 ~/.claude/scripts/wordpress-media-upload.py
--file images/photo.jpg
--alt "描述文本"
--human
--file images/photo.jpg
--alt "描述文本"
--human
Note the media_id from output
记录输出中的media_id
2. Create the post (frontmatter auto-parsed for title, categories, tags, slug)
2. 创建文章(自动解析YAML前置元数据中的标题、分类、标签、slug)
python3 ~/.claude/scripts/wordpress-upload.py
--file content/article.md
--category "News"
--tag "Example Tag" --tag "Example Event"
--status draft
--human
--file content/article.md
--category "News"
--tag "Example Tag" --tag "Example Event"
--status draft
--human
python3 ~/.claude/scripts/wordpress-upload.py
--file content/article.md
--category "新闻"
--tag "示例标签" --tag "示例活动"
--status draft
--human
--file content/article.md
--category "新闻"
--tag "示例标签" --tag "示例活动"
--status draft
--human
Note the post_id from output
记录输出中的post_id
3. Attach featured image to post
3. 将特色图片关联至文章
python3 ~/.claude/scripts/wordpress-edit-post.py
--id <post_id>
--featured-image <media_id>
--human
--id <post_id>
--featured-image <media_id>
--human
**Draft cleanup workflow (delete old drafts after replacement upload):**
```bashpython3 ~/.claude/scripts/wordpress-edit-post.py
--id <post_id>
--featured-image <media_id>
--human
--id <post_id>
--featured-image <media_id>
--human
**草稿清理工作流(替换上传后删除旧草稿):**
```bash1. List existing drafts to find old version
1. 列出所有现有草稿以找到旧版本
python3 ~/.claude/scripts/wordpress-edit-post.py --list-drafts --human
python3 ~/.claude/scripts/wordpress-edit-post.py --list-drafts --human
2. Delete old draft
2. 删除旧草稿
python3 ~/.claude/scripts/wordpress-edit-post.py
--id <old_post_id>
--delete
--human
--id <old_post_id>
--delete
--human
**Important**: Always delete old drafts after uploading a replacement. Multiple drafts of the same article accumulate in WordPress and cause confusion.
---python3 ~/.claude/scripts/wordpress-edit-post.py
--id <旧文章ID>
--delete
--human
--id <旧文章ID>
--delete
--human
**重要提示**:替换上传后请务必删除旧草稿。同一文章的多个草稿会在WordPress中堆积,造成混淆。
---Script Reference
脚本参考
wordpress-upload.py (Create Posts)
wordpress-upload.py(创建文章)
| Flag | Short | Description |
|---|---|---|
| | Path to markdown file (required). Auto-parses YAML frontmatter for title, categories, tags, slug, excerpt. |
| | Post title (extracted from YAML frontmatter or H1 if omitted) |
| | Post status: draft, publish, pending, private |
| Category by NAME, e.g. | |
| Tag by NAME, e.g. | |
| Author user ID | |
| Convert to Gutenberg HTML, validate block structure, print results as JSON, and exit without uploading | |
| Human-readable output |
WordPress categories: Look up your site's category IDs via the REST API or wp-admin. Use category names with and the script resolves IDs automatically.
--categoryYAML frontmatter: The upload script auto-strips frontmatter from the article body. No YAML should appear in the published content. If you see or key-value pairs in the published article, the upload failed to strip it.
---| 参数 | 简写 | 描述 |
|---|---|---|
| | markdown文件路径(必填)。自动解析YAML前置元数据,提取标题、分类、标签、slug、摘要。 |
| | 文章标题(若省略则从YAML前置元数据或H1标题中提取) |
| | 文章状态:draft、publish、pending、private |
| 分类名称,例如 | |
| 标签名称,例如 | |
| 作者用户ID | |
| 将markdown转换为Gutenberg HTML,验证区块结构,以JSON格式打印结果,且不执行上传操作 | |
| 人类可读格式输出 |
WordPress分类:可通过REST API或wp-admin查看站点的分类ID。使用参数指定分类名称,脚本会自动解析对应的ID。
--categoryYAML前置元数据:上传脚本会自动从文章正文中移除前置元数据。发布的内容中不应出现YAML。如果在发布的文章中看到或键值对,说明上传脚本未能成功移除前置元数据。
---wordpress-media-upload.py (Upload Media)
wordpress-media-upload.py(上传媒体)
| Flag | Short | Description |
|---|---|---|
| | Path to media file (required) |
| | Media title (defaults to filename) |
| Alt text for accessibility | |
| Caption for the media | |
| Description for the media | |
| Human-readable output |
| 参数 | 简写 | 描述 |
|---|---|---|
| | 媒体文件路径(必填) |
| | 媒体标题(默认使用文件名) |
| 用于无障碍访问的替代文本 | |
| 媒体说明文字 | |
| 媒体描述 | |
| 人类可读格式输出 |
wordpress-edit-post.py (Edit Posts)
wordpress-edit-post.py(编辑文章)
| Flag | Short | Description |
|---|---|---|
| | Post ID to edit (required, except with |
| Fetch post info without editing | |
| | New post title |
| New content as HTML string | |
| New content from markdown file | |
| | New status: draft, publish, pending, private |
| Featured image media ID. Use to attach uploaded image to post. | |
| Category by NAME (replaces existing) | |
| Tag by NAME (replaces existing) | |
| Post excerpt | |
| Delete the specified post (use to clean up old drafts after replacement upload) | |
| List all draft posts (no | |
| Human-readable output |
| 参数 | 简写 | 描述 |
|---|---|---|
| | 待编辑的文章ID(必填,使用 |
| 获取文章信息但不进行编辑 | |
| | 新文章标题 |
| 新内容(HTML字符串格式) | |
| 来自markdown文件的新内容 | |
| | 新状态:draft、publish、pending、private |
| 特色图片的媒体ID。用于将已上传的图片关联至文章。 | |
| 分类名称(替换现有分类) | |
| 标签名称(替换现有标签) | |
| 文章摘要 | |
| 删除指定文章(用于替换上传后清理旧草稿) | |
| 列出所有草稿文章(无需 | |
| 人类可读格式输出 |
Content Formatting
内容格式规范
Do NOT include title or author in the article body. WordPress manages these as metadata. Duplicating them in content creates inconsistency when editing in wp-admin.
请勿在文章正文中包含标题或作者信息。WordPress将这些信息作为元数据管理。在内容中重复这些信息会导致在wp-admin中编辑时出现不一致。
Supported Gutenberg Block Types
支持的Gutenberg区块类型
The upload script automatically converts standard markdown to these Gutenberg block types:
| Markdown Syntax | Gutenberg Block | Notes |
|---|---|---|
| | H2-H4 supported; H1 becomes post title |
| Regular text | | Inline bold, italic, links supported |
| | Unordered list |
| | Ordered list with |
| | Blockquote |
| | Standalone images |
| | Horizontal rule |
| | Fenced code block with optional language |
| | Button link |
上传脚本会自动将标准markdown转换为以下Gutenberg区块类型:
| Markdown语法 | Gutenberg区块 | 说明 |
|---|---|---|
| | 支持H2-H4;H1会作为文章标题 |
| 普通文本 | | 支持加粗、斜体、链接等行内格式 |
| | 无序列表 |
| | 使用 |
| | 引用块 |
| | 独立图片 |
| | 水平线 |
| | 带可选语言标识的代码块 |
| | 按钮链接 |
Code Blocks
代码块
Fenced code blocks with optional language hints are converted to blocks:
wp:codemarkdown
```python
def hello():
print("Hello, World!")
```带可选语言标识的代码块会被转换为区块:
wp:codemarkdown
```python
def hello():
print("Hello, World!")
```Button Links
按钮链接
Use the attribute to create WordPress button blocks:
{.wp-button}markdown
[Download Now](https://example.com/download){.wp-button}使用属性创建WordPress按钮区块:
{.wp-button}markdown
[立即下载](https://example.com/download){.wp-button}Block Validation
区块验证
Use to check Gutenberg HTML structure without uploading:
--validatebash
python3 ~/.claude/scripts/wordpress-upload.py --file article.md --validateOutput is JSON: or .
{"status": "valid", "block_count": N}{"status": "invalid", "errors": [...]}For Gutenberg editor compatibility, you can also use raw WordPress block comments between sections:
markdown
Your opening paragraph here.
<!-- wp:separator -->
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<!-- /wp:separator -->
<!-- wp:heading -->使用参数检查Gutenberg HTML结构而不执行上传:
--validatebash
python3 ~/.claude/scripts/wordpress-upload.py --file article.md --validate输出为JSON格式: 或 。
{"status": "valid", "block_count": N}{"status": "invalid", "errors": [...]}为了兼容Gutenberg编辑器,你也可以在章节之间使用原生WordPress区块注释:
markdown
你的开篇段落。
<!-- wp:separator -->
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<!-- /wp:separator -->
<!-- wp:heading -->Section Title
章节标题
<!-- /wp:heading -->
Section content here.
---<!-- /wp:heading -->
章节内容。
---Error Handling
错误处理
Error: "WORDPRESS_SITE not set" or Missing Credentials
错误:"WORDPRESS_SITE not set" 或凭证缺失
Cause: Environment variables not configured in
Solution:
~/.env- Verify exists in the home directory
~/.env - Check it contains WORDPRESS_SITE, WORDPRESS_USER, and WORDPRESS_APP_PASSWORD
- Ensure no extra whitespace or quoting around values
原因:文件中未配置环境变量
解决方案:
~/.env- 确认文件存在于用户主目录
~/.env - 检查文件中是否包含WORDPRESS_SITE、WORDPRESS_USER和WORDPRESS_APP_PASSWORD
- 确保变量值前后没有多余空格或引号
Error: "401 Unauthorized"
错误:"401 Unauthorized"
Cause: Invalid or expired Application Password
Solution:
- Log into WordPress admin (wp-admin) > Users > Profile
- Revoke the old Application Password
- Generate a new one and update
~/.env - Verify the username matches the WordPress account exactly
原因:应用密码无效或已过期
解决方案:
- 登录WordPress后台(wp-admin)> 用户 > 个人资料
- 撤销旧的应用密码
- 生成新的应用密码并更新文件
~/.env - 确认用户名与WordPress账户完全匹配
Error: "403 Forbidden"
错误:"403 Forbidden"
Cause: WordPress user lacks required capability (e.g., publish_posts, upload_files)
Solution:
- Confirm the user has Editor or Administrator role
- Check if a security plugin is blocking REST API access
- Verify the site allows Application Password authentication
原因:WordPress用户缺少必要权限(如publish_posts、upload_files)
解决方案:
- 确认用户拥有编辑者或管理员角色
- 检查是否有安全插件阻止REST API访问
- 确认站点允许应用密码认证
Error: "File not found" or Empty Content
错误:"File not found" 或内容为空
Cause: Incorrect file path or markdown file is empty
Solution:
- Verify the file path with
ls -la <path> - Confirm the file has content (not zero bytes)
- Check for typos in the path, especially the content/ directory structure
原因:文件路径错误或markdown文件为空
解决方案:
- 使用验证文件路径
ls -la <路径> - 确认文件非空(大小不为0字节)
- 检查路径中的拼写错误,尤其是content/目录结构
Anti-Patterns
反模式
Anti-Pattern 1: Publishing Without Confirmation
反模式1:未确认就发布
What it looks like: Setting without asking the user first
Why wrong: Published posts are immediately visible to readers. Mistakes are public.
Do instead: Always create as draft. Ask for explicit confirmation before publishing.
--status publish表现:未询问用户就设置参数
危害:已发布的文章会立即对读者可见,错误会公开暴露
正确做法:始终将文章保存为草稿。发布前需获得用户明确确认。
--status publishAnti-Pattern 2: Skipping Environment Validation
反模式2:跳过环境验证
What it looks like: Running the upload script without checking credentials first
Why wrong: Produces confusing errors. Wastes time debugging API failures that are just config issues.
Do instead: Complete Phase 1 validation before any script execution.
表现:未检查凭证就直接运行上传脚本
危害:产生难以理解的错误,浪费时间调试本可避免的配置问题
正确做法:执行任何脚本前完成阶段1的验证步骤
Anti-Pattern 3: Raw API Calls Instead of Scripts
反模式3:使用原生API调用而非脚本
What it looks like: Using curl or Python requests directly against the WordPress REST API
Why wrong: Bypasses credential handling, error formatting, and markdown conversion built into the scripts.
Do instead: Always use the three provided Python scripts for all WordPress operations.
表现:直接使用curl或Python requests调用WordPress REST API
危害:绕过了脚本内置的凭证处理、错误格式化和markdown转换功能
正确做法:所有WordPress操作均使用提供的三个Python脚本
Anti-Pattern 4: Including Title in Article Body
反模式4:在文章正文中包含标题
What it looks like: Markdown file starts with and is also set
Why wrong: Creates duplicate title in WordPress. The H1 renders inside the post body AND as the post title.
Do instead: Either use flag OR include H1 in markdown, never both.
# Article Title--title--title表现:markdown文件以开头,同时设置了参数
危害:在WordPress中创建重复标题。H1会同时显示在文章正文中和作为文章标题
正确做法:要么使用参数,要么在markdown中包含H1标题,二者不可同时使用
# 文章标题--title--titleReferences
参考资料
This skill uses these shared patterns:
- Anti-Rationalization - Prevents shortcut rationalizations
- Verification Checklist - Pre-completion checks
本技能使用以下共享模式:
- 反合理化 - 防止寻找捷径的合理化借口
- 验证清单 - 完成前的检查步骤
Domain-Specific Anti-Rationalization
领域特定反合理化
| Rationalization | Why It's Wrong | Required Action |
|---|---|---|
| "Credentials are probably fine" | Config issues cause most upload failures | Run Phase 1 validation |
| "Draft is close enough to publish" | Draft and publish are different states | Confirm desired status explicitly |
| "I'll just curl the API directly" | Scripts handle auth, conversion, errors | Use the provided scripts |
| "Title in body is fine" | Creates duplicate rendering in WordPress | Use --title flag OR H1, not both |
| 合理化借口 | 危害 | 要求操作 |
|---|---|---|
| "凭证应该没问题" | 配置问题是导致上传失败的主要原因 | 执行阶段1的验证步骤 |
| "草稿和发布差不多" | 草稿和发布是不同的状态 | 明确确认所需状态 |
| "我直接用curl调用API就行" | 脚本处理认证、转换和错误处理 | 使用提供的脚本 |
| "正文中包含标题没关系" | 在WordPress中造成重复显示 | 使用--title参数或H1标题,二者选其一 |
Script Files
脚本文件
- : Create new posts from markdown
scripts/wordpress-upload.py - : Upload images/media to library
scripts/wordpress-media-upload.py - : Edit existing posts (title, content, status, featured image)
scripts/wordpress-edit-post.py
- :从markdown文件创建新文章
scripts/wordpress-upload.py - :上传图片/媒体至媒体库
scripts/wordpress-media-upload.py - :编辑现有文章(标题、内容、状态、特色图片)
scripts/wordpress-edit-post.py