# Unified Template Implementation Guide


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

## Overview

This document provides a comprehensive guide for implementing the unified comparison page template that consolidates the "details" and "nodetails" templates into a single data-driven template.

## Implementation Strategy

### Approach

Instead of manually creating a 2300+ line template from scratch, the recommended approach is:

1. **Copy the base template**: `cp v2/pages/compare_template_details.php v2/pages/compare_template_unified.php`
2. **Add data loading at top**: Include competitor data file and helper functions
3. **Replace placeholders systematically**: Use PHP variables from $competitorData array
4. **Implement conditional Details section**: Use PHP if/else for has_details flag
5. **Integrate helper functions**: Replace hardcoded HTML with function calls

### Key Modifications Required

#### 1. Header Section (Lines 1-72)

**Add at top (after session_start):**

```php
<?php
session_start();

/**
 * Unified Comparison Page Template
 *
 * This template handles both competitors with and without Details sections
 * using conditional rendering based on $competitorData['has_details'].
 *
 * USAGE:
 * 1. Create competitor data file in v2/data/competitors/{slug}.php
 * 2. Copy this template to v2/pages/compare_{slug}.php
 * 3. Update the data file path below
 * 4. Test the page
 */

// Load competitor data
$competitorData = require __DIR__ . '/../data/competitors/clockin_example.php';  // UPDATE THIS PATH

// Load helper functions
require_once __DIR__ . '/../helpers/comparison_template_helpers.php';

// Validate data
$validation = validateCompetitorData($competitorData);
if (!$validation['valid']) {
    die('<h1>Error: Invalid Competitor Data</h1><pre>' . implode("\n", $validation['errors']) . '</pre>');
}

// Apply defaults
$competitorData = applyDefaultValues($competitorData);

// Extract commonly used variables for convenience
$name = $competitorData['name'];
$slug = $competitorData['slug'];
$category = $competitorData['category'];
$focus = $competitorData['focus'];
$target = $competitorData['target'];
$logo = $competitorData['logo'];
$rating = $competitorData['rating'];
$description = $competitorData['description'];
$description_heading = $competitorData['description_heading'];
$pricing = $competitorData['pricing'];
$hasDetails = $competitorData['has_details'];
$details = $competitorData['details'];
$faq = $competitorData['faq'];
$schema = $competitorData['schema'];
?>
```

#### 2. Meta Tags Section (Lines ~79-118)

**Replace with helper function:**

```php
<?php echo generateMetaTags($competitorData); ?>
<?php echo generateOGTags($competitorData); ?>
```

**Add canonical and preload:**

```php
<link rel="canonical" href="https://www.ordio.com/alternativen/<?php echo $slug; ?>-vergleich">
<link rel="stylesheet" href="/v2/css/comparison-pages.min.css?v=<?php echo filemtime(__DIR__ . '/../css/comparison-pages.min.css'); ?>" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="/v2/css/comparison-pages.min.css"></noscript>
<link rel="preload" href="<?php echo $logo['paths']['vergleich_160w']; ?>" as="image" fetchpriority="high">
```

#### 3. Schema Section (Lines ~119-290)

**Replace entire JSON-LD with:**

```php
<script type="application/ld+json">
<?php
// Generate schema (note: Some PHP code like ordio_get_page_last_modified_iso()
// needs to be executed, so we can't fully generate this)
$jsonLd = [
    '@context' => 'https://schema.org',
    '@graph' => [
        // ... (Use structure from helper function but with PHP execution for dates)
    ]
];

// Output with FAQ schema items
echo json_encode($jsonLd, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
?>
</script>
```

**Note**: The schema generation is complex due to dynamic PHP functions like `ordio_get_page_last_modified_iso()`. The helper provides the structure, but final schema needs manual integration.

#### 4. Hero Section (Lines ~293-675)

**Replace competitor logo:**

```php
<img src="<?php echo $logo['paths']['vergleich_160w']; ?>"
     srcset="<?php echo $logo['paths']['vergleich_160w']; ?> 160w,
             <?php echo $logo['paths']['vergleich_320w']; ?> 320w"
     sizes="(max-width: 640px) 160px, 160px"
     alt="<?php echo sanitizeOutput($logo['alt']); ?>"
     class="max-h-8 max-w-full object-contain <?php echo $logo['class']; ?>"
     width="160" height="32"
     fetchpriority="high"
     decoding="async">
```

