mcpField
W
wordpress

wordpress

github.com/acedatacloud营销与增长1772 次安装今天更新
代码仓库

关于 wordpress

通过 `curl` 和 `jq` 调用 WordPress REST API 管理内容的 skill。它涵盖连接检查、文章与媒体操作,并提供凭据、重复文章和发布安全措施。

主要功能

  1. 01验证站点认证与用户角色
  2. 02创建、更新、定时发布和列出文章
  3. 03管理分类、标签与媒体
  4. 04发布前检查重复文章
  5. 05处理 HTML 内容与 SEO 字段

适用场景

  1. 01创建草稿并返回编辑链接
  2. 02更新或定时发布现有文章
  3. 03上传特色图片并设置 SEO 字段
  4. 04查看文章和分类标签 ID

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/acedatacloud/skills --skill wordpress

安装后在 Claude Code 中输入/wordpress确认已加载。

详细介绍

使用 curl + jq 操作 WordPress REST API(/wp-json/wp/v2)。

用户自托管的 WordPress 凭据会作为环境变量注入:

  • $WORDPRESS_SITE_URL — 站点根地址,例如 https://blog.example.com
  • $WORDPRESS_USERNAME — WordPress 登录用户名
  • $WORDPRESS_APP_PASSWORD — 应用程序密码(WP 5.6+ 核心功能),不是登录密码。请将其视为机密——切勿记录或回显。

通过 HTTPS 使用 HTTP Basic(username:app_password)进行身份验证。先设置一次可复用的基础配置,之后每次调用都复用它:

# Normalize the site URL (strip a trailing slash) and build the API base.
SITE="${WORDPRESS_SITE_URL%/}"
API="$SITE/wp-json/wp/v2"
# -u sends HTTP Basic auth; --fail-with-body surfaces the JSON error body on 4xx/5xx.
WP=(curl -sS --fail-with-body -u "$WORDPRESS_USERNAME:$WORDPRESS_APP_PASSWORD")

不要在这些调用中添加 -L/--location。 重定向通常意味着站点 URL 有误。若重定向跨越主机或协议(例如 http→https、根域名→www),curl 会移除 Authorization 标头——这里恰好就可能出现这种情况——因此后续请求会以未通过身份验证的状态执行,并可能返回站点的 HTML 页面和 HTTP 200:看起来像是成功了,实际上什么也没写入。请改正 URL(参见下方 /wp-json 的注意事项)。

错误会以 {"code": "...", "message": "...", "data": {"status": 401}} 的形式返回——原样显示 message。常见代码:

HTTP含义告知用户的内容
401incorrect_password / Basic 身份验证错误应用程序密码错误或已撤销 → 重新生成密码并重新连接 WordPress 连接器
401纯 http:// 站点上的 rest_not_logged_in未启用 HTTPS 时会禁用应用程序密码 → 用户必须启用 HTTPS
403rest_cannot_create / 权限不足用户角色无法发布;需要 Author/Editor/Admin,或者站点已禁用应用程序密码
404rest_no_routeREST API 已禁用,或安全插件阻止了 /wp-json → 用户必须重新启用它
400rest_invalid_param字段无效(例如未知的分类 ID)→ 修正后重试
500rest_upload_sideload_errorWeb 服务器无法写入 wp-content/uploads → 用户必须修正目录权限

content 是 HTML,不是 Markdown。 原始 Markdown 会原样显示。未安装 pandoc——请使用 Python 的 markdown 包进行转换(沙盒中已预装)。如果导入失败,请先运行 pip install markdown,然后:

HTML=$(python3 -c "
import sys, markdown
print(markdown.markdown(sys.stdin.read(), extensions=['fenced_code','tables']))
" <<'MD'
## 标题

正文 **粗体**
MD
)

步骤 0 — 先验证连接

"${WP[@]}" "$API/users/me?context=edit" | jq '{id, name, slug, roles}'

必须使用 context=edit——否则 WP 会完全省略 roles/capabilities,因此无法判断账户是否有权发布。若返回 200,且 roles 包含 administrator、editor 或 author,则表示站点 URL、用户名、应用程序密码以及发布权限均已确认。如果此步骤失败,请停止并展示错误——不要尝试写入。

