# How to Create New Comparison Pages


**Last Updated:** 2025-11-20

## Quick Process Overview

Creating a new comparison page takes **~5 minutes** and involves 3 simple steps:

1. **Create competitor data file** (3 minutes)
2. **Generate page file** (10 seconds)
3. **Test & validate** (1 minute)

---

## Step-by-Step Guide

### Step 1: Create Competitor Data File

**1.1 Copy the example template:**

```bash
cp v2/data/competitors/clockin_example.php v2/data/competitors/YOUR_COMPETITOR_SLUG.php
```

**1.2 Open the new file and fill in competitor data:**

```php
<?php
require_once __DIR__ . '/../competitor_template_data.php';

$competitorData = [
    // === BASIC INFO ===
    'name' => 'Competitor Name',           // Display name (e.g., "Clockin")
    'slug' => 'competitor-slug',           // URL slug (lowercase, hyphens OK)
    'category' => 'Zeiterfassung',         // Product category
    'focus' => 'What they focus on',        // Use case/focus
    'target' => 'Target audience',         // Target market
    
    // === LOGO ===
    'logo' => [
        'alt' => 'competitorname',
        'class' => '',  // or 'brightness-0 invert' if logo needs inversion
        'paths' => [
            'vergleich_160w' => '/v2/img/alternativen/competitor-slug-vergleich-logo-160w.webp',
            'vergleich_320w' => '/v2/img/alternativen/competitor-slug-vergleich-logo-320w.webp',
        ]
    ],
    
    // === RATINGS ===
    'rating' => [
        'overall' => 4.5,                  // Overall rating (0-5)
        'review_count' => 250,             // Total reviews
        'distribution' => [                 // Star distribution (must sum to review_count)
            '5' => ['count' => 150, 'percentage' => 60],
            '4' => ['count' => 75, 'percentage' => 30],
            '3' => ['count' => 20, 'percentage' => 8],
            '2' => ['count' => 5, 'percentage' => 2],
            '1' => ['count' => 0, 'percentage' => 0],
        ],
        'category_ratings' => [            // OMR-style category ratings
            'benutzerfreundlichkeit' => ['score' => 9.0, 'category' => 'Zeiterfassung', 'average' => 9],
            'erfuellung' => ['score' => 8.8, 'category' => 'Zeiterfassung', 'average' => 9.1],
            'kundensupport' => ['score' => 9.2, 'category' => 'Zeiterfassung', 'average' => 9.1],
            'einrichtung' => ['score' => 8.5, 'category' => 'Zeiterfassung', 'average' => 8.8]
        ]
    ],
    
    // === CONTENT ===
    'description' => 'Full product description paragraph...',
    'description_heading' => '',  // Optional, defaults to "Was ist {name}?"
    
    // === DATA UPDATE INFO ===
    'last_updated' => '2025-10-15',  // Last update date (YYYY-MM-DD)
    
    // === PRICING ===
    'pricing' => [
        'starting_price' => '9.99',
        'currency' => 'EUR',
        'unit' => 'pro User pro Monat',
        'plans' => [
            ['name' => 'Basic', 'description' => 'Essential features', 'price' => '9.99', 'unit' => 'User / Monat'],
            ['name' => 'Pro', 'description' => 'Advanced features', 'price' => '19.99', 'unit' => 'User / Monat'],
        ]
    ],
    
    // === DETAILS SECTION ===
    'has_details' => true,  // true = show Details section, false = invisible placeholder
    'details' => [
        'button_text' => 'CompetitorName Details',
        'features' => ['Feature 1', 'Feature 2', 'Feature 3'],
        'integrations' => ['Integration 1', 'Integration 2'],
        'special' => ['Special thing 1', 'Special thing 2']
    ],
    
    // === FAQ ===
    'faq' => [
        'title' => '',  // Auto-generated if empty
        'items' => [
            ['question' => 'Was kostet CompetitorName?', 'answer' => 'Answer text...']
        ]
    ],
    
    // === SCHEMA ===
    'schema' => [
        'name' => 'CompetitorName',  // May differ from display name
        'description' => 'Schema description for SEO...'
    ]
];

// Validate and return
$validation = validateCompetitorData($competitorData);
if (!$validation['valid']) {
    error_log('Data validation failed:');
    error_log(print_r($validation['errors'], true));
}

$competitorData = applyDefaultValues($competitorData);
return $competitorData;
?>
```