**Replace hero text:**

```php
<h1 class="text-4xl sm:text-6xl font-gilroybold leading-[102%] tracking-[-1.5px] mb-4 inline-block p-1">
    <?php echo sanitizeOutput($name); ?> Alternativen: <span class="text-ordio-blue">Vergleich</span> & <span class="text-ordio-blue">Bewertung</span> 2025
</h1>
<p class="text-lg text-gray-600 leading-relaxed">
    Welche Alternativen zu <?php echo sanitizeOutput($name); ?> gibt es? Entdecke den detaillierten Vergleich zwischen Ordio und <?php echo sanitizeOutput($name); ?>: Preise, Funktionen und Bewertungen im direkten Vergleich. Finde die beste <?php echo sanitizeOutput($category); ?> Alternative für <?php echo sanitizeOutput($focus); ?>.
</p>
```

#### 5. Comparison Section Heading (Lines ~700-709)

**Replace:**

```php
<h2 class="text-5xl sm:text-7xl font-gilroybold leading-[102%] tracking-[-1.5px] mb-6 inline-block p-1 text-[#333333]">
    Ordio vs. <?php echo sanitizeOutput($name); ?>
    <br><span class="block sm:inline text-2xl sm:text-4xl font-inter500 font-normal align-middle">Funktionsvergleich im Überblick</span>
</h2>
```

#### 6. Competitor Column Header (Lines ~928-963)

**Replace logo:**

```php
<img src="<?php echo $logo['paths']['vergleich_160w']; ?>"
     srcset="<?php echo $logo['paths']['vergleich_160w']; ?> 160w,
             <?php echo $logo['paths']['vergleich_320w']; ?> 320w"
     sizes="(max-width: 640px) 160px, 160px"
     alt="<?php echo sanitizeOutput($logo['alt']); ?>"
     class="max-h-8 max-w-full object-contain <?php echo $logo['class']; ?>"
     width="160" height="32"
     fetchpriority="high"
     decoding="async">
```

**Replace rating display:**

```php
<?php echo renderStarRating($rating['overall']); ?>
<span class="ml-2 text-white text-sm font-medium"><?php echo number_format($rating['overall'], 1, ',', '.'); ?></span>
</div>
<p class="text-gray-200 text-sm"><?php echo $rating['review_count']; ?> Bewertungen</p>
```

#### 7. Product Description (Lines ~1000-1008)

**Replace:**

```php
<div class="mb-6">
    <h4 class="text-lg font-semibold text-gray-900 mb-3"><?php echo sanitizeOutput($description_heading); ?></h4>
    <p class="text-gray-600 leading-relaxed">
        <?php echo sanitizeOutput($description); ?><br><br><br>
    </p>
</div>
```

#### 8. Details Section (Lines ~1010-1065) - CRITICAL

**Replace entire section with conditional:**

```php
<?php echo renderDetailsSection($competitorData); ?>
```

This single line handles both cases:

- If `$hasDetails === true`: Renders expandable Details section
- If `$hasDetails === false`: Renders invisible placeholder div

#### 9. Star Rating Distribution (Lines ~1067-1137)

**Replace with:**

```php
<?php echo renderRatingDistribution($competitorData); ?>
```

#### 10. Category Ratings (Lines ~1139-1221)

**Replace with:**

```php
<?php echo renderCategoryRatings($competitorData); ?>
```

#### 11. Pricing Section (Lines ~1223-1269)

**Replace with:**

```php
<?php echo renderPricingPlans($competitorData); ?>
```

#### 12. FAQ Section (Lines ~1845-2100)

**Replace FAQ title:**

```php
<h2 class="text-4xl font-gilroybold mb-8 text-center text-ordio-blue">
    <?php echo sanitizeOutput($faq['title']); ?>
</h2>
```

**Replace FAQ items:**

```php
<div class="max-w-4xl mx-auto space-y-4">
    <?php echo renderFAQItems($competitorData); ?>

    <!-- Note: FAQs will be optimized based on SEO reports per competitor -->
    <!-- Current items are placeholders for structure -->
</div>
```

