Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.mavera.io/llms.txt

Use this file to discover all available pages before exploring further.

Scenario

Your WordPress category taxonomy reveals where your content strategy is thin. You pull all categories with their post counts, identify categories with few or no posts, create a Mavera persona for your target reader in each sparse category, then run a focus group to validate which content gaps your audience actually cares about filling.

Architecture

Code

import os, requests

WP, MV = os.environ["WORDPRESS_URL"], os.environ["MAVERA_API_KEY"]
MB = "https://app.mavera.io/api/v1"
MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}
THRESHOLD = 3

cats, page = [], 1
while True:
    resp = requests.get(f"{WP}/wp-json/wp/v2/categories", params={
        "per_page": 100, "page": page, "_fields": "id,name,slug,count,description"})
    if resp.status_code == 400: break
    resp.raise_for_status()
    batch = resp.json()
    if not batch: break
    cats.extend(batch)
    if page >= int(resp.headers.get("X-WP-TotalPages", 1)): break
    page += 1

sparse = sorted([c for c in cats if c["count"] < THRESHOLD and c["name"] != "Uncategorized"], key=lambda c: c["count"])
print(f"Categories: {len(cats)} | Sparse (< {THRESHOLD} posts): {len(sparse)}")

persona_ids = []
for c in sparse[:6]:
    r = requests.post(f"{MB}/personas", json={
        "name": f"Reader — {c['name']}",
        "description": f"Professional searching for {c['name'].lower()} content. Found limited coverage. Desc: {c.get('description', 'N/A')}",
    }, headers=MH)
    r.raise_for_status()
    persona_ids.append(r.json()["id"])
    print(f"  Persona: {r.json()['name']} ({r.json()['id']})")

cat_list = "\n".join(f"- {c['name']}: {c['count']} posts" for c in sparse[:6])
fg = requests.post(f"{MB}/focus-groups", json={
    "name": "WordPress Category Gap Analysis", "persona_ids": persona_ids,
    "questions": ["Which content gaps would you most want filled?",
        "What specific topics within your area would you search for?",
        "Would you subscribe if this category were covered regularly?",
        "Best format — long guides, short tips, or video tutorials?"],
    "context": f"Blog has thin coverage:\n\n{cat_list}",
}, headers=MH)
fg.raise_for_status(); result = fg.json()
print(f"\nFocus group: {result['id']}")
for r in result.get("responses", []):
    print(f"\n[{r['persona_name']}] {r['question']}\n{r['answer']}")

Example Output

{
  "id": "fg_9b2e4f1a",
  "name": "WordPress Category Gap Analysis",
  "responses": [
    {
      "persona_name": "Reader — Data Engineering",
      "question": "Which of these content gaps would you most want filled?",
      "answer": "Data Engineering, without question. There are plenty of general data science blogs, but practical data engineering content — pipeline architecture, orchestration tools, data quality — is hard to find in one place."
    },
    {
      "persona_name": "Reader — Developer Experience",
      "question": "What format works best — long guides, short tips, or video tutorials?",
      "answer": "Short, scannable tips with code snippets I can copy. I read during standups and between deploys — I need answers in 3 minutes, not 30."
    }
  ]
}

Error Handling

WordPress creates a default “Uncategorized” category that may have a high count. The code explicitly filters it out. If you’ve renamed the default category, update the filter to match your category name or filter by the default category ID (usually 1).
If your taxonomy has dozens of sparse categories, the focus group becomes unfocused. Limit to 5–6 categories per focus group. Run separate groups for different topic clusters (e.g., technical vs. business categories).