Major refactoring to create a clean, integrated CLI application: ### New Features: - Unified CLI executable (./seo) with simple command structure - All commands accept optional CSV file arguments - Auto-detection of latest files when no arguments provided - Simplified output directory structure (output/ instead of output/reports/) - Cleaner export filename format (all_posts_YYYY-MM-DD.csv) ### Commands: - export: Export all posts from WordPress sites - analyze [csv]: Analyze posts with AI (optional CSV input) - recategorize [csv]: Recategorize posts with AI - seo_check: Check SEO quality - categories: Manage categories across sites - approve [files]: Review and approve recommendations - full_pipeline: Run complete workflow - analytics, gaps, opportunities, report, status ### Changes: - Moved all scripts to scripts/ directory - Created config.yaml for configuration - Updated all scripts to use output/ directory - Deprecated old seo-cli.py in favor of new ./seo - Added AGENTS.md and CHANGELOG.md documentation - Consolidated README.md with updated usage ### Technical: - Added PyYAML dependency - Removed hardcoded configuration values - All scripts now properly integrated - Better error handling and user feedback Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
444 lines
11 KiB
Markdown
444 lines
11 KiB
Markdown
# Multi-Site SEO Analyzer Guide
|
||
|
||
**Purpose:** Fetch posts from all 3 WordPress sites, analyze titles and meta descriptions, and provide AI-powered optimization recommendations.
|
||
|
||
**Output:** CSV with detailed analysis + Markdown summary report
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
The Multi-Site SEO Analyzer does the following:
|
||
|
||
1. **Fetches** all published posts from your 3 WordPress sites (mistergeek.net, webscroll.fr, hellogeek.net)
|
||
2. **Analyzes** each post's:
|
||
- Title (length, power words, numbers, readability)
|
||
- Meta description (presence, length, call-to-action)
|
||
3. **Scores** posts on SEO best practices (0-100)
|
||
4. **Generates** AI recommendations for your top priority posts
|
||
5. **Exports** results to CSV for action
|
||
|
||
---
|
||
|
||
## Setup
|
||
|
||
### Step 1: Configure WordPress Access
|
||
|
||
Update your `.env` file with credentials for all 3 sites:
|
||
|
||
```bash
|
||
# Primary site (fallback for others if not specified)
|
||
WORDPRESS_URL=https://www.mistergeek.net
|
||
WORDPRESS_USERNAME=your_username
|
||
WORDPRESS_APP_PASSWORD=your_app_password
|
||
|
||
# Site 1: mistergeek.net (uses primary credentials if not specified)
|
||
WORDPRESS_MISTERGEEK_URL=https://www.mistergeek.net
|
||
WORDPRESS_MISTERGEEK_USERNAME=your_username
|
||
WORDPRESS_MISTERGEEK_PASSWORD=your_app_password
|
||
|
||
# Site 2: webscroll.fr
|
||
WORDPRESS_WEBSCROLL_URL=https://www.webscroll.fr
|
||
WORDPRESS_WEBSCROLL_USERNAME=your_username
|
||
WORDPRESS_WEBSCROLL_PASSWORD=your_app_password
|
||
|
||
# Site 3: hellogeek.net
|
||
WORDPRESS_HELLOGEEK_URL=https://www.hellogeek.net
|
||
WORDPRESS_HELLOGEEK_USERNAME=your_username
|
||
WORDPRESS_HELLOGEEK_PASSWORD=your_app_password
|
||
|
||
# OpenRouter API (for AI recommendations)
|
||
OPENROUTER_API_KEY=your_key
|
||
```
|
||
|
||
**Note:** If a site's credentials are not specified, the script uses the primary site credentials.
|
||
|
||
### Step 2: Verify Your .env
|
||
|
||
```bash
|
||
cat .env | grep -E "WORDPRESS|OPENROUTER"
|
||
```
|
||
|
||
---
|
||
|
||
## Usage
|
||
|
||
### Basic Usage (with AI recommendations)
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py
|
||
```
|
||
|
||
This will:
|
||
- Fetch all posts from 3 sites
|
||
- Analyze each post
|
||
- Generate AI recommendations for top 10 worst-scoring posts
|
||
- Export results to CSV and Markdown
|
||
|
||
### Include Draft Posts
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py --include-drafts
|
||
```
|
||
|
||
Analyzes both published and draft posts. Useful for:
|
||
- Optimizing posts before publishing
|
||
- Recovering removed content saved as drafts
|
||
- Getting full picture of all content
|
||
- CSV will show `status` column (publish/draft)
|
||
|
||
### Skip AI (Save Cost)
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py --no-ai
|
||
```
|
||
|
||
Analyzes posts without AI recommendations. Good for:
|
||
- Quick overview
|
||
- Sites with >500 posts (AI costs add up)
|
||
- Budget testing
|
||
|
||
### Generate AI for Top 20 Posts
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py --top-n 20
|
||
```
|
||
|
||
AI recommendations for 20 worst-scoring posts instead of 10.
|
||
|
||
### Combine Options
|
||
|
||
```bash
|
||
# Analyze published + drafts with AI for top 20
|
||
python scripts/multi_site_seo_analyzer.py --include-drafts --top-n 20
|
||
|
||
# Analyze drafts only (then filter in Excel to status=draft)
|
||
python scripts/multi_site_seo_analyzer.py --include-drafts --no-ai
|
||
```
|
||
|
||
### Custom Output File
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py --output output/custom_report.csv
|
||
```
|
||
|
||
---
|
||
|
||
## Output Files
|
||
|
||
### 1. CSV Report: `seo_analysis_TIMESTAMP.csv`
|
||
|
||
Contains all analyzed posts with columns:
|
||
|
||
| Column | Description |
|
||
|--------|-------------|
|
||
| `site` | Website (mistergeek.net, webscroll.fr, hellogeek.net) |
|
||
| `post_id` | WordPress post ID |
|
||
| `title` | Post title |
|
||
| `slug` | Post slug |
|
||
| `url` | Full post URL |
|
||
| `meta_description` | Current meta description |
|
||
| `title_score` | Title SEO score (0-100) |
|
||
| `title_issues` | Title problems (too short, no power words, etc.) |
|
||
| `title_recommendations` | How to improve title |
|
||
| `meta_score` | Meta description SEO score (0-100) |
|
||
| `meta_issues` | Meta description problems |
|
||
| `meta_recommendations` | How to improve meta |
|
||
| `overall_score` | Combined score (40% title + 60% meta) |
|
||
| `ai_recommendations` | Claude-generated specific recommendations |
|
||
|
||
### 2. Summary Report: `seo_analysis_TIMESTAMP_summary.md`
|
||
|
||
Human-readable markdown with:
|
||
- Overall statistics (total posts, average score, cost)
|
||
- Priority issues (missing meta, weak titles, weak descriptions)
|
||
- Per-site breakdown
|
||
- Top 5 posts to optimize on each site
|
||
- Legend explaining scores
|
||
|
||
---
|
||
|
||
## Understanding Scores
|
||
|
||
### Title Score (0-100)
|
||
|
||
**What's analyzed:**
|
||
- Length (target: 50-70 characters)
|
||
- Power words (best, complete, guide, ultimate, essential, etc.)
|
||
- Numbers (top 5, 2025, etc.)
|
||
- Special characters that might break rendering
|
||
|
||
**Optimal title example:**
|
||
"The Complete 2025 Guide to VPN Services (Updated)"
|
||
- Length: 57 characters ✓
|
||
- Power words: "Complete", "Guide" ✓
|
||
- Numbers: "2025" ✓
|
||
- Score: 95/100
|
||
|
||
### Meta Description Score (0-100)
|
||
|
||
**What's analyzed:**
|
||
- Presence (missing = 0 score)
|
||
- Length (target: 120-160 characters)
|
||
- Call-to-action (learn, discover, find, check, etc.)
|
||
|
||
**Optimal meta example:**
|
||
"Discover the best VPN services for 2025. Compare 50+ options, learn about encryption, and find the perfect VPN for your needs. Updated monthly."
|
||
- Length: 149 characters ✓
|
||
- CTA: "Discover", "Compare", "learn", "find" ✓
|
||
- Score: 90/100
|
||
|
||
### Overall Score (0-100)
|
||
|
||
```
|
||
Overall = (Title Score × 40%) + (Meta Score × 60%)
|
||
```
|
||
|
||
Meta description weighted heavier because it directly impacts click-through rates from search results.
|
||
|
||
---
|
||
|
||
## Action Plan
|
||
|
||
### 1. Review Results
|
||
|
||
```bash
|
||
# Open the summary report
|
||
open output/reports/seo_analysis_*.md
|
||
|
||
# Or open the detailed CSV
|
||
open output/reports/seo_analysis_*.csv
|
||
```
|
||
|
||
### 2. Prioritize by Score
|
||
|
||
**High Priority (Score < 50):**
|
||
- Title issues OR missing/weak meta
|
||
- Implement AI recommendations immediately
|
||
- Estimated impact: 10-20% CTR improvement
|
||
|
||
**Medium Priority (Score 50-75):**
|
||
- Minor title or meta issues
|
||
- Apply recommendations when convenient
|
||
- Estimated impact: 5-10% CTR improvement
|
||
|
||
**Low Priority (Score > 75):**
|
||
- Already optimized
|
||
- Only update if major content changes
|
||
|
||
### 3. Batch Implementation
|
||
|
||
**For WordPress:**
|
||
|
||
1. Go to WordPress admin
|
||
2. Edit post
|
||
3. Update title (if recommended)
|
||
4. Update meta description in Yoast SEO or All in One SEO:
|
||
- Yoast: Bottom of editor → "SEO" tab → Meta description
|
||
- AIOSEO: Right sidebar → "General" → Description
|
||
|
||
5. Save post
|
||
|
||
**OR use bulk operations** if your SEO plugin supports it.
|
||
|
||
### 4. Monitor Impact
|
||
|
||
Re-run the analyzer in 30 days:
|
||
|
||
```bash
|
||
python scripts/multi_site_seo_analyzer.py
|
||
```
|
||
|
||
Track improvements:
|
||
- Average score increase
|
||
- Fewer posts with score < 50
|
||
- Posts moved from "Missing meta" to "Strong meta"
|
||
|
||
---
|
||
|
||
## Cost Estimation
|
||
|
||
### AI Recommendation Costs
|
||
|
||
Using Claude 3.5 Sonnet via OpenRouter ($3 input / $15 output per 1M tokens):
|
||
|
||
**Scenario 1: 10 posts with AI**
|
||
- ~2,500 input tokens per post × 10 = 25,000 input tokens
|
||
- ~500 output tokens per post × 10 = 5,000 output tokens
|
||
- Cost: (25,000 × $3 + 5,000 × $15) / 1,000,000 = **$0.105** (~11¢)
|
||
|
||
**Scenario 2: 50 posts with AI**
|
||
- 125,000 input + 25,000 output tokens
|
||
- Cost: **$0.525** (~52¢)
|
||
|
||
**Scenario 3: No AI (--no-ai flag)**
|
||
- Cost: **$0.00**
|
||
|
||
### Monthly Scenarios
|
||
|
||
| Scenario | Frequency | Cost/Month |
|
||
|----------|-----------|-----------|
|
||
| No AI | Weekly | $0 |
|
||
| 10 posts/week | Weekly | ~€0.40 |
|
||
| 20 posts/week | Weekly | ~€0.80 |
|
||
| 50 posts/month | Once | ~€0.50 |
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### "Connection refused" on a site
|
||
|
||
**Problem:** WordPress site is down or credentials are wrong.
|
||
|
||
**Solutions:**
|
||
1. Check site URL is correct (https, www vs no-www)
|
||
2. Verify credentials: Try logging in manually
|
||
3. Check if site has REST API enabled: `https://yoursite.com/wp-json/`
|
||
4. Skip that site temporarily (remove from config, re-run)
|
||
|
||
### "No posts found"
|
||
|
||
**Problem:** API returns 0 posts.
|
||
|
||
**Solutions:**
|
||
1. Verify credentials have permission to read posts
|
||
2. Check if posts exist on the site
|
||
3. Try without authentication (remove from config)
|
||
4. Check if REST API is disabled
|
||
|
||
### AI recommendations are empty
|
||
|
||
**Problem:** OpenRouter API call failed.
|
||
|
||
**Solutions:**
|
||
1. Verify OPENROUTER_API_KEY is set: `echo $OPENROUTER_API_KEY`
|
||
2. Check API key is valid (not expired, has credits)
|
||
3. Try with --no-ai flag to verify the rest works
|
||
4. Check internet connection
|
||
|
||
### Memory issues with 1000+ posts
|
||
|
||
**Problem:** Script runs out of memory.
|
||
|
||
**Solutions:**
|
||
1. Run --no-ai version first (lighter)
|
||
2. Analyze one site at a time (modify config temporarily)
|
||
3. Increase system memory or close other apps
|
||
|
||
---
|
||
|
||
## Advanced Usage
|
||
|
||
### Analyze One Site
|
||
|
||
Temporarily comment out sites in config.py or create a custom script:
|
||
|
||
```python
|
||
from scripts.multi_site_seo_analyzer import MultiSiteSEOAnalyzer
|
||
from scripts.config import Config
|
||
|
||
analyzer = MultiSiteSEOAnalyzer()
|
||
|
||
# Override to just one site
|
||
analyzer.sites_config = {
|
||
'mistergeek.net': Config.WORDPRESS_SITES['mistergeek.net']
|
||
}
|
||
|
||
analyzer.run(use_ai=True, top_n=20)
|
||
```
|
||
|
||
### Export to Google Sheets
|
||
|
||
1. Download the CSV
|
||
2. Open Google Sheets
|
||
3. File → Import → Upload CSV
|
||
4. Share link with team
|
||
5. Filter by site or score
|
||
6. Add "Completed" checkbox column
|
||
7. Track progress as you optimize
|
||
|
||
### Integrate with WordPress via Zapier
|
||
|
||
1. Export CSV from analyzer
|
||
2. Use Zapier to trigger WordPress post updates
|
||
3. Automatically update meta descriptions for high-priority posts
|
||
4. (Advanced - requires Zapier Pro)
|
||
|
||
---
|
||
|
||
## Examples
|
||
|
||
### Example 1: Post with Low Title Score
|
||
|
||
```
|
||
Title: "VPN"
|
||
Title Issues: Too short (3), Missing power word, No number
|
||
Title Score: 10/100
|
||
|
||
Recommendation: Expand title to include benefit and year
|
||
Better Title: "Best VPN Services 2025: Complete Guide"
|
||
```
|
||
|
||
### Example 2: Post with Missing Meta
|
||
|
||
```
|
||
Meta Description: [MISSING]
|
||
Meta Score: 0/100
|
||
|
||
AI Recommendation:
|
||
"Write a meta description: 'Learn about the best VPN services for 2025.
|
||
Compare 50+ providers, understand encryption, and choose the right VPN
|
||
for your needs. Updated weekly.' (150 characters)"
|
||
```
|
||
|
||
### Example 3: Strong Post (No Changes Needed)
|
||
|
||
```
|
||
Title: "The Complete Guide to NordVPN: Features, Pricing, and Reviews"
|
||
Title Issues: None
|
||
Title Score: 95/100
|
||
|
||
Meta: "Comprehensive review of NordVPN including speed tests, security features, pricing plans, and user reviews. Find out if NordVPN is right for you."
|
||
Meta Issues: None
|
||
Meta Score: 95/100
|
||
|
||
Overall Score: 95/100
|
||
Status: No changes needed ✓
|
||
```
|
||
|
||
---
|
||
|
||
## FAQ
|
||
|
||
**Q: How often should I run this?**
|
||
A: Monthly or after publishing 10+ new posts. More frequent for highly competitive topics.
|
||
|
||
**Q: Will changing titles affect SEO?**
|
||
A: No, titles can be improved without penalty. The URL stays the same, so search rankings are preserved.
|
||
|
||
**Q: Should I update all weak meta descriptions?**
|
||
A: Prioritize posts with traffic. Update high-traffic posts first for maximum impact.
|
||
|
||
**Q: Can I use this on a site with 5000+ posts?**
|
||
A: Yes, but consider:
|
||
- Using --no-ai on first run (faster)
|
||
- Running once per month instead of weekly
|
||
- Focusing AI analysis on high-traffic posts only
|
||
|
||
**Q: What if my site uses a different SEO plugin?**
|
||
A: The script looks for common meta description fields. If it finds nothing, add one manually. Plugin doesn't matter; the meta description HTML is standard.
|
||
|
||
---
|
||
|
||
## Next Steps
|
||
|
||
1. **Run the analyzer:** `python scripts/multi_site_seo_analyzer.py`
|
||
2. **Review the report:** Open `output/reports/seo_analysis_*_summary.md`
|
||
3. **Prioritize:** Identify posts with score < 50
|
||
4. **Implement:** Update titles and meta descriptions
|
||
5. **Track:** Re-run in 30 days to measure improvement
|
||
6. **Monitor:** Watch Google Search Console for CTR improvements
|
||
|
||
Ready to optimize? Let's go! 🚀
|