---
name: seo-multi-channel
description: Generate multi-channel marketing content (Facebook, Ads, Blog, X) with Thai language support and website-creator integration. Use when user wants to create content for multiple channels from a single topic.
---

# 🎯 SEO Multi-Channel Content Generator

**Skill Name:** `seo-multi-channel`  
**Category:** `deep`  
**Load Skills:** `['website-creator']`

---

## 🚀 Purpose

Generate marketing content for multiple channels from a single topic with:

- ✅ **Priority Channels:** Facebook > Facebook Ads > Google Ads > Blog > X (Twitter)
- ✅ **Thai Language Support:** Full Thai text processing with PyThaiNLP
- ✅ **Image Handling:** Browse website repo for product images, or ask user to provide
- ✅ **Website-Creator Integration:** Auto-publish blog posts to Astro content collections
- ✅ **API-Ready Output:** Structured JSON for future ad platform API integration
- ✅ **Per-Project Context:** Context files in each website repo

**Use Cases:**
1. **Multi-Channel Campaign:** One topic → Facebook post + Facebook Ads + Google Ads + Blog + X thread
2. **Social-Only:** Facebook post + Facebook Ads for product promotion
3. **Blog-First:** SEO blog post with auto-publish to website
4. **Ads-Only:** Google Ads + Facebook Ads copy for existing product

---

## 📋 Pre-Flight Questions

**MUST ask before generating:**

1. **Topic/Subject:** What topic do you want content about?

2. **Channels Needed:** (Default: All channels)
   - Facebook (organic posts)
   - Facebook Ads (paid campaigns)
   - Google Ads (search campaigns)
   - Blog (SEO articles)
   - X/Twitter (threads)

3. **Content Type:** (Auto-detect or ask)
   - Product/Service (requires product images)
   - Knowledge/Educational (generates fresh images)
   - Statistics/Data (generates infographic-style images)
   - Announcement/News (may not need images)

4. **Target Language:** (Auto-detect from topic or ask)
   - Thai (default for Thai topics)
   - English
   - Bilingual (both Thai + English)

5. **For Product Content:**
   - Product name
   - Website repo path (to browse for existing images)
   - Product URL (if available)

6. **For Blog Posts:**
   - Target keyword for SEO
   - Should I auto-publish to website? (yes/no)
   - Website repo path (if auto-publish)

7. **Tone/Formality:** (Auto-detect from context or default)
   - กันเอง (Casual) - for social media
   - ปกติ (Normal) - for blog
   - เป็นทางการ (Formal) - for corporate

---

## 🔄 Workflow

### Phase 1: Context Loading

1. **Load Project Context:**
   - Read `context/brand-voice.md` from website repo
   - Read `context/target-keywords.md`
   - Read `context/seo-guidelines.md`
   - Auto-detect formality level from brand voice

2. **Check Data Services:**
   - Check if GA4 configured (skip if not)
   - Check if GSC configured (skip if not)
   - Check if DataForSEO configured (skip if not)
   - Check if Umami configured (skip if not)
   - Fetch available performance data

3. **Load Channel Templates:**
   - Load YAML templates for selected channels
   - Apply brand voice customizations

---

### Phase 2: Content Generation

#### **For Each Channel:**

**Facebook (Organic):**
```yaml
Output:
  - primary_text: 125-250 chars (Thai can be longer)
  - headline: 100 chars max
  - hashtags: 3-5 recommended
  - cta: เลือกจาก ["เรียนรู้เพิ่มเติม", "สมัครเลย", "ซื้อเลย", "ดูรายละเอียด"]
  - image: Generated or edited
  - variations: 5 options
```

**Facebook Ads:**
```yaml
Output:
  - primary_text: 125 chars recommended (5000 max)
  - headline: 40 chars
  - description: 90 chars
  - cta: Button choice
  - image: Product-focused or benefit-focused
  - variations: 5 options
  - api_ready: true (matches Meta Ads API structure)
```

**Google Ads:**
```yaml
Output:
  - headlines: 15 variations (30 chars each)
  - descriptions: 4 variations (90 chars each)
  - keywords: Suggested keyword list
  - negative_keywords: Suggested negatives
  - ad_extensions: Sitelink, callout, structured snippets
  - api_ready: true (matches Google Ads API structure)
```