## Complete Replacement Map

### Placeholders → PHP Variables

| Placeholder                       | Replacement                                                     |
| --------------------------------- | --------------------------------------------------------------- |
| `{COMPETITOR}`                    | `<?php echo sanitizeOutput($name); ?>`                          |
| `{competitor}`                    | `<?php echo $slug; ?>`                                          |
| `{competitor-slug}`               | `<?php echo $slug; ?>`                                          |
| `{COMPETITOR_RATING}`             | `<?php echo number_format($rating['overall'], 1, ',', '.'); ?>` |
| `{COMPETITOR_REVIEWS}`            | `<?php echo $rating['review_count']; ?>`                        |
| `{COMPETITOR_DESCRIPTION}`        | `<?php echo sanitizeOutput($description); ?>`                   |
| `{COMPETITOR_CATEGORY}`           | `<?php echo sanitizeOutput($category); ?>`                      |
| `{COMPETITOR_FOCUS}`              | `<?php echo sanitizeOutput($focus); ?>`                         |
| `{COMPETITOR_TARGET}`             | `<?php echo sanitizeOutput($target); ?>`                        |
| `{COMPETITOR_LOGO_ALT}`           | `<?php echo sanitizeOutput($logo['alt']); ?>`                   |
| `{COMPETITOR_LOGO_CLASS}`         | `<?php echo $logo['class']; ?>`                                 |
| `{COMPETITOR_DETAILS_BUTTON}`     | `<?php echo sanitizeOutput($details['button_text']); ?>`        |
| `{COMPETITOR_PRICE_STARTING}`     | `<?php echo $pricing['starting_price']; ?>`                     |
| `{COMPETITOR_PRICE_UNIT}`         | `<?php echo sanitizeOutput($pricing['unit']); ?>`               |
| `{COMPETITOR_FAQ_TITLE}`          | `<?php echo sanitizeOutput($faq['title']); ?>`                  |
| `{COMPETITOR_SCHEMA_NAME}`        | `<?php echo sanitizeOutput($schema['name']); ?>`                |
| `{COMPETITOR_SCHEMA_DESCRIPTION}` | `<?php echo sanitizeOutput($schema['description']); ?>`         |

### Sections → Helper Functions

| Section             | Helper Function                             |
| ------------------- | ------------------------------------------- |
| Star rating display | `renderStarRating($rating['overall'])`      |
| Rating distribution | `renderRatingDistribution($competitorData)` |
| Category ratings    | `renderCategoryRatings($competitorData)`    |
| Pricing plans       | `renderPricingPlans($competitorData)`       |
| Details section     | `renderDetailsSection($competitorData)`     |
| FAQ items           | `renderFAQItems($competitorData)`           |
| Meta tags           | `generateMetaTags($competitorData)`         |
| OG tags             | `generateOGTags($competitorData)`           |

## Testing Checklist

After implementing the unified template:

- [ ] Test with clockin_example.php (has_details = true)
- [ ] Test with personio_example.php (has_details = false)
- [ ] Verify Details section expands/collapses correctly
- [ ] Verify invisible placeholder maintains height alignment
- [ ] Check all meta tags render correctly
- [ ] Validate schema with Google Rich Results Test
- [ ] Test responsive design on mobile/tablet/desktop
- [ ] Verify all images load with correct srcset/sizes
- [ ] Check Alpine.js interactions work
- [ ] Verify no console errors
- [ ] Compare output with existing clockin page

## Migration Strategy

1. **Phase 1**: Create unified template and test with 2-3 competitors
2. **Phase 2**: Migrate 5 existing pages and compare outputs
3. **Phase 3**: Bulk migrate remaining pages
4. **Phase 4**: Deprecate old templates

## Performance Considerations

- Logo preload maintained for LCP optimization
- Helper functions add minimal overhead
- Data validation only runs once at page load
- No runtime performance impact vs. hardcoded templates

## Maintenance Benefits

- **Single source of truth**: One template to maintain
- **Data-driven**: Changes to data don't require template edits
- **Consistent output**: All pages use same structure
- **Easy updates**: Fix bugs once, applies to all pages
- **Type safety**: Validation catches data errors early
