setup-cms

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

/setup-cms

/setup-cms

Guide the user through connecting their CMS to toprank's SEO analysis tools.
Once configured,
/seo-analysis
automatically pulls published content from the CMS and cross-references it against Google Search Console data — finding invisible pages, content gaps, stale articles, and missing SEO fields.

引导用户将其CMS连接到toprank的SEO分析工具。
配置完成后,
/seo-analysis
会自动从CMS拉取已发布内容,并与Google Search Console数据进行交叉引用——找出隐形页面、内容缺口、过时文章和缺失的SEO字段。

Step 0 — Setup

步骤0 — 准备工作

Read and follow
../shared/preamble.md
— it locates the SEO scripts directory. Use
$SKILL_SCRIPTS
from the preamble for all script calls below.
阅读并遵循
../shared/preamble.md
中的说明——它会定位SEO脚本目录。以下所有脚本调用均使用前言中定义的
$SKILL_SCRIPTS

Step 1 — Detect existing CMS configuration

步骤1 — 检测现有CMS配置

bash
CMS_TYPE=$(python3 "$SKILL_SCRIPTS/cms_detect.py" 2>/dev/null)
CMS_STATUS=$?
echo "CMS_TYPE=$CMS_TYPE  EXIT=$CMS_STATUS"
  • CMS_STATUS=0
    → a CMS is already configured (
    $CMS_TYPE
    is the name). Show the user: "You already have [$CMS_TYPE] connected. Would you like to reconfigure it, or switch to a different CMS?" Wait for their reply. If they say reconfigure/switch, continue to Step 2. If they say test or verify, jump to Step 5 (skip to connection test).
  • CMS_STATUS=2
    → nothing configured yet. Continue to Step 2.

bash
CMS_TYPE=$(python3 "$SKILL_SCRIPTS/cms_detect.py" 2>/dev/null)
CMS_STATUS=$?
echo "CMS_TYPE=$CMS_TYPE  EXIT=$CMS_STATUS"
  • CMS_STATUS=0
    → 已配置CMS(
    $CMS_TYPE
    为对应名称)。 告知用户:“您已连接**[$CMS_TYPE]**。是否需要重新配置,或切换到其他CMS?” 等待用户回复。如果用户选择重新配置/切换,继续步骤2。 如果用户选择测试或验证,跳至步骤5(跳过至连接测试)。
  • CMS_STATUS=2
    → 尚未配置任何CMS。继续步骤2。

Step 2 — Choose a CMS

步骤2 — 选择CMS

Ask the user:
"Which CMS are you connecting? I support:
  1. WordPress — self-hosted or WordPress.com (uses REST API + Application Password)
  2. Strapi — v4 or v5, self-hosted (uses API Token)
  3. Contentful — cloud headless CMS (uses Delivery API key)
  4. Ghost — Ghost.org or self-hosted (uses Content API key)
Reply with the name or number."
Wait for their answer. Map to:
wordpress
,
strapi
,
contentful
,
ghost
.

询问用户:
“您要连接哪款CMS?我支持:
  1. WordPress — 自托管或WordPress.com(使用REST API + 应用密码)
  2. Strapi — v4或v5版本,自托管(使用API令牌)
  3. Contentful — 云原生无头CMS(使用Delivery API密钥)
  4. Ghost — Ghost.org或自托管(使用Content API密钥)
请回复名称或编号。”
等待用户回答,将其映射为:
wordpress
strapi
contentful
ghost

Step 3 — Credential setup by CMS

步骤3 — 按CMS类型设置凭据

Jump to the sub-section for the chosen CMS.

跳至所选CMS对应的子章节。

3A — WordPress

3A — WordPress

WordPress uses the built-in Application Passwords feature (introduced in WP 5.6). This is the safest way to grant API access — it never exposes your main password and can be revoked at any time.
Tell the user:
"I need three things to connect WordPress:
  1. Your WordPress URL (e.g.
    https://myblog.com
    )
  2. Your WordPress username (the one you log in with)
  3. An Application Password — create one in: WordPress Admin → Users → Profile → scroll to Application Passwords → enter a name like "toprank" → click Add New → copy the generated password
Paste each value when ready."
Collect values one at a time:
  1. Ask for
    WP_URL
    → validate it starts with
    http://
    or
    https://
  2. Ask for
    WP_USERNAME
  3. Ask for
    WP_APP_PASSWORD
  4. Ask for
    WP_CONTENT_TYPE
    :
    "What content type should I analyze? Common values:
    posts
    ,
    pages
    . Press Enter to use
    posts
    (default), or enter a custom post type slug."