**Blog (SEO Article):**
```yaml
Output:
  - markdown: Full article with frontmatter
  - word_count: 1500-3000 (Thai), 2000-3000 (English)
  - keyword_density: 1.0-1.5% (Thai), 1.5-2% (English)
  - meta_title: 50-60 chars
  - meta_description: 150-160 chars
  - slug: Auto-generated (Thai-friendly)
  - images: Saved to website repo
  - astro_ready: true (content collections format)
```

**X/Twitter Thread:**
```yaml
Output:
  - tweets: 5-10 tweet thread
  - hook_tweet: First tweet (280 chars)
  - body_tweets: 2-8 tweets (280 chars each)
  - cta_tweet: Final tweet with CTA
  - hashtags: 2-3 per tweet
  - thread_title: Optional title card
```

---

### Phase 3: Image Handling

#### **Product Content:**

```python
1. Browse website repo for existing product images:
   - Search: public/images/, src/assets/, **/*{product_name}*.{jpg,png,webp}
   
2. If images found:
   - Select best image (highest quality, product-focused)
   - Ask user: "Use this image or provide a new one?"
   
3. If no images found:
   - Ask user: "No product images found in repo. Please provide image path or URL."
   - Wait for user to provide
```

#### **Non-Product Content:**

```python
1. Determine content type:
   - Service → Professional illustration
   - Knowledge → Educational visual metaphor
   - Stats → Infographic with charts
   - News → Clean, modern announcement style

2. Ask user to provide image:
   - "For this content, please provide an image or use: [suggestion]"

3. Save images:
   - Social/Ads → seo-multi-channel/generated-images/{topic}/{channel}/
   - Blog → {website-repo}/public/images/blog/{slug}/
```

---

### Phase 4: Output & Publishing

#### **Output Structure:**

```
output/{topic-slug}/
├── facebook/
│   ├── posts.json
│   └── images/
├── facebook_ads/
│   ├── ads.json
│   └── images/
├── google_ads/
│   └── ads.json
├── blog/
│   ├── article.md
│   └── images/
├── x/
│   └── thread.json
└── summary.json
```

#### **Auto-Publish Blog (if enabled):**

```python
1. Parse frontmatter from blog markdown
2. Detect language (Thai → 'th', English → 'en')
3. Generate slug (Thai-friendly: use transliteration or keep Thai)
4. Save to: {website-repo}/src/content/blog/({lang})/{slug}.md
5. Copy images to: {website-repo}/public/images/blog/{slug}/
6. Git commit: git add . && git commit -m "Add blog post: {slug}"
7. Git push: git push origin main (triggers Easypanel auto-deploy)
8. Return deployment URL
```

---

## 📁 Output Examples

### **Facebook Post Output:**

```json
{
  "channel": "facebook",
  "topic": "บริการ podcast",
  "language": "th",
  "generated_at": "2026-03-08T14:30:00+07:00",
  "variations": [
    {
      "id": "fb_post_1",
      "primary_text": "คุณกำลังมองหาวิธีเริ่มต้น podcast ใช่ไหม? 🎙️\n\nตอนนี้ใครๆ ก็ทำ podcast ได้ง่ายๆ แค่มีเครื่องมือที่เหมาะสม เราช่วยคุณได้ตั้งแต่เริ่มจนถึงเผยแพร่\n\n#podcast #podcastไทย #สร้างpodcast",
      "headline": "เริ่มต้น podcast ของคุณวันนี้",
      "cta": "เรียนรู้เพิ่มเติม",
      "hashtags": ["#podcast", "#podcastไทย", "#สร้างpodcast"],
      "image": {
        "type": "generated",
        "path": "output/บริการ-podcast/facebook/images/variation_1.png",
        "prompt": "Professional podcast studio setup with microphone and headphones, modern aesthetic, Thai-friendly design"
      },
      "api_ready": {
        "message": "Matches Meta Graph API /act_id/adcreatives structure",
        "endpoint": "POST /v18.0/act_{ad_account_id}/adcreatives"
      }
    }
  ]
}
```

