# Template Page Creation Guide

**Last Updated:** 2026-02-07

This guide explains how to create and customize template pages using the modular template system with dynamic content generation.

## Yearly Labor Law Updates

Template pages include Mindestlohn, Minijob-Grenze, and Midijob-Bereich. These values change annually (typically 01.01.). See `docs/content/LABOR_LAW_VALUES_2026.md` for the current values and update checklist. When creating or updating templates, ensure labor law values match the single source of truth.

## Overview

The template page system provides a reusable, customizable base for all template download pages. It includes:

- **Hero Section**: Two-column layout with text/CTA on left, Excel visual on right
- **Excel Visual Component**: Modular, template-type-aware Excel-like spreadsheet preview (automatically extracts data from template JSON)
- **Content Blocks**: Customizable sections (features, compliance, FAQs, etc.)
- **HubSpot Integration**: Template-specific form submission
- **Configuration System**: Loads data from template registry and keyword reports
- **Visual Extraction System**: Automatically extracts and visualizes data from template definitions
- **Dynamic Meta Tags**: Automatically generates all meta tags (title, description, OG tags, Twitter cards) from template config
- **Dynamic Schema**: Automatically generates JSON-LD schema (WebPage, DigitalDocument, HowTo, FAQPage) from template config
- **Dynamic FAQs**: Loads FAQs from template registry or separate FAQ config file
- **Dynamic Alpine.js Components**: Generates component names dynamically from template ID

## Architecture

```
templates_template.php (Base Template)
├── Configuration (template-page-config.php)
├── Hero Component (template-hero.php)
│   └── Excel Visual Component (excel-visual.php)
├── Content Blocks (customizable per template)
├── Template Download Form (HubSpot integration)
├── FAQ Section (customizable)
└── Footer
```

## Creating a New Template Page

### Step 1: Copy Base Template

Copy `v2/pages/templates_template.php` to your new template page:

```bash
cp v2/pages/templates_template.php v2/pages/templates_your_template.php
```

### Step 2: Set Template ID

At the top of your new file, set the template ID. The template ID can be:

- Hardcoded in the file (for dedicated template pages)
- Loaded from query string (for dynamic routing via .htaccess)

**Option A: Hardcoded Template ID (Recommended for dedicated pages)**

```php
<?php
session_start();

// Load template configuration helpers
require_once __DIR__ . '/../config/template-page-config.php';
require_once __DIR__ . '/../config/template-meta-generator.php';
require_once __DIR__ . '/../config/template-schema-generator.php';

// Template ID - must match template registry
$templateId = 'your-template-id'; // e.g., 'dienstplan-excel-vorlage'

// Validate template exists
$templateMetadata = get_template_metadata($templateId);
if (!$templateMetadata) {
    // Handle error - redirect or show 404
    header('HTTP/1.0 404 Not Found');
    exit('Template not found');
}

// Load template configuration
$templateConfig = load_template_config($templateId);
$excelVisualData = load_excel_visual_data($templateId);
$templateContentType = get_template_content_type($templateId);
$templateFaqs = load_template_faqs($templateId);
$alpineComponentName = generate_alpine_component_name($templateId);

// Generate meta tags and schema
$metaTags = generate_template_meta_tags($templateId);
$schema = generate_template_schema($templateId);
```

**Option B: Query String Parameter (For dynamic routing)**

The base template (`templates_template.php`) supports query string parameter:

```php
// Template ID from query string (with fallback)
$templateId = !empty($_GET['template_id']) ? trim($_GET['template_id']) : 'default-template-id';

// Validate template exists
$templateMetadata = get_template_metadata($templateId);
if (!$templateMetadata) {
    // Fallback to default or show error
    $templateId = 'dienstplan-excel-vorlage';
}
```

**Note:** When using query string parameters, ensure your `.htaccess` route includes `[L,QSA]` flags to preserve query strings.

### Step 3: Customize Hero Configuration

Update the hero config before including the hero component:

```php
// Hero configuration
$heroConfig = [
    'badge' => 'Vorlagen',
    'title' => 'Your Template Title',
    'title_highlight' => 'kostenlos',
    'subtitle' => 'your subtitle',
    'description' => 'Your template description...',
    'cta_text' => 'Kostenlos downloaden',
    'cta_action' => 'openHubSpotForm',
    'trust_badges' => [
        ['text' => '100% kostenlos', 'bg' => 'bg-green-50', 'icon_color' => 'text-green-500'],
        ['text' => 'Rechtssicher', 'bg' => 'bg-blue-50', 'icon_color' => 'text-blue-500'],
        ['text' => 'XLSX Format', 'bg' => 'bg-orange-50', 'icon_color' => 'text-orange-500']
    ]
];

// Merge with template config if available
if (isset($templateConfig['hero'])) {
    $heroConfig = array_merge($heroConfig, $templateConfig['hero']);
}
```