发布文章或保存为草稿

发布会公开显示且很难撤销——使用 status=publish 前,请先与用户确认。 默认使用 status=draft,并提供编辑链接。

jq -n --arg t "国内如何稳定调用 Claude API" \
      --arg c "<p>正文 HTML……</p>" \
      --arg s "draft" \
  '{title:$t, content:$c, status:$s}' \
| "${WP[@]}" -X POST "$API/posts" \
    -H "Content-Type: application/json" -d @- \
| jq '{id, status, link, edit: "\(env.WORDPRESS_SITE_URL)/wp-admin/post.php?action=edit&post=\(.id)"}'

添加分类 / 标签 / 摘要(ID 来自下方的端点):

jq -n --arg t "标题" --arg c "<p>正文</p>" --arg e "一句话摘要" \
  '{title:$t, content:$c, excerpt:$e, status:"draft",
    categories:[5], tags:[12,34]}' \
| "${WP[@]}" -X POST "$API/posts" -H "Content-Type: application/json" -d @- \
| jq '{id, status, link}'
  • 发布现有草稿:请求体为 {"status":"publish"},调用 POST $API/posts/<id>。
  • 更新文章:调用 POST $API/posts/<id>,传入任意字段子集(WP REST 更新使用 POST,而不是 PUT)。
  • 删除(移至回收站)文章:"${WP[@]}" -X DELETE "$API/posts/<id>"。
  • 定时发布文章:{"status":"future","date_gmt":"2030-01-01T00:00:00"}(UTC,不带结尾的 Z)。

真正重要的 SEO 字段

WordPress 核心会自行输出 <link rel="canonical">,但完全不会提供 meta description 标签——只有网站运行了 SEO 插件(Yoast、Rank Math、SEOPress)或会渲染此标签的主题时,才会出现该标签。这些插件和主题会使用文章的 excerpt,因此设置 excerpt 才能生成优质描述;在未安装插件或主题的基础 WordPress 中,设置它不会起任何作用。发布 SEO 文章时,务必设置:

字段原因
slug固定链接。请明确设置为简短的 ASCII 关键词短语——否则,包含 CJK 字符的标题会变成百分号编码的 URL。
excerptSEO 插件的 meta description 和列表页摘要的来源。请写一个句子。
categories / tags用于内部链接和主题聚类。
featured_media社交媒体/OG 卡片图片。
媒体的 alt_text图片 SEO 和无障碍访问。请在媒体对象上设置(见下文)。
jq -n --arg s "claude-api-guide" --argjson c 3 --argjson m 9 \
  '{title:"如何稳定调用 Claude API:完整对接指南",
    slug:$s,
    content:"<h2>小标题</h2><p>正文</p>",
    excerpt:"一句话摘要,用于 meta description。",
    status:"publish", categories:[$c], featured_media:$m}' \
| "${WP[@]}" -X POST "$API/posts" -H "Content-Type: application/json" -d @- \
| jq '{id, status, slug, link}'

发布前:检查是否有重复内容

**WordPress 不会拒绝重复的 slug——而是会静默追加 -2,**因此,无人值守或定时运行时,如果重复发布同一篇文章,就会不断产生彼此竞争搜索排名的近似 URL。请务必预先检查:

SLUG="claude-api-guide"
# Fail CLOSED at BOTH steps: a failed request, or a 200 that isn't a JSON array
# (HTML from a redirect/permalink issue, or an error object), must abort — never
# fall through and create the duplicate this check exists to prevent.
if ! LOOKUP=$("${WP[@]}" "$API/posts?slug=$SLUG&status=publish,draft,future&_fields=id,link"); then
  echo "duplicate check failed (request error) — aborting" >&2; exit 1
fi
if ! EXISTING=$(printf '%s' "$LOOKUP" | jq -er 'if type=="array" then (.[0].id // "") else error("not a JSON array") end'); then
  echo "duplicate check failed (unexpected response) — aborting" >&2; exit 1
fi
if [ -n "$EXISTING" ]; then
  echo "already exists as post $EXISTING — update it instead of creating a new one"
  # update:  "${WP[@]}" -X POST "$API/posts/$EXISTING" ...
fi