### **Google Ads Output:**

```json
{
  "channel": "google_ads",
  "topic": "podcast hosting",
  "language": "th",
  "generated_at": "2026-03-08T14:30:00+07:00",
  "responsive_search_ads": [
    {
      "id": "ga_rsa_1",
      "headlines": [
        {"text": "บริการ Podcast Hosting", "pin": false},
        {"text": "เริ่มต้นฟรี 14 วัน", "pin": false},
        {"text": "เผยแพร่ทุกแพลตฟอร์ม", "pin": false},
        {"text": "ง่าย รวดเร็ว มืออาชีพ", "pin": false},
        {"text": "รองรับภาษาไทย", "pin": false}
      ],
      "descriptions": [
        {"text": "แพลตฟอร์ม podcast ที่ครบวงจรที่สุด เริ่มต้นสร้าง podcast ของคุณวันนี้"},
        {"text": "เผยแพร่ Apple Podcasts, Spotify, YouTube Music ได้ในคลิกเดียว"}
      ],
      "keywords": ["podcast hosting", "host podcast", "บริการ podcast", "แพลตฟอร์ม podcast"],
      "negative_keywords": ["ฟรี", "download", "mp3"],
      "ad_extensions": {
        "sitelinks": [
          {"text": "เริ่มฟรี 14 วัน", "url": "/free-trial"},
          {"text": "ดูคุณสมบัติ", "url": "/features"}
        ],
        "callouts": ["รองรับภาษาไทย", "ทีมซัพพอร์ท 24/7", "ยกเลิกเมื่อไหร่ก็ได้"]
      },
      "api_ready": {
        "matches": "Google Ads API v15.0",
        "endpoint": "POST /google.ads.googleads.v15.services/GoogleAdsService:Mutate",
        "resource": "AdGroupAd"
      }
    }
  ]
}
```

### **Blog Post Output:**

```markdown
---
title: "บริการ Podcast Hosting ที่ดีที่สุดปี 2026: คู่มือครบวงจร"
description: "เปรียบเทียบ 10+ บริการ podcast hosting พร้อมข้อมูลจริง ช่วยคุณเลือกแพลตฟอร์มที่เหมาะกับ podcast ของคุณ"
keywords: ["podcast hosting", "บริการ podcast", "แพลตฟอร์ม podcast", "host podcast"]
slug: podcast-hosting-best-2026
lang: th
category: guides
tags: [podcast, hosting, review]
created: 2026-03-08
images:
  - src: /images/blog/podcast-hosting-best-2026/hero.png
    alt: "เปรียบเทียบบริการ podcast hosting"
---

# บริการ Podcast Hosting ที่ดีที่สุดในปี 2026

คุณกำลังมองหาบริการ podcast hosting ที่ใช่อยู่ใช่ไหม? 🎙️

บทความนี้จะเปรียบเทียบแพลตฟอร์มยอดนิยม 10+ เจ้า พร้อมข้อมูลจริงจากการทดสอบ...

[Content continues for 2000+ words]

## สรุป

เลือกบริการ podcast hosting ที่เหมาะกับคุณที่สุด...

**พร้อมเริ่ม podcast ของคุณหรือยัง?** [สมัครฟรี 14 วัน →](/signup)
```

---

## 🔧 Technical Implementation

### **Thai Language Processing:**

```python
from pythainlp import word_tokenize, sent_tokenize
from pythainlp.util import normalize

def count_thai_words(text: str) -> int:
    """Count Thai words (no spaces between words)"""
    tokens = word_tokenize(text, engine="newmm")
    return len([t for t in tokens if t.strip() and not t.isspace()])

def calculate_thai_keyword_density(text: str, keyword: str) -> float:
    """Calculate keyword density for Thai text"""
    text_normalized = normalize(text)
    keyword_normalized = normalize(keyword)
    count = text_normalized.count(keyword_normalized)
    word_count = count_thai_words(text)
    return (count / word_count * 100) if word_count > 0 else 0

def detect_content_language(text: str) -> str:
    """Detect if content is Thai or English"""
    thai_chars = sum(1 for c in text if '\u0E00' <= c <= '\u0E7F')
    total_chars = len(text)
    thai_ratio = thai_chars / total_chars if total_chars > 0 else 0
    
    if thai_ratio > 0.3:
        return 'th'
    return 'en'
```