**Key points:**
- Update `slug` everywhere (in filename, logo paths, etc.)
- Rating distribution counts must sum to `review_count`
- Set `has_details` to `false` for well-known competitors (like Personio)
- Set `last_updated` to today's date when creating/updating

---

### Step 2: Generate Page File

**Option A: Use the generator script (Recommended)**

```bash
php scripts/generate_comparison_page.php competitor-slug
```

This will:
- ✅ Validate your data
- ✅ Generate the page file automatically
- ✅ Show a summary and checklist

**Option B: Manual copy**

```bash
cp v2/pages/compare_template_unified.php v2/pages/compare_competitor-slug.php
```

Then edit the new file and update line ~27:

```php
$competitorData = require __DIR__ . '/../data/competitors/competitor-slug.php';
```

---

### Step 3: Test & Validate

**3.1 Test in browser:**

Visit: `http://localhost:8003/v2/pages/compare_competitor-slug.php`

**Checklist:**
- [ ] Page loads without errors
- [ ] Logo displays correctly
- [ ] Ratings show properly
- [ ] Pricing section renders
- [ ] Details section works (if `has_details = true`)
- [ ] FAQ section displays
- [ ] No console errors
- [ ] Responsive design works

**3.2 Validate data:**

```bash
php scripts/validate_competitor_data.php v2/data/competitors/competitor-slug.php
```

**3.3 Test schema:**

1. Copy the page URL
2. Visit: https://search.google.com/test/rich-results
3. Paste URL and test
4. Verify no errors

---

## Common Scenarios

### Scenario 1: Competitor WITH Details Section

Use when competitor has notable features/integrations worth highlighting:

```php
'has_details' => true,
'details' => [
    'button_text' => 'CompetitorName Details',
    'features' => ['Feature 1', 'Feature 2'],
    'integrations' => ['DATEV', 'Integration 2'],
    'special' => ['Special characteristic']
]
```

**Example:** Clockin (has DATEV integrations, digital forms, etc.)

### Scenario 2: Competitor WITHOUT Details Section

Use for well-known competitors that don't need detailed breakdown:

```php
'has_details' => false,
'details' => [
    'button_text' => '',
    'features' => [],
    'integrations' => [],
    'special' => []
]
```

**Example:** Personio (well-known, no need for detailed feature list)

### Scenario 3: "On Request" Pricing

When competitor doesn't publish prices:

```php
'pricing' => [
    'starting_price' => '0.00',
    'currency' => 'EUR',
    'unit' => 'auf Anfrage',
    'plans' => [
        ['name' => 'Professional', 'description' => 'For growing teams', 'price' => 'Auf Anfrage', 'unit' => '']
    ]
]
```

### Scenario 4: Logo Needs Inversion

When logo is dark and needs to be inverted on gray background:

```php
'logo' => [
    'alt' => 'competitorname',
    'class' => 'brightness-0 invert',  // Inverts dark logo
    'paths' => [...]
]
```

**Example:** Personio (dark logo on gray background)

---

## Data Sources

**Where to get competitor information:**

- **Ratings & Reviews**: OMR Reviews, Capterra, G2, Trustpilot
- **Pricing**: Competitor website pricing page
- **Features**: Competitor product/features page
- **Description**: Competitor about page, marketing materials
- **Category Ratings**: OMR Reviews (specific category breakdowns)

---

## File Structure

```
v2/
├── data/
│   └── competitors/
│       └── competitor-slug.php          ← Your data file
├── pages/
│   └── compare_competitor-slug.php      ← Generated page file
└── img/
    └── alternativen/
        ├── competitor-slug-vergleich-logo-160w.webp
        └── competitor-slug-vergleich-logo-320w.webp
```

---

## Common Mistakes to Avoid

### ❌ Wrong: Slug mismatch

```php
// File: v2/data/competitors/personio.php
'slug' => 'clockin',  // Wrong! Should be 'personio'
```

### ✅ Correct:

```php
// File: v2/data/competitors/personio.php
'slug' => 'personio',  // Matches filename
```

