# Comparison Pages Component Documentation


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

Complete documentation of all components used in comparison pages, their data structures, usage patterns, and customization options.

## Table of Contents

1. [ordio_comparison_content.php](#ordio_comparison_contentphp)
2. [compare_carousel.php](#compare_carouselphp)
3. [tools_data.php](#tools_dataphp)
4. [ordio_comparison_data.php](#ordio_comparison_dataphp)

## ordio_comparison_content.php

### Location

`v2/components/ordio_comparison_content.php`

### Purpose

Renders dynamic Ordio content for comparison pages. This component displays Ordio's product description, features, target audience, and pricing information in a standardized format.

### Data Source

Requires `v2/data/ordio_comparison_data.php` to be loaded first.

### Usage

```php
<?php include '../components/ordio_comparison_content.php'; ?>
```

### Structure

The component renders:

1. **Product Description**

   - Title: "Was ist Ordio?"
   - Content: Description of Ordio's value proposition

2. **Collapsible Details Section**
   - Title: "Ordio Details"
   - Expandable/collapsible via Alpine.js
   - Contains three subsections:
     - **Features:** List of Ordio features with checkmarks
     - **Target Audience:** Who Ordio is for
     - **Pricing Info:** Pricing model explanation

### Alpine.js Integration

The component uses Alpine.js for:

- **Expandable/Collapsible Functionality:** `x-data="{ open: false }"`
- **Height Synchronization:** Dispatches `height-changed` events to parent
- **Smooth Transitions:** Uses `x-transition` for animations

**Height Synchronization Code:**

```php
x-init="
    // Initial height dispatch
    $nextTick(() => {
        $dispatch('height-changed', { height: $el.offsetHeight });
    });

    // Watch for changes and trigger parent sync
    $watch('open', () => {
        $nextTick(() => {
            setTimeout(() => {
                $dispatch('height-changed', { height: $el.offsetHeight });
            }, 350); // Wait for x-transition animation
        });
    });
"
```

### Data Structure

Depends on `$ordio_data` array from `ordio_comparison_data.php`:

```php
$ordio_data = [
    'description' => [
        'title' => 'Was ist Ordio?',
        'content' => '...'
    ],
    'details' => [
        'title' => 'Ordio Details',
        'sections' => [
            'features' => [
                'title' => '...',
                'description' => '...',
                'features' => ['Feature 1', 'Feature 2', ...]
            ],
            'target_audience' => [
                'title' => '...',
                'content' => '...'
            ],
            'pricing_info' => [
                'title' => '...',
                'content' => '...'
            ]
        ]
    ]
];
```

### Customization

To update Ordio content across all comparison pages:

1. Edit `v2/data/ordio_comparison_data.php`
2. Update the `$ordio_data` array
3. Changes automatically reflect on all comparison pages

### Dependencies

- Alpine.js (loaded via `head.php`)
- `ordio_comparison_data.php` (must be included before component)

### CSS Classes Used

- `.checkmark-container` - Container for feature list items
- `.checkmark-icon` - Checkmark SVG styling
- Standard Tailwind classes for layout and spacing

## compare_carousel.php

### Location

`v2/base/compare_carousel.php`

### Purpose

Displays a rotating carousel of other comparison pages, excluding the current competitor. Provides navigation to other alternatives.

### Data Source

Requires `v2/data/tools_data.php` to be loaded.

### Usage

```php
<?php include '../base/compare_carousel.php'; ?>
```

### Functionality

**Auto-Filtering:**

- Automatically excludes current competitor from carousel
- Extracts competitor slug from URL: `/alternativen/{slug}-vergleich`
- Falls back to `$currentCompetitorSlug` variable if set

**Responsive Behavior:**

- **Desktop (≥1024px):** 4 cards visible
- **Tablet (768px-1023px):** 2 cards visible
- **Mobile (<768px):** 1 card visible

**Auto-Rotation:**

- Rotates every 6 seconds
- Stops auto-rotation on user interaction (click, arrow, dot)
- Loops back to first page when reaching end

**Navigation:**

- Left/right arrow buttons (desktop only)
- Pagination dots (if more than 4 items)
- Touch/swipe support (mobile)

### Alpine.js Implementation

**Main Data Object:**

```javascript
function compareCarouselData() {
    return {
        currentSlide: 0,
        currentPage: 0,
        totalSlides: <?php echo count($availableComparisons); ?>,
        slidesPerView: 4,
        slideWidth: 25,
        autoRotateInterval: null,
        userInteracted: false,
        // Methods: init(), updateSlidesPerView(), nextSlide(), previousSlide(), goToPage(), startAutoRotate(), stopAutoRotate()
    }
}
```

**Key Methods:**

- `init()` - Initialize carousel, set up resize listener
- `updateSlidesPerView()` - Adjust cards per view based on viewport
- `nextSlide(isAuto)` - Navigate to next page
- `previousSlide()` - Navigate to previous page
- `goToPage(pageIndex)` - Jump to specific page
- `startAutoRotate()` - Begin auto-rotation (if user hasn't interacted)
- `stopAutoRotate()` - Stop auto-rotation

### Data Structure

Uses `$toolsData` array from `tools_data.php`:

```php
$toolsData = [
    [
        'name' => 'Competitor Name',
        'slug' => 'competitor-slug',
        'description' => 'Short description',
        'logo' => 'competitor-logo.webp',
        'tags' => ['Tag1', 'Tag2', 'Tag3', 'Tag4', 'Tag5'],
        'filter_categories' => ['Category1', 'Category2']
    ],
    // More competitors...
];
```

### Card Structure

Each carousel card displays:

- **Logo:** 64px square, responsive (64w, 128w variants)
- **Name:** Competitor name (fixed height for alignment)
- **Description:** Short description (3 lines max, fixed height)
- **Tags:** Up to 3 tags displayed
- **Link:** "Vergleich ansehen" with arrow icon

### Customization

**To add/remove competitors:**

1. Edit `v2/data/tools_data.php`
2. Add/remove entries from `$toolsData` array
3. Ensure logo files exist in `v2/img/alternativen/`
4. Generate responsive variants: `node scripts/generate_responsive_logos.js`

**To change carousel behavior:**

Edit `compare_carousel.php`:

- Auto-rotation interval: Change `6000` (6 seconds) to desired value
- Cards per view: Modify `updateSlidesPerView()` method
- Card styling: Update CSS classes in card markup

### Dependencies

- Alpine.js (loaded via `head.php`)
- `tools_data.php` (must be included before component)
- Responsive logo variants (64w, 128w)

### CSS Classes Used

- `.carousel-wrapper` - Main carousel container
- `.carousel-card` - Individual card styling
- `.line-clamp-3` - Text truncation (3 lines)
- Custom scoped styles in `<style>` tag

### Edge Cases

**No Competitors Available:**

- Component checks `count($availableComparisons) > 0`
- If false, carousel section is not rendered

**Current Competitor Not Found:**

- Falls back to empty string
- All competitors shown (including current one)
- Should not happen in production

## tools_data.php

### Location

`v2/data/tools_data.php`

### Purpose

Central data file containing all competitor information used in comparison carousel and other components.

### Structure

```php
$toolsData = [
    [
        'name' => 'Competitor Display Name',
        'slug' => 'competitor-slug',  // Used in URLs and filtering
        'description' => 'Short description for carousel cards',
        'logo' => 'competitor-logo.webp',  // Filename only, no path
        'tags' => ['Tag1', 'Tag2', 'Tag3', 'Tag4', 'Tag5'],  // 4-5 tags
        'filter_categories' => ['Category1', 'Category2']  // For filtering
    ],
    // More entries...
];
```

### Required Fields

- **name:** Display name (e.g., "awork", "7shifts")
- **slug:** URL slug (e.g., "awork", "7shifts") - must match page filename
- **description:** Short description (used in carousel, ~100-150 chars)
- **logo:** Logo filename without path (e.g., "awork-logo.webp")
- **tags:** Array of 4-5 tags for display
- **filter_categories:** Array for filtering functionality

### Usage

**In compare_carousel.php:**

```php
require_once __DIR__ . '/../data/tools_data.php';

// Filter out current competitor
$availableComparisons = array_filter($toolsData, function($tool) use ($currentCompetitorSlug) {
    return $tool['slug'] !== $currentCompetitorSlug;
});
```

### Adding New Competitor

1. **Add entry to `$toolsData` array:**

```php
[
    'name' => 'New Competitor',
    'slug' => 'newcompetitor',
    'description' => 'Description of competitor',
    'logo' => 'newcompetitor-logo.webp',
    'tags' => ['Tag1', 'Tag2', 'Tag3', 'Tag4', 'Tag5'],
    'filter_categories' => ['Category1']
]
```

2. **Ensure logo files exist:**

   - `v2/img/alternativen/newcompetitor-logo.webp`
   - Generate variants: `node scripts/generate_responsive_logos.js`

3. **Create comparison page:**
   - `v2/pages/compare_newcompetitor.php`

### Slug Naming Convention

- Use lowercase
- Hyphenate multi-word names (e.g., "flair-hr")
- Match page filename: `compare_{slug}.php`
- Match URL pattern: `/alternativen/{slug}-vergleich`

### Tag Guidelines

- Use 4-5 tags per competitor
- Tags should be relevant and searchable
- Common tags: "Schichtplanung", "Zeiterfassung", "HR-Software", "KMU", "Gastronomie"
- Display only first 3 tags in carousel

## ordio_comparison_data.php

### Location

`v2/data/ordio_comparison_data.php`

### Purpose

Central data file containing all Ordio-specific content displayed on comparison pages. Update this file to change Ordio content across all comparison pages.

### Structure

```php
$ordio_data = [
    'description' => [
        'title' => 'Was ist Ordio?',
        'content' => 'Full description text...'
    ],

    'details' => [
        'title' => 'Ordio Details',
        'sections' => [
            'features' => [
                'title' => 'Welche Funktionsbereiche umfasst Ordio?',
                'description' => 'Intro text...',
                'features' => [
                    'Feature 1',
                    'Feature 2',
                    // More features...
                ]
            ],
            'target_audience' => [
                'title' => 'Für wen ist Ordio geeignet?',
                'content' => 'Target audience description...'
            ],
            'pricing_info' => [
                'title' => 'Was kostet Ordio?',
                'content' => 'Pricing model explanation...'
            ]
        ]
    ],

    'pricing' => [
        'title' => 'Preise',
        'plans' => [
            'starter' => [
                'name' => 'Starter',
                'description' => 'Description...',
                'price' => '€89,00',
                'period' => '/ Standort / Monat'
            ],
            'plus' => [...],
            'pro' => [...]
        ]
    ]
];
```

### Usage

**In ordio_comparison_content.php:**

```php
require_once __DIR__ . '/../data/ordio_comparison_data.php';

// Access data:
echo htmlspecialchars($ordio_data['description']['title']);
echo htmlspecialchars($ordio_data['description']['content']);
```

### Updating Content

**To update Ordio description:**

1. Edit `v2/data/ordio_comparison_data.php`
2. Update `$ordio_data['description']['content']`
3. Changes reflect on all comparison pages immediately

**To add/remove features:**

1. Edit `$ordio_data['details']['sections']['features']['features']` array
2. Add or remove feature strings
3. Features display with checkmarks automatically

**To update pricing:**

1. Edit `$ordio_data['pricing']['plans']` array
2. Update plan names, descriptions, prices, periods
3. Note: Pricing is also hardcoded in individual pages - update both locations

### Data Fields

**Description:**

- `title` - Section heading
- `content` - Full description text

**Details Sections:**

- `features` - Array of feature strings
- `target_audience` - Target audience description
- `pricing_info` - Pricing model explanation

**Pricing Plans:**

- `name` - Plan name (Starter, Plus, Pro)
- `description` - Plan description
- `price` - Price string (e.g., "€89,00")
- `period` - Billing period (e.g., "/ Standort / Monat")

### HTML Escaping

All content is escaped using `htmlspecialchars()` in the component to prevent XSS attacks.

### Best Practices

1. **Keep content concise** - Descriptions should be readable and scannable
2. **Update regularly** - Keep pricing and features current
3. **Use consistent tone** - Follow du tone guidelines
4. **Test changes** - Verify content displays correctly after updates

## Component Integration

### Loading Order

Components must be loaded in this order:

1. **Data files first:**

   ```php
   require_once __DIR__ . '/../data/ordio_comparison_data.php';
   require_once __DIR__ . '/../data/tools_data.php';
   ```

2. **Then components:**
   ```php
   include '../components/ordio_comparison_content.php';
   include '../base/compare_carousel.php';
   ```

### Dependencies Graph

```
compare_{competitor}.php
├── ordio_comparison_content.php
│   └── ordio_comparison_data.php
└── compare_carousel.php
    └── tools_data.php
```

### Common Issues

**Issue: Component not displaying**

- Check data file is loaded before component
- Verify file paths are correct (relative to page location)
- Check PHP errors in console/logs

**Issue: Data not updating**

- Clear PHP opcache if enabled
- Verify file was saved correctly
- Check for syntax errors in data file

**Issue: Carousel showing current competitor**

- Verify slug extraction from URL works
- Check `$currentCompetitorSlug` variable if manually set
- Ensure slug matches exactly (case-sensitive)

## Customization Examples

### Adding Custom Section to Ordio Content

1. **Update data structure:**

```php
$ordio_data['details']['sections']['custom_section'] = [
    'title' => 'Custom Section Title',
    'content' => 'Custom content...'
];
```

2. **Update component template:**

Add rendering code in `ordio_comparison_content.php`:

```php
<div>
    <h4 class="text-lg font-semibold text-gray-900 mb-3">
        <?= htmlspecialchars($ordio_data['details']['sections']['custom_section']['title']) ?>
    </h4>
    <p class="text-gray-600 leading-relaxed">
        <?= htmlspecialchars($ordio_data['details']['sections']['custom_section']['content']) ?>
    </p>
</div>
```

### Customizing Carousel Behavior

**Change auto-rotation speed:**

In `compare_carousel.php`, find:

```javascript
this.autoRotateInterval = setInterval(() => {
  this.nextSlide(true);
}, 6000); // Change 6000 to desired milliseconds
```

**Change cards per view:**

Modify `updateSlidesPerView()` method:

```javascript
if (width >= 1024) {
  this.slidesPerView = 4; // Change to desired number
  this.slideWidth = 25; // Adjust accordingly (100 / slidesPerView)
}
```

## Testing Components

### Testing ordio_comparison_content.php

1. **Verify content displays:**

   - Check description renders
   - Verify expandable section works
   - Test height synchronization

2. **Test data updates:**
   - Update `ordio_comparison_data.php`
   - Verify changes reflect on page
   - Check HTML escaping works

### Testing compare_carousel.php

1. **Verify filtering:**

   - Check current competitor excluded
   - Verify all other competitors shown
   - Test with different competitor pages

2. **Test responsiveness:**

   - Desktop: 4 cards visible
   - Tablet: 2 cards visible
   - Mobile: 1 card visible

3. **Test interactions:**
   - Click arrows (desktop)
   - Click pagination dots
   - Verify auto-rotation stops on interaction
   - Test touch/swipe (mobile)

### Testing Data Files

1. **Validate structure:**

   - Check PHP syntax: `php -l tools_data.php`
   - Verify required fields present
   - Check array structure

2. **Test data access:**
   - Include file in test script
   - Verify data accessible
   - Check for undefined index errors

## Performance Considerations

### Component Loading

- Components are included, not required (won't break if missing)
- Data files use `require_once` (prevents duplicate includes)
- Consider caching if performance becomes issue

### Carousel Performance

- Only renders if competitors available
- Lazy loads images (`loading="lazy"`)
- Uses CSS transforms for animations (GPU accelerated)
- Auto-rotation stops on user interaction (saves resources)

### Optimization Tips

1. **Minimize data file size** - Keep descriptions concise
2. **Use lazy loading** - Images load as needed
3. **Cache data** - Consider caching if frequently accessed
4. **Optimize images** - Ensure logo variants are optimized
