# Comparison Pages Unified Template Usage Guide


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

## Overview

This guide provides complete instructions for using the unified comparison page template system to create new competitor comparison pages quickly and efficiently.

## Quick Start

### Creating a New Comparison Page (5 Steps)

1. **Create competitor data file**
2. **Copy and rename template**
3. **Update data file path**
4. **Generate images**
5. **Test and validate**

## Step 1: Create Competitor Data File

### 1.1 Copy Template Structure

```bash
cp v2/data/competitors/clockin_example.php v2/data/competitors/{competitor_slug}.php
```

### 1.2 Fill In Competitor Data

Open the new file and fill in all fields with competitor-specific data.

**Example for a competitor WITH Details section:**

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

$competitorData = [
    // Basic Info
    'name' => 'ToolName',
    'slug' => 'toolname',
    'category' => 'Zeiterfassung',
    'focus' => 'Schichtplanung, Zeiterfassung & Personalmanagement',
    'target' => 'kleine und mittlere Unternehmen',

    // Logo & Images
    'logo' => [
        'alt' => 'toolname',
        'class' => '',  // Use "brightness-0 invert" if logo needs inversion
        'paths' => [
            'vergleich_160w' => '/v2/img/alternativen/toolname-vergleich-logo-160w.webp',
            'vergleich_320w' => '/v2/img/alternativen/toolname-vergleich-logo-320w.webp',
        ]
    ],

    // Ratings
    'rating' => [
        'overall' => 4.5,
        'review_count' => 250,
        'distribution' => [
            '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' => [
            '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 competitor description here...',
    'description_heading' => 'Custom heading or leave empty for default',

    // Pricing
    'pricing' => [
        'starting_price' => '5.99',
        'currency' => 'EUR',
        'unit' => 'pro User pro Monat',
        'plans' => [
            [
                'name' => 'Basic',
                'description' => 'Essential features',
                'price' => '5.99',
                'unit' => 'User / Monat'
            ],
            // Add more plans...
        ]
    ],

    // Details Section - Set has_details based on competitor
    'has_details' => true,  // or false for well-known competitors
    'details' => [
        'button_text' => 'ToolName Details',
        'features' => [
            'Feature 1',
            'Feature 2',
            // ...
        ],
        'integrations' => [
            'Integration 1',
            'Integration 2',
            // ...
        ],
        'special' => [
            'Special characteristic 1',
            'Special characteristic 2',
            // ...
        ]
    ],

    // FAQ - Placeholder for SEO optimization
    'faq' => [
        'title' => '',  // Will default to standard pattern
        'items' => [
            [
                'question' => 'Was kostet ToolName?',
                'answer' => 'Answer here...'
            ]
            // More FAQs will be added based on SEO reports
        ]
    ],

    // Schema
    'schema' => [
        'name' => 'ToolName',  // May differ from display name
        'description' => 'Schema description...'
    ]
];

$validation = validateCompetitorData($competitorData);
if (!$validation['valid']) {
    error_log('ToolName data validation failed:');
    error_log(print_r($validation['errors'], true));
}

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

**Example for a competitor WITHOUT Details section:**

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

$competitorData = [
    // ... same structure as above but:

    'has_details' => false,  // No Details section
    'details' => [
        'button_text' => '',
        'features' => [],
        'integrations' => [],
        'special' => []
    ],

    // ... rest of the data
];

return $competitorData;
?>
```

### 1.3 Validate Data

Run validation script:

```bash
php scripts/validate_competitor_data.php v2/data/competitors/{competitor_slug}.php
```

## Step 2: Generate Images

### 2.1 Prepare Source Images

Create two source images:

1. **Comparison logo**: `{competitor}-vergleich-logo.webp` (320x64px recommended)
2. **Regular logo**: `{competitor}-logo.webp` (160x160px square)

Place in `v2/img/alternativen/`

### 2.2 Generate Responsive Variants

```bash
node scripts/generate_responsive_logos.js
```

This creates:

- `{competitor}-vergleich-logo-160w.webp`
- `{competitor}-vergleich-logo-320w.webp`
- `{competitor}-logo-64w.webp`, `80w`, `128w`, `160w`

## Step 3: Create Page File

### 3.1 Use Generator Script

```bash
php scripts/generate_comparison_page.php {competitor_slug}
```

This creates `v2/pages/compare_{competitor_slug}.php` with correct data file path.

### 3.2 Manual Creation (Alternative)

If generator script is not available:

```bash
cp v2/pages/compare_template_unified.php v2/pages/compare_{competitor_slug}.php
```

Then edit the data file path at the top:

```php
// Change this line:
$competitorData = require __DIR__ . '/../data/competitors/clockin_example.php';

// To:
$competitorData = require __DIR__ . '/../data/competitors/{competitor_slug}.php';
```

## Step 4: Test

### 4.1 Local Testing

Visit: `http://localhost:8003/v2/pages/compare_{competitor_slug}.php`

### 4.2 Validation Checklist

- [ ] Page loads without errors
- [ ] All competitor data displays correctly
- [ ] Logo loads with correct srcset
- [ ] Rating stars display correctly
- [ ] Pricing plans render properly
- [ ] Details section expands/collapses (if has_details = true)
- [ ] Or invisible placeholder maintains height (if has_details = false)
- [ ] FAQ section displays
- [ ] No console errors
- [ ] Responsive design works on mobile

### 4.3 Schema Validation

Test with Google Rich Results Test:
`https://search.google.com/test/rich-results`

### 4.4 Performance Check

- Logo should be preloaded (check Network tab)
- LCP < 2.5s
- CLS < 0.1
- No layout shifts

## Data Structure Reference

### Required Fields

**Top Level:**

- `name` - Display name
- `slug` - URL slug
- `category` - Product category
- `focus` - Focus/use case
- `target` - Target audience
- `logo` - Logo data
- `rating` - Rating data
- `description` - Product description
- `pricing` - Pricing data
- `has_details` - Boolean flag
- `details` - Details data (can be empty if has_details = false)
- `faq` - FAQ data
- `schema` - Schema data

**Logo Object:**

- `alt` - Alt text
- `class` - CSS classes
- `paths.vergleich_160w` - Path to 160w image
- `paths.vergleich_320w` - Path to 320w image

**Rating Object:**

- `overall` - Overall rating (0-5)
- `review_count` - Total reviews
- `distribution` - Array of 5 star levels with count/percentage
- `category_ratings` - 4 category ratings (benutzerfreundlichkeit, erfuellung, kundensupport, einrichtung)

**Pricing Object:**

- `starting_price` - Starting price
- `currency` - Currency code (usually EUR)
- `unit` - Price unit
- `plans` - Array of pricing plans

### Optional Fields

- `description_heading` - Defaults to "Was ist {name}?"
- `faq.title` - Defaults to standard pattern
- `schema.name` - Defaults to `name`
- `schema.description` - Defaults to `description`

## Common Patterns

### Deciding has_details Value

**Use `has_details = true` when:**

- Competitor has notable features/integrations to showcase
- Competitor has special characteristics worth highlighting
- Competitor is less well-known and needs context
- Example: Clockin (has DATEV integrations, digital forms)

**Use `has_details = false` when:**

- Competitor is well-known (doesn't need feature breakdown)
- Competitor details are less relevant
- You want a simpler, cleaner competitor column
- Example: Personio (well-known HR software)

### Calculating Rating Distribution

Rating distribution must:

- Sum counts = review_count (±1 for rounding)
- Sum percentages ≈ 100% (±2% for rounding)

Example:

```php
'review_count' => 329,
'distribution' => [
    '5' => ['count' => 316, 'percentage' => 96],   // 316/329 = 96%
    '4' => ['count' => 12, 'percentage' => 4],     // 12/329 = 4%
    '3' => ['count' => 0, 'percentage' => 0],
    '2' => ['count' => 1, 'percentage' => 0.3],    // 1/329 = 0.3%
    '1' => ['count' => 0, 'percentage' => 0],
],
// Total: 316 + 12 + 0 + 1 + 0 = 329 ✓
// Total: 96 + 4 + 0 + 0.3 + 0 = 100.3% ✓ (within tolerance)
```

### Pricing for "On Request" Competitors

For competitors without public pricing:

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

### Logo Class for Dark Backgrounds

If competitor logo is dark and needs inversion on gray background:

```php
'logo' => [
    'class' => 'brightness-0 invert',
    // ...
]
```

Example: Personio logo

## Troubleshooting

### Validation Errors

**Error: "Rating distribution counts don't match review count"**

Check that sum of all distribution counts equals review_count.

**Error: "Missing required field"**

Ensure all required fields are present in data array.

**Error: "Invalid slug format"**

Slug must be lowercase alphanumeric with hyphens only.

### Display Issues

**Logo not displaying:**

- Check image paths are correct
- Verify image files exist
- Check srcset syntax

**Details section not expanding:**

- Verify Alpine.js is loaded
- Check browser console for JavaScript errors
- Ensure x-data and x-show directives are present

**Height misalignment:**

- Check that ordioDetailsHeight is being set
- Verify Alpine.js height-changed event is dispatched
- Test with browser devtools

### Performance Issues

**Slow LCP:**

- Ensure logo preload tag is present
- Check logo file size (should be optimized WebP)
- Verify fetchpriority="high" on logo

**Console errors:**

- Check that all PHP files are properly included
- Verify data array structure is correct
- Look for missing closing tags

## Migration from Old Templates

### Migrating Existing Pages

**Option 1: Extract Data**

```bash
php scripts/data/extract_to_unified_format.php v2/pages/compare_existing.php
```

This creates a data file you can review and use.

**Option 2: Manual Migration**

1. Identify which old template was used (details or nodetails)
2. Extract all competitor-specific data
3. Create new data file with extracted data
4. Test new unified template page
5. Compare outputs side-by-side
6. Once verified, replace old page

### Comparison Checklist

When comparing old vs new page output:

- [ ] Meta tags identical
- [ ] Schema identical
- [ ] Hero section identical
- [ ] Ratings display identical
- [ ] Pricing section identical
- [ ] Details section behavior identical
- [ ] FAQ section identical
- [ ] Performance metrics comparable

## Best Practices

### Data Organization

- Keep data files organized in `v2/data/competitors/`
- Use clear, descriptive filenames matching slugs
- Add comments for complex data
- Validate data before using

### Content Quality

- Write clear, benefit-focused descriptions
- Use neutral language for competitors (no praise)
- Ensure FAQ answers provide value
- Keep pricing information current

### Maintenance

- Update competitor data files when pricing/features change
- Re-validate after data updates
- Test pages after template updates
- Keep schema current with Google requirements

### Performance

- Optimize images before generating variants
- Use WebP format for all images
- Preload LCP images
- Minimize inline PHP logic

## Additional Resources

- **Data Structure**: `v2/data/competitor_template_data.php`
- **Helper Functions**: `v2/helpers/comparison_template_helpers.php`
- **Examples**: `v2/data/competitors/clockin_example.php`, `personio_example.php`
- **Implementation Guide**: `docs/guides/UNIFIED_TEMPLATE_IMPLEMENTATION.md`
- **Analysis Document**: `docs/guides/COMPARISON_PAGES_TEMPLATE_ANALYSIS.md`
- **Cursor Rules**: `.cursor/rules/comparison-pages-core.mdc`

## Support

For questions or issues:

1. Check troubleshooting section above
2. Review example data files
3. Validate data structure
4. Check browser console for errors
5. Review implementation guide for template details