### ❌ Wrong: Rating distribution doesn't sum

```php
'review_count' => 250,
'distribution' => [
    '5' => ['count' => 150, 'percentage' => 60],
    '4' => ['count' => 50, 'percentage' => 20],  // Total: 200, not 250!
]
```

### ✅ Correct:

```php
'review_count' => 250,
'distribution' => [
    '5' => ['count' => 150, 'percentage' => 60],  // 150
    '4' => ['count' => 75, 'percentage' => 30],   // +75
    '3' => ['count' => 20, 'percentage' => 8],    // +20
    '2' => ['count' => 5, 'percentage' => 2],     // +5
    '1' => ['count' => 0, 'percentage' => 0],     // +0
    // Total: 250 ✓
]
```

### ❌ Wrong: has_details = true but empty details

```php
'has_details' => true,
'details' => [
    'button_text' => '',  // Will cause validation error!
    'features' => [],
]
```

### ✅ Correct:

```php
'has_details' => true,
'details' => [
    'button_text' => 'CompetitorName Details',
    'features' => ['At least one feature'],
    'integrations' => ['At least one integration'],
    'special' => ['At least one special thing']
]
```

---

## Quick Reference

### Required Fields

- `name` - Display name
- `slug` - URL slug (lowercase, hyphens OK)
- `category` - Product category
- `focus` - Focus/use case
- `target` - Target audience
- `logo` - Logo paths and alt text
- `rating` - Overall rating, review count, distribution, category ratings
- `description` - Product description
- `last_updated` - Update date (YYYY-MM-DD)
- `pricing` - Starting price, currency, unit, plans
- `has_details` - Boolean (true/false)
- `details` - Details section data (can be empty if has_details = false)
- `faq` - FAQ items (at least 1)
- `schema` - Schema name and description

### Optional Fields (with defaults)

- `description_heading` - Defaults to "Was ist {name}?"
- `faq.title` - Defaults to "Häufige Fragen zu {name} & {category} Alternativen 2025"

---

## Troubleshooting

**Problem: Page shows "Invalid Competitor Data"**
→ Run validation script: `php scripts/validate_competitor_data.php v2/data/competitors/competitor-slug.php`

**Problem: Logo not displaying**
→ Check image paths and verify files exist at `/v2/img/alternativen/`

**Problem: Details section not expanding**
→ Check browser console for JavaScript errors (Alpine.js)

**Problem: Rating percentages don't add up**
→ Recalculate percentages (sum should be 98-102% due to rounding)

**Problem: Schema validation fails**
→ Check that all required schema fields are filled (name, description)

---

## Next Steps After Creation

1. ✅ **Test page** in browser
2. ✅ **Validate schema** with Google Rich Results Test
3. ✅ **Check performance** (PageSpeed Insights)
4. ✅ **Review content** for accuracy
5. ✅ **Optimize FAQs** based on SEO reports (add more later)
6. ✅ **Update last_updated** date when you make changes

---

## Resources

- **Quick Start Guide**: `docs/guides/COMPARISON_PAGES_QUICK_START.md`
- **Full Documentation**: `docs/guides/COMPARISON_PAGES_UNIFIED_TEMPLATE.md`
- **Data Template**: `v2/data/competitor_template_data.php`
- **Examples**: 
  - `v2/data/competitors/clockin_example.php` (with details)
  - `v2/data/competitors/personio_example.php` (without details)
- **Generator Script**: `scripts/generate_comparison_page.php`
- **Validation Script**: `scripts/validate_competitor_data.php`

---

## Example: Creating "Shiftbase" Comparison Page

```bash
# 1. Copy template
cp v2/data/competitors/clockin_example.php v2/data/competitors/shiftbase.php

# 2. Edit v2/data/competitors/shiftbase.php and fill in data
# (Update name, slug, ratings, pricing, etc.)

# 3. Generate page
php scripts/generate_comparison_page.php shiftbase

# 4. Test
# Visit: http://localhost:8003/v2/pages/compare_shiftbase.php

# 5. Validate
php scripts/validate_competitor_data.php v2/data/competitors/shiftbase.php
```

That's it! Your new comparison page is ready. 🎉