Once all four are collected, continue to Step 4 (test connection).
Write to
.env.local
:
WP_URL=<value>
WP_USERNAME=<value>
WP_APP_PASSWORD=<value>
WP_CONTENT_TYPE=<value or posts>

WordPress使用内置的**应用密码(Application Passwords)**功能(WP 5.6版本引入)。 这是授予API访问权限最安全的方式——它绝不会暴露您的主密码,且可随时撤销。
告知用户:
“连接WordPress需要三项信息:
  1. 您的WordPress网址(例如
    https://myblog.com
  2. 您的WordPress用户名(登录时使用的用户名)
  3. 应用密码 — 在以下位置创建: WordPress后台 → 用户 → 个人资料 → 滚动至应用密码 → 输入名称如“toprank” → 点击添加新密码 → 复制生成的密码
准备好后粘贴每个值。”
依次收集以下值:
  1. 请求
    WP_URL
    → 验证其以
    http://
    https://
    开头
  2. 请求
    WP_USERNAME
  3. 请求
    WP_APP_PASSWORD
  4. 请求
    WP_CONTENT_TYPE
    “我应该分析哪种内容类型?常见值:
    posts
    pages
    。 按回车键使用默认值
    posts
    ,或输入自定义文章类型别名。”
收集完所有四项信息后,继续步骤4(测试连接)。
将内容写入
.env.local
WP_URL=<value>
WP_USERNAME=<value>
WP_APP_PASSWORD=<value>
WP_CONTENT_TYPE=<value or posts>

3B — Strapi

3B — Strapi

Tell the user:
"I need two things to connect Strapi:
  1. Your Strapi URL (e.g.
    https://cms.example.com
    )
  2. A Full-access API Token — create one in: Strapi Admin → Settings → Global settings → API Tokens → Create new API Token → Type: Full access → copy the token
Optionally:
  • Content type — the plural API ID of your content collection (default:
    articles
    ). Find it in: Content-Type Builder → [your type] → API ID (plural)
  • Strapi version
    4
    or
    5
    (auto-detected if omitted)
Paste each value when ready."
Collect:
  1. STRAPI_URL
  2. STRAPI_API_KEY
  3. STRAPI_CONTENT_TYPE
    (optional, default:
    articles
    )
  4. STRAPI_VERSION
    (optional)
Write to
.env.local
:
STRAPI_URL=<value>
STRAPI_API_KEY=<value>
STRAPI_CONTENT_TYPE=<value or articles>
Include
STRAPI_VERSION=<value>
only if the user specified it.

告知用户:
“连接Strapi需要两项信息:
  1. 您的Strapi网址(例如
    https://cms.example.com
  2. 全权限API令牌 — 在以下位置创建: Strapi后台 → 设置 → 全局设置 → API令牌 → 创建新API令牌 → 类型:全权限 → 复制令牌
可选信息:
  • 内容类型 — 您的内容集合的复数API ID(默认值:
    articles
    )。 在以下位置查找:内容类型构建器 → [您的类型] → API ID(复数)
  • Strapi版本
    4
    5
    (若省略则自动检测)
准备好后粘贴每个值。”
收集:
  1. STRAPI_URL
  2. STRAPI_API_KEY
  3. STRAPI_CONTENT_TYPE
    (可选,默认值:
    articles
  4. STRAPI_VERSION
    (可选)
将内容写入
.env.local
STRAPI_URL=<value>
STRAPI_API_KEY=<value>
STRAPI_CONTENT_TYPE=<value or articles>
仅当用户指定时才添加
STRAPI_VERSION=<value>

3C — Contentful

3C — Contentful

Tell the user:
"I need three things to connect Contentful:
  1. Space ID — find it in: Contentful → Settings → General Settings → Space ID
  2. Content Delivery API token — find it in: Settings → API Keys → [your key] → Content Delivery API - access token (If no key exists, create one under Settings → API Keys → Add API Key)
  3. Content type ID — the API identifier for your content type. Find it in: Content model → [your type] → API Identifier
Optionally:
  • Environment (default:
    master
    )
Paste each value when ready."
Collect:
  1. CONTENTFUL_SPACE_ID
  2. CONTENTFUL_DELIVERY_TOKEN
  3. CONTENTFUL_CONTENT_TYPE
  4. CONTENTFUL_ENVIRONMENT
    (optional, default:
    master
    )
Write to
.env.local
:
CONTENTFUL_SPACE_ID=<value>
CONTENTFUL_DELIVERY_TOKEN=<value>
CONTENTFUL_CONTENT_TYPE=<value>
CONTENTFUL_ENVIRONMENT=<value or master>

告知用户:
“连接Contentful需要三项信息:
  1. 空间ID(Space ID) — 在以下位置查找:Contentful → 设置 → 常规设置 → 空间ID
  2. 内容交付API令牌(Content Delivery API token) — 在以下位置查找: 设置 → API密钥 → [您的密钥] → 内容交付API - 访问令牌 (如果没有密钥,请在设置 → API密钥 → 添加API密钥下创建一个)
  3. 内容类型ID — 您的内容类型的API标识符。 在以下位置查找:内容模型 → [您的类型] → API标识符
可选信息:
  • 环境(默认值:
    master
准备好后粘贴每个值。”
收集:
  1. CONTENTFUL_SPACE_ID
  2. CONTENTFUL_DELIVERY_TOKEN
  3. CONTENTFUL_CONTENT_TYPE
  4. CONTENTFUL_ENVIRONMENT
    (可选,默认值:
    master
将内容写入
.env.local
CONTENTFUL_SPACE_ID=<value>
CONTENTFUL_DELIVERY_TOKEN=<value>
CONTENTFUL_CONTENT_TYPE=<value>
CONTENTFUL_ENVIRONMENT=<value or master>

3D — Ghost

3D — Ghost

Tell the user:
"I need two things to connect Ghost:
  1. Your Ghost URL (e.g.
    https://myblog.ghost.io
    )
  2. Content API key — create one in: Ghost Admin → Settings → Integrations → Add custom integration → copy the Content API Key
Optionally:
  • Content type:
    posts
    (default) or
    pages
Paste each value when ready."
Collect:
  1. GHOST_URL
  2. GHOST_CONTENT_KEY
  3. GHOST_CONTENT_TYPE
    (optional, default:
    posts
    )
Write to
.env.local
:
GHOST_URL=<value>
GHOST_CONTENT_KEY=<value>
GHOST_CONTENT_TYPE=<value or posts>

告知用户:
“连接Ghost需要两项信息:
  1. 您的Ghost网址(例如
    https://myblog.ghost.io
  2. 内容API密钥 — 在以下位置创建: Ghost后台 → 设置 → 集成 → 添加自定义集成 → 复制内容API密钥
可选信息:
  • 内容类型
    posts
    (默认值)或
    pages
准备好后粘贴每个值。”
收集:
  1. GHOST_URL
  2. GHOST_CONTENT_KEY
  3. GHOST_CONTENT_TYPE
    (可选,默认值:
    posts
将内容写入
.env.local
GHOST_URL=<value>
GHOST_CONTENT_KEY=<value>
GHOST_CONTENT_TYPE=<value or posts>

Step 4 — Write .env.local

步骤4 — 写入.env.local

Find the project's
.env.local
file. Search for it:
bash
ENV_FILE=""
for candidate in ".env.local" "$HOME/.env.local"; do
  [ -f "$candidate" ] && ENV_FILE="$candidate" && break
done
[ -z "$ENV_FILE" ] && ENV_FILE=".env.local"
echo "Writing to: $ENV_FILE"
Merge strategy — do not overwrite the entire file. For each env var:
  1. If the key already exists in the file, replace that line.
  2. If it does not exist, append it to the end.
Read the file first (if it exists), then update key by key, then write back.
If the file doesn't exist yet, create it.
After writing, confirm:
"Credentials written to
[path]
. Testing connection now..."

找到项目的
.env.local
文件。按以下方式搜索:
bash
ENV_FILE=""
for candidate in ".env.local" "$HOME/.env.local"; do
  [ -f "$candidate" ] && ENV_FILE="$candidate" && break
done
[ -z "$ENV_FILE" ] && ENV_FILE=".env.local"
echo "Writing to: $ENV_FILE"
合并策略 — 不要覆盖整个文件。对于每个环境变量:
  1. 如果密钥已存在于文件中,替换该行。
  2. 如果不存在,将其追加到文件末尾。
先读取文件(如果存在),然后逐个更新密钥,再写回文件。
如果文件尚未存在,则创建它。
写入完成后,确认:
“凭据已写入
[路径]
。现在测试连接...”

Step 5 — Test connection

步骤5 — 测试连接

Run the appropriate preflight script and capture the exit code:
bash
undefined
运行相应的预检脚本并捕获退出代码:
bash
undefined

WordPress

WordPress

python3 "$SKILL_SCRIPTS/preflight_wordpress.py" 2>&1; PREFLIGHT_EXIT=$?
python3 "$SKILL_SCRIPTS/preflight_wordpress.py" 2>&1; PREFLIGHT_EXIT=$?

Strapi

Strapi

python3 "$SKILL_SCRIPTS/preflight_strapi.py" 2>&1; PREFLIGHT_EXIT=$?
python3 "$SKILL_SCRIPTS/preflight_strapi.py" 2>&1; PREFLIGHT_EXIT=$?

Contentful

Contentful

python3 "$SKILL_SCRIPTS/preflight_contentful.py" 2>&1; PREFLIGHT_EXIT=$?
python3 "$SKILL_SCRIPTS/preflight_contentful.py" 2>&1; PREFLIGHT_EXIT=$?

Ghost

Ghost

python3 "$SKILL_SCRIPTS/preflight_ghost.py" 2>&1; PREFLIGHT_EXIT=$?

The `2>&1` redirect surfaces error messages in the output so you can show them.

**`PREFLIGHT_EXIT=0`** — connection successful. Show the "OK: …" line to the user,
then continue to Step 6.

**`PREFLIGHT_EXIT=1`** — connection failed. Show the full error output verbatim.
Help the user diagnose:
- `401 Unauthorized` → wrong token/password — suggest regenerating
- `403 Forbidden` → token lacks permission — suggest a Full Access / unrestricted token
- `404 Not Found` → wrong URL or wrong content type slug
- Network error → URL unreachable — check the URL in a browser first

Ask: "Want to fix the credentials and try again (I'll go back to Step 3), or skip CMS setup for now?"

**`PREFLIGHT_EXIT=2`** → credentials were removed from `.env.local` between steps. Restart from Step 3.

---
python3 "$SKILL_SCRIPTS/preflight_ghost.py" 2>&1; PREFLIGHT_EXIT=$?

`2>&1`会将错误消息重定向到输出中,以便您展示给用户。

**`PREFLIGHT_EXIT=0`** — 连接成功。向用户显示“OK: …”行,然后继续步骤6。

**`PREFLIGHT_EXIT=1`** — 连接失败。逐字显示完整的错误输出。
帮助用户诊断:
- `401 Unauthorized` → 令牌/密码错误 — 建议重新生成
- `403 Forbidden` → 令牌权限不足 — 建议使用全权限/无限制令牌
- `404 Not Found` → 网址错误或内容类型别名错误
- 网络错误 → 网址无法访问 — 先在浏览器中检查网址

询问:“是否需要修复凭据并重试(我将返回步骤3),还是暂时跳过CMS设置?”

**`PREFLIGHT_EXIT=2`** → 步骤之间`.env.local`中的凭据已被移除。从步骤3重新开始。

---

Step 6 — Confirm and summarize

步骤6 — 确认并总结

Once the connection succeeds, show a summary:
CMS connected successfully!

  CMS:          [WordPress/Strapi/Contentful/Ghost]
  URL:          [cms_url]
  Content type: [content_type]
  Published:    [N] entries found

What this enables in /seo-analysis:
  • Cross-reference [N] published articles against Google Search Console data
  • Find published content with zero GSC impressions (unindexed or invisible)
  • Identify content gaps: queries ranking 11-30 with no matching article
  • Flag stale content: articles >6 months old with declining clicks
  • Audit SEO fields: missing meta titles/descriptions, length violations
Then offer:
"Run
/seo-analysis
to see a full audit with your CMS content included, or type
/setup-cms
again to connect a different CMS."
连接成功后,显示总结:
CMS连接成功!

  CMS:          [WordPress/Strapi/Contentful/Ghost]
  URL:          [cms_url]
  Content type: [content_type]
  已发布内容:    [N] 条条目

这将为/seo-analysis带来以下功能:
  • 将[N]篇已发布文章与Google Search Console数据进行交叉引用
  • 找出Google Search Console中展示量为0的已发布内容(未索引或隐形)
  • 识别内容缺口:排名11-30位但无对应文章的查询
  • 标记过时内容:发布超过6个月且点击量下降的文章
  • 审核SEO字段:缺失元标题/描述、长度不符合要求
然后提供选项:
“运行
/seo-analysis
查看包含您CMS内容的完整审计报告, 或再次输入
/setup-cms
连接其他CMS。”