### Step 4: Meta Tags (Automatic)

Meta tags are automatically generated from template config. Simply use:

```php
<!-- In <head> section -->
<?php echo render_template_meta_tags($templateId); ?>
```

This generates:

- Title tag
- Meta description
- Meta keywords
- Open Graph tags (og:title, og:description, og:image, etc.)
- Twitter Card tags
- Canonical URL
- Mobile app tags

**Customization:** You can override specific meta tags by passing overrides:

```php
$metaTags = generate_template_meta_tags($templateId, [
    'title' => 'Custom Title',
    'description' => 'Custom Description'
]);
```

### Step 5: Excel Visual (Automatic)

The Excel visual component automatically extracts data from your template JSON definition. No additional configuration needed! The system:

- Automatically detects the best sheet for visualization
- Detects data structure (table, key-value, list)
- Applies appropriate formatting based on template category
- Handles edge cases with graceful fallbacks

**Customization (Optional):**

If you need to customize the visual, you can override settings in `apply_template_visual_overrides()`:

```php
// In template-page-config.php
$overrides = [
    'your-template-id' => [
        'max_rows' => 10,
        'fade_start' => 65
    ]
];
```

See [Excel Visual Guide](./EXCEL_VISUAL_GUIDE.md) for detailed customization options.

### Step 5: Customize Content Blocks

The template includes several content blocks that can be customized:

- **How It Works**: Step-by-step guide
- **Compliance & Legal**: Legal information
- **Minijob/Midijob Section**: Salary information
- **Industry Presets**: Industry-specific configurations
- **Ordio Integration**: Integration features
- **FAQs**: Frequently asked questions

You can customize these sections directly in the template file or create a content blocks component.

### Step 6: Schema Markup (Automatic)

Schema markup is automatically generated from template config. Simply use:

```php
<!-- In <head> section -->
<?php echo render_template_schema($templateId); ?>
```

This generates:

- **WebPage** schema with breadcrumbs
- **DigitalDocument** schema with file formats
- **HowTo** schema with usage steps
- **SoftwareApplication** schema with features
- **FAQPage** schema (if FAQs are available)

**Customization:** You can override specific schema values:

```php
$schema = generate_template_schema($templateId, [
    'name' => 'Custom Name',
    'description' => 'Custom Description',
    'date_published' => '2026-01-05T00:00:00+01:00'
]);
```

### Step 7: Add .htaccess Route

Add a route in `.htaccess` to make your template accessible:

```apache
RewriteRule ^vorlagen/your-template-url\/?$ v2/pages/templates_your_template.php [L]
```

## Excel Visual Customization

The Excel visual component automatically loads data from template definitions. To customize:

### Option 1: Use Template Definition File

Create a template definition JSON file in `v2/systems/excel-template-generator/data/template-definitions/examples/`:

```json
{
  "sheets": [
    {
      "name": "Dienstplan",
      "type": "data_entry",
      "cells": [
        {
          "address": "A1",
          "value": "Mitarbeiter",
          "style": { "preset": "header" }
        },
        {
          "address": "B1",
          "value": "Montag",
          "style": { "preset": "header" }
        }
        // ... more cells
      ]
    }
  ]
}
```

### Option 2: Override in PHP

Override the Excel visual data directly:

```php
$excelVisualData = [
    'sheet_name' => 'Your Sheet Name',
    'headers' => ['A' => 'Column 1', 'B' => 'Column 2'],
    'rows' => [
        ['Row 1 Col 1', 'Row 1 Col 2'],
        ['Row 2 Col 1', 'Row 2 Col 2']
    ],
    'highlighted_cells' => ['A1', 'B2']
];
```

## HubSpot Integration

The template automatically integrates with HubSpot via `submit-template.php`. The content type is set automatically based on the template ID and category from the registry.

**Dynamic Content Type Mapping:**

- Content type is automatically determined from template registry category
- Categories map to content types: `shift_planning` → "Schichtplan Vorlage - Template", `time_tracking` → "Zeiterfassung Vorlage - Template", etc.
- Falls back to template name + " - Template" if category mapping not found