### **Image Handling:**

```python
import os
import glob
from pathlib import Path

def find_product_images(product_name: str, website_repo: str) -> List[str]:
    """Find existing product images in website repo"""
    extensions = ['.jpg', '.jpeg', '.png', '.webp']
    found_images = []
    
    search_patterns = [
        f"**/*{product_name}*{{ext}}" for ext in extensions
    ] + [
        f"public/images/**/*{{ext}}",
        f"src/assets/**/*{{ext}}"
    ]
    
    for pattern in search_patterns:
        matches = glob.glob(os.path.join(website_repo, pattern), recursive=True)
        found_images.extend(matches)
    
    return found_images[:10]  # Return top 10 matches

def save_image_for_channel(image_data: bytes, topic: str, channel: str) -> str:
    """Save generated/edited image to correct location"""
    if channel == 'blog':
        # Blog images go to website repo
        output_dir = os.path.join(website_repo, 'public/images/blog', topic_slug)
    else:
        # Social/Ads images go to separate folder
        output_dir = os.path.join('output', topic_slug, channel, 'images')
    
    os.makedirs(output_dir, exist_ok=True)
    image_path = os.path.join(output_dir, f"variation_{variation_num}.png")
    
    with open(image_path, 'wb') as f:
        f.write(image_data)
    
    return image_path
```

### **Website-Creator Integration:**

```python
def publish_blog_to_astro(article_md: str, website_repo: str) -> Dict:
    """
    Publish blog post to Astro content collections
    Returns deployment status
    """
    # Parse frontmatter
    frontmatter = parse_frontmatter(article_md)
    
    # Detect language
    lang = detect_content_language(article_md)
    
    # Generate slug
    slug = generate_slug(frontmatter['title'], lang)
    
    # Determine output path
    output_path = os.path.join(
        website_repo,
        'src/content/blog',
        f'({lang})',
        f'{slug}.md'
    )
    
    # Ensure directory exists
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    
    # Write article
    with open(output_path, 'w', encoding='utf-8') as f:
        f.write(article_md)
    
    # Copy images if any
    if 'images' in frontmatter:
        for img in frontmatter['images']:
            # Copy from temp location to website repo
            dest_path = os.path.join(website_repo, 'public', img['src'].lstrip('/'))
            os.makedirs(os.path.dirname(dest_path), exist_ok=True)
            shutil.copy(img['local_path'], dest_path)
    
    # Git commit and push
    subprocess.run(['git', 'add', '.'], cwd=website_repo, check=True)
    subprocess.run(['git', 'commit', '-m', f'Add blog post: {slug}'], cwd=website_repo, check=True)
    subprocess.run(['git', 'push', 'origin', 'main'], cwd=website_repo, check=True)
    
    # Return deployment info
    return {
        'published': True,
        'slug': slug,
        'language': lang,
        'path': output_path,
        'deployment_url': f"https://your-domain.com/blog/{slug}" if lang == 'en' else f"https://your-domain.com/th/{slug}"
    }
```

---

## 📐 Channel Specifications

### **Facebook:**
- Primary text: 125-250 chars (Thai can be longer)
- Headline: 100 chars max
- Hashtags: 3-5 recommended
- Image: 1200x630 (1.91:1)
- Variations: 5

### **Facebook Ads:**
- Primary text: 125 chars recommended (5000 max)
- Headline: 40 chars
- Description: 90 chars
- CTA: Button selection
- Image: 1200x628 (1.91:1) or 1080x1080 (1:1)
- API ready: Yes (Meta Graph API)

### **Google Ads:**
- Headlines: 15 variations, 30 chars each
- Descriptions: 4 variations, 90 chars each
- Keywords: 15-20 suggested
- Negative keywords: 10-15 suggested
- Ad extensions: Sitelinks, callouts, structured snippets
- API ready: Yes (Google Ads API)

