skills/blog-taxonomy/SKILL.md
Extract, suggest, and sync tags and categories for blog posts across all major CMS platforms. Supports WordPress REST API, Shopify GraphQL, Ghost Content API, Strapi REST/GraphQL, and Sanity GROQ. Generates tag suggestions from content analysis (keyword frequency, heading extraction, semantic grouping), enforces minimum post-count thresholds to prevent thin tag archives, and syncs taxonomy via authenticated API calls. Use when user says "tags", "categories", "taxonomy", "tag suggestions", "sync tags", "WordPress tags", "Shopify tags".
npx skillsauth add agricidaniel/claude-blog blog-taxonomyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Manage tags, categories, and topic clusters across CMS platforms.
| Command | Purpose |
|---------|---------|
| /blog taxonomy suggest <file> | Extract candidate tags and categories from content |
| /blog taxonomy sync <cms> | Push taxonomy to CMS via authenticated API |
| /blog taxonomy audit [directory] | Check for thin tags, orphan tags, taxonomy bloat |
Read the target file and extract:
Scan the body text for high-frequency phrases:
Exclude common non-tag words: articles, prepositions, conjunctions, pronouns.
Group related candidates into clusters:
(frequency * 2) + (heading_presence * 5) + (emphasis * 1)## Tag Suggestions: [Post Title]
| Rank | Tag | Score | Source |
|------|-----|-------|--------|
| 1 | content-marketing | 18 | H2 + 6 mentions |
| 2 | seo-strategy | 14 | H3 + 4 mentions |
| 3 | keyword-research | 11 | 5 mentions + bold |
### Suggested Categories
- Primary: [best-fit category]
- Secondary: [optional second category]
| CMS | API Type | Auth Method | Tags Model | |-----|----------|-------------|------------| | WordPress | REST | Application Passwords (base64) | First-class entities with IDs | | Shopify | GraphQL (Admin API) | Admin API access token | String array on Article | | Ghost | REST (Admin API) | API key with JWT signing | First-class entities | | Strapi | REST or GraphQL | API token (Bearer) | User-defined content type | | Sanity | GROQ / Mutations | Project token (Bearer) | Document type |
List tags:
GET {CMS_URL}/wp-json/wp/v2/tags?per_page=100&search={keyword}
Authorization: Basic {base64(username:app_password)}
Create tag:
POST {CMS_URL}/wp-json/wp/v2/tags
Body: {"name": "Tag Name", "slug": "tag-name", "description": "Optional"}
List categories (hierarchical, supports parent field):
GET {CMS_URL}/wp-json/wp/v2/categories?per_page=100
Create category:
POST {CMS_URL}/wp-json/wp/v2/categories
Body: {"name": "Category", "slug": "category", "parent": 0}
Assign tags to post:
POST {CMS_URL}/wp-json/wp/v2/posts/{id}
Body: {"tags": [1, 2, 3], "categories": [4]}
Pagination: follow X-WP-TotalPages header for full listing.
Tags on Shopify are string arrays on the Article object, not first-class entities.
Update article tags (GraphQL Admin API):
mutation {
articleUpdate(id: "gid://shopify/Article/123", article: {
tags: ["tag-one", "tag-two", "tag-three"]
}) {
article { id tags }
userErrors { field message }
}
}
List all tags in use (GraphQL):
{
articles(first: 250) {
edges {
node { id title tags }
}
}
}
Auth header: X-Shopify-Access-Token: {token}
Note: REST API marked legacy Oct 2024. GraphQL required for new apps since Apr 2025.
List tags:
GET {CMS_URL}/ghost/api/admin/tags/?limit=all
Authorization: Ghost {jwt_token}
Create tag:
POST {CMS_URL}/ghost/api/admin/tags/
Body: {"tags": [{"name": "Tag Name", "slug": "tag-name"}]}
JWT generation: sign with admin API key (id:secret format), iat = now, exp = 5 min,
audience = /admin/.
Endpoint auto-generated from content types. Typical setup:
GET {CMS_URL}/api/tags?pagination[pageSize]=100
POST {CMS_URL}/api/tags
Body: {"data": {"name": "Tag Name", "slug": "tag-name"}}
Authorization: Bearer {api_token}
Strapi v4+ uses the data wrapper. Check your content type schema for field names.
Query tags (GROQ):
*[_type == "tag"] { _id, name, slug }
Create tag (Mutations API):
POST https://{project_id}.api.sanity.io/v2024-01-01/data/mutate/{dataset}
Body: {"mutations": [{"create": {"_type": "tag", "name": "Tag", "slug": {"current": "tag"}}}]}
Authorization: Bearer {token}
Scan all posts in the target directory (or fetch from CMS). Build a map:
| Check | Threshold | Action | |-------|-----------|--------| | Thin tag archives | < 5 posts per tag | Recommend noindex or merge | | Orphan tags | 0 posts | Recommend deletion | | Tag bloat | > 50 total tags | Recommend consolidation | | Category depth | > 3 levels | Recommend flattening | | Uncategorized posts | No category assigned | Assign to appropriate category | | Duplicate slugs | Same slug, different name | Merge into canonical version |
Group findings by priority:
## Taxonomy Audit: [Site/Directory]
**Total tags**: [n] | **Total categories**: [n]
**Healthy**: [n] | **Thin**: [n] | **Orphan**: [n]
### Critical Issues
- [orphan tags list]
### Recommendations
1. Merge [tag-a] and [tag-b] (same topic, [n] combined posts)
2. Delete orphan tags: [list]
3. Add noindex to tag archives with < 5 posts
| Variable | Purpose | Example | |----------|---------|---------| | CMS_TYPE | Platform identifier | wordpress, shopify, ghost, strapi, sanity | | CMS_URL | Base URL of the CMS | https://example.com | | CMS_API_KEY | Authentication credential | Application password, API token, or key |
These must be set in the shell environment. Never store credentials in files or
commit them to version control. The skill reads them via $CMS_TYPE, $CMS_URL,
and $CMS_API_KEY at runtime.
development
Research what people are actually saying about a topic in the last 30 days across Reddit, X / Twitter, YouTube, Hacker News, dev.to, Medium, and other public discourse platforms. API-free; uses WebSearch with platform-targeted site operators plus recency filters. Produces DISCOURSE.md (a structured brief) and JSON output the writer can consume. Complements blog-researcher (which focuses on authority sources) with a recency-and-engagement lens. Use when user says "blog discourse", "discourse research", "what are people saying about", "research what people are saying", "voice of customer", "social listening", "30-day research", "trend research", "what's the discussion on", "real-time research", "practitioner discourse", "/blog discourse".
documentation
Establish durable brand and voice context for cross-skill consumption. Generates BRAND.md (audience, positioning, do/don't editorial rules, taboo phrases, competitor differentiation) and VOICE.md (existing persona JSON re-expressed as readable prose), both written to the project root. When present, all blog sub-skills auto-load these files before writing or reviewing. Pairs with blog-persona, which manages the structured persona JSON. Use when user says "blog brand", "create brand context", "brand voice doc", "BRAND.md", "VOICE.md", "establish editorial brand", "brand guidelines for blog".
testing
Translate existing blog posts into one or more target languages with SEO-optimized localization. Produces native-quality translations that preserve markdown structure, frontmatter, schema JSON-LD, image and chart embeds, and citation capsules. Localizes keywords, meta tags, numbers, dates, currencies, and quote styles per locale. Flags machine-translation artifacts for review. Run BEFORE blog-localize: this handles language conversion; localize handles cultural adaptation after translation completes. Use when user says "translate blog", "blog translate", "uebersetzen", "traduire", "traducir", "translate post", "blog auf Deutsch", "blog en espanol".
testing
One-command multilingual blog creation. Writes a blog post, translates it into user-specified languages, applies cultural adaptation, and emits hreflang tags, sitemap entries, and a CMS-ready language map. The complete write-to-publish pipeline for international content. Orchestrates blog-write, blog-translate, blog-localize, and (optionally) seo-hreflang. Use when user says "multilingual blog", "blog multilingual", "write in multiple languages", "international blog", "mehrsprachiger Blog", "blog multilingue", "blog multilingue", "create blog in German and French".