优先更新现有文章,而不是创建近似重复内容。这一点在定时任务中尤为重要,因为届时没有人查看输出。

列出/读取文章

"${WP[@]}" "$API/posts?per_page=10&status=publish,draft&_fields=id,title,status,link,date" \
  | jq '.[] | {id, title: .title.rendered, status, link, date}'

使用 &page=2 分页;总页数位于 X-WP-TotalPages 响应头中(添加 -D - 可查看响应头)。

分类和标签(获取或创建 ID)

# List existing
"${WP[@]}" "$API/categories?per_page=100&_fields=id,name,slug" | jq '.[] | {id, name}'
"${WP[@]}" "$API/tags?per_page=100&_fields=id,name,slug"       | jq '.[] | {id, name}'

# Create one (returns its id)
jq -n --arg n "AI 教程" '{name:$n}' \
| "${WP[@]}" -X POST "$API/categories" -H "Content-Type: application/json" -d @- \
| jq '{id, name}'

如果要创建的术语已存在,会返回 {"code":"term_exists", ... "data":{"status":400,"term_id":<id>}}——请复用 .data.term_id,不要因此失败。

上传媒体(特色图片/正文图片)

FILE="./cover.png"
NAME="$(basename "$FILE")"
MEDIA_ID=$("${WP[@]}" -X POST "$API/media" \
  -H "Content-Disposition: attachment; filename=\"$NAME\"" \
  -H "Content-Type: image/png" \
  --data-binary @"$FILE" | jq -r '.id')
echo "media id=$MEDIA_ID"

# Set alt text (image SEO + accessibility) — a separate call on the media object.
jq -n --arg a "Claude API 架构图" '{alt_text:$a}' \
| "${WP[@]}" -X POST "$API/media/$MEDIA_ID" \
    -H "Content-Type: application/json" -d @- | jq '{id, alt_text}'

# Attach as the post's featured image:
#   add  "featured_media": <MEDIA_ID>  to the post body.

注意事项

  • Application Passwords 实际上必须使用 HTTPS。 WP 通过 wp_is_application_passwords_available() 控制其可用性;在使用纯 http:// 的生产网站上,该函数会返回 false → 已认证的调用会因 rest_not_logged_in (401) 而失败。(此限制可通过筛选器配置;当 WP_ENVIRONMENT_TYPE 为 local 时也会绕过,因此开发环境可能仍然可用——但用户连接的任何实际网站都必须支持 HTTPS。)

  • $WORDPRESS_SITE_URL 必须与网站配置的地址完全一致。 如果两者不同(缺少或多了 www,或者 http 与 https 不一致),WP 会将 /wp-json/... 请求重定向(301)到规范主机。请修正连接器中保存的网站 URL,不要用 -L 来掩盖问题。

  • 安全插件/主机可能会屏蔽 /wp-json(Wordfence、“disable REST API” 插件、某些托管主机)。症状包括:返回 404 rest_no_route,或返回 HTML 登录页面而不是 JSON。用户必须允许访问 REST API。

  • 可能未启用固定链接美化。 如果 /wp-json/wp/v2/... 返回的是网站 HTML 而不是 JSON,说明网站使用的是普通固定链接——请改用始终可用的查询形式:$SITE/?rest_route=/wp/v2/posts。

  • Application Password 中包含空格(例如 abcd efgh ijkl mnop)。 请保留空格——curl -u 可以正常处理;不要删除空格。

  • 绝不要静默发布。 即使用户说“发出去”,也应优先创建草稿并返回 wp-admin 编辑链接,除非用户明确要求正式发布。(在无人值守的定时任务中,用户已预先授权执行,因此预期会直接发布——但仍须检查是否有重复内容。)

记录输出

成功发布并获得实际结果 URL 后,请调用内置 publish_artifact 工具一次,以便用户在我的输出中跟踪此交付内容:

publish_artifact(kind="article", channel="wordpress", title="<title>", url="<the REAL returned URL>", status="delivered")

请使用实际返回的 URL——绝不要伪造。每个已发布项目调用一次,且仅在确认交付后调用;如果发布失败,请跳过(或使用 status="failed")。 请参阅 _shared/artifacts.md。

评论

支持 Markdown