**Alpine.js Component:**

- Component name is automatically generated from template ID
- Example: `dienstplan-excel-vorlage` → `dienstplanData`
- Component is registered dynamically before Alpine.js initializes

## SEO Content Integration

The system automatically loads SEO keywords from `template-keywords.json`:

1. Add your template ID to `template-keywords.json`
2. Keywords will be automatically loaded into meta tags
3. Content blocks can use keywords naturally

Example:

```json
{
  "your-template-id": {
    "top_keywords": ["keyword1", "keyword2"],
    "target_keywords": ["keyword3", "keyword4"]
  }
}
```

## Content Blocks System

Content blocks are customizable per template. The system supports:

- **Hero Section**: Title, description, CTA (loaded from template config)
- **Features/Benefits**: Feature lists (loaded from template registry)
- **Compliance/Legal**: Legal information
- **Industry Presets**: Industry-specific content
- **How It Works**: Step-by-step guides
- **Integration Section**: Integration features
- **FAQs**: Frequently asked questions (loaded dynamically)

### Dynamic FAQ Loading

FAQs are automatically loaded from:

1. Template registry (`faqs` field in template metadata)
2. Separate FAQ config file (`template-faqs.json`)

```php
// FAQs are automatically loaded
$templateFaqs = load_template_faqs($templateId);

// Render FAQs in template
<?php if (!empty($templateFaqs)): ?>
    <?php foreach ($templateFaqs as $index => $faq): ?>
        <!-- FAQ HTML -->
    <?php endforeach; ?>
<?php endif; ?>
```

### Customizing Content Blocks

Content blocks can be customized in two ways:

1. **Direct Editing**: Edit sections directly in the template file
2. **Configuration System**: Use `load_template_config()` to load from registry

## Mobile Optimization

The template is fully responsive:

- Hero section stacks on mobile (text above Excel visual)
- Excel visual is scrollable on mobile
- Form modal is optimized for mobile
- Touch interactions are supported

## Performance Optimization

The template includes:

- Lazy loading for images
- Intersection Observer for Excel visual
- Optimized CSS (minified)
- Deferred JavaScript loading

## Testing Checklist

Before deploying a new template page:

- [ ] Hero section displays correctly (desktop and mobile)
- [ ] Excel visual renders properly
- [ ] Form submission works with HubSpot
- [ ] Content blocks display correctly
- [ ] SEO keywords are integrated
- [ ] Schema markup validates (Google Rich Results Test)
- [ ] Mobile responsiveness works
- [ ] Performance is acceptable (PageSpeed Insights)

## File Structure

```
v2/
├── pages/
│   └── templates_template.php (base template)
├── components/
│   ├── template-hero.php (hero component)
│   └── excel-visual.php (Excel visual component)
├── config/
│   ├── template-page-config.php (configuration helper)
│   ├── template-meta-generator.php (meta tags generator)
│   └── template-schema-generator.php (schema generator)
└── css/
    └── templates-pages.css (template styles)
```

## Dynamic Generation Functions

### Meta Tags Generation

```php
// Generate meta tags array
$metaTags = generate_template_meta_tags($templateId);

// Render as HTML
echo render_template_meta_tags($templateId);
```

### Schema Generation

```php
// Generate schema array
$schema = generate_template_schema($templateId);

// Render as JSON-LD script tag
echo render_template_schema($templateId);
```

### Alpine.js Component Name

```php
// Generate component name from template ID
$componentName = generate_alpine_component_name($templateId);
// Example: 'dienstplan-excel-vorlage' → 'dienstplanData'
```

### Template URLs

```php
// Generate canonical URL
$url = get_template_url($templateId);
// Returns: https://www.ordio.com/vorlagen/{template-id}

// Get OG image URL
$ogImage = get_template_og_image($templateId);
// Returns: https://www.ordio.com/v2/img/vorlagen/{image-name}.webp
```

## Examples

See existing template pages for examples:

- `templates_dienstplan.php` - Dienstplan template
- `templates_schichtplan.php` - Schichtplan template

## Support

For questions or issues, contact the development team or refer to:

- Template Registry: `v2/systems/excel-template-generator/data/template-registry.json`
- Keyword Reports: `v2/systems/excel-template-generator/data/template-keywords.json`
- Template Definitions: `v2/systems/excel-template-generator/data/template-definitions/examples/`