### **Blog:**
- Word count: 1500-3000 (Thai), 2000-3000 (English)
- Keyword density: 1.0-1.5% (Thai), 1.5-2% (English)
- Meta title: 50-60 chars
- Meta description: 150-160 chars
- Images: Saved to website repo
- Format: Markdown with frontmatter
- Astro ready: Yes (content collections)

### **X/Twitter:**
- Hook tweet: 280 chars
- Body tweets: 2-8 tweets, 280 chars each
- CTA tweet: 280 chars
- Hashtags: 2-3 per tweet
- Thread title: Optional

---

## ⚙️ Environment Variables

**Required (in unified .env or project .env):**

```bash
# MiniMax API (for image generation via minimax-multimodal-toolkit)
MINIMAX_API_KEY=your_token_here

# Google Analytics 4 (optional)
GA4_PROPERTY_ID=G-XXXXXXXXXX
GA4_CREDENTIALS_PATH=path/to/ga4-credentials.json

# Google Search Console (optional)
GSC_SITE_URL=https://yourdomain.com
GSC_CREDENTIALS_PATH=path/to/gsc-credentials.json

# DataForSEO (optional)
DATAFORSEO_LOGIN=your_login
DATAFORSEO_PASSWORD=your_password

# Umami Analytics (optional, if self-hosted)
UMAMI_API_URL=https://analytics.yourdomain.com
UMAMI_API_KEY=your_api_key
```

---

## 🚀 Commands

### **Generate Multi-Channel Content:**

```bash
python3 skills/seo-multi-channel/scripts/generate_content.py \
  --topic "บริการ podcast hosting" \
  --channels facebook facebook_ads google_ads blog x \
  --website-repo ./my-website \
  --auto-publish true
```

### **Generate for Specific Channel:**

```bash
# Facebook Ads only
python3 skills/seo-multi-channel/scripts/generate_content.py \
  --topic "podcast microphone" \
  --channels facebook_ads \
  --product-name "PodMic Pro" \
  --website-repo ./my-website
```

### **Publish Existing Blog:**

```bash
python3 skills/seo-multi-channel/scripts/publish_blog.py \
  --article drafts/podcast-guide-2026.md \
  --website-repo ./my-website
```

---

## 📊 Quality Scoring

Each piece of content is scored before output:

1. **Keyword Optimization** (0-25 points)
   - Density, placement, variations

2. **Brand Voice Alignment** (0-25 points)
   - Tone, terminology, style

3. **Channel Fit** (0-25 points)
   - Length, format, CTA appropriateness

4. **Thai Language Quality** (0-25 points)
   - Natural phrasing, formality level, no awkward translations

**Minimum score: 70/100** to publish. Below 70 → auto-revise or flag for review.

---

## ⚠️ Important Notes

1. **Thai Word Counting:** Thai has no spaces between words. Uses PyThaiNLP for accurate counting.

2. **Formality Detection:** Auto-detects from brand voice context. Defaults to casual for social, normal for blog.

3. **Image Handling:**
   - Product content → Browse repo first → Ask user to confirm or provide
   - Non-product → Ask user to provide image
   - Blog images → Website repo
   - Social/Ads images → Separate folder

4. **API Ready:** Output structures match Google Ads and Meta Ads API schemas for future integration.

5. **Data Services Optional:** Skips unconfigured services (GA4, GSC, DataForSEO, Umami).

6. **Per-Project Context:** Each website has its own context/ folder with brand voice, keywords, guidelines.

---

## 🔄 Integration with Other Skills

- **website-creator:** Blog posts published to Astro content collections
- **seo-analyzers:** Quality scoring and Thai language analysis
- **seo-data:** Performance data for content optimization
- **seo-context:** Context file management

---

## ✅ Success Criteria

- ✅ Content generated for all selected channels
- ✅ Thai language processing accurate (word count, keyword density)
- ✅ Product images found or user asked to provide
- ✅ Blog posts published to Astro (if enabled)
- ✅ Git commit + push successful (triggers auto-deploy)
- ✅ Output structures API-ready for future integration
- ✅ Quality scores ≥ 70/100 for all content

---

**Use this skill when you need to create multi-channel marketing content from a single topic with full Thai language support and automatic image handling.**
