# Blog Index Page HTML Size Optimization

**Last Updated:** 2026-03-29

## Overview

The blog index page (`/insights/`) uses server-side pagination and navigational category links to keep HTML size under 2 MB. With 350+ posts, the previous client-side filtering approach (all posts in DOM + inline JSON) exceeded Semrush's 2 MB threshold.

## Problem (2026-03)

The blog index was loading all posts and rendering every PostCard in the DOM, with full post data embedded as JSON for Alpine.js filtering. This resulted in:

- **HTML size**: ~2.13 MB (exceeding Semrush's 2 MB threshold)
- **Root cause**: 348 PostCards (~5 KB each) + ~249 KB inline JSON
- **Performance**: Slow page load, poor Core Web Vitals

## Solution: Server-Side Pagination (Match Category Page Pattern)

Adopted the same architecture as category pages:

1. **Render only `ordio_blog_listing_posts_per_page()` posts per page (18; 3×6 desktop grid)** – Use `$posts = array_slice($all_posts, $offset, $posts_per_page)` for the PostCard loop
2. **Navigational filter links** – "Alle Artikel", "Lexikon", "Ratgeber", "Inside Ordio" are links to `/insights/`, `/insights/lexikon/`, etc. (no client-side filtering)
3. **Server-rendered pagination** – Use `Pagination.php` component with links like `/insights/page/2/`
4. **No inline JSON** – Removed `blogIndexFilterData` and `blog-index-filter.min.js` from the index page

## Implementation

### Updated Files

**File**: `v2/pages/blog/index.php`

- Replaced Alpine.js `x-data` and client-side filtering with static HTML
- Filter buttons → navigational links with post counts from `$categories`
- PostCard loop iterates over `$posts` (18 items per page) instead of `$all_posts` (full set in memory for counts/slicing only)
- Pagination uses `Pagination.php` component (same as category pages)
- Removed `blog-index-filter.min.js`; added `blog-pagination.min.js` for keyboard nav

**File**: `v2/scripts/blog/analyze-html-size.php`

- Measures actual HTML output via output buffering (includes full page render)
- Reports real HTML size instead of JSON-only estimate

## Results

### Size Reduction

- **Before**: ~2.13 MB HTML (348 PostCards + 249 KB inline JSON)
- **After**: ~458 KB HTML with 12 cards (historical); with **18** cards, size scales ~50% vs 12-card baseline—still far under 2 MB. Re-run `analyze-html-size.php` after changing `ordio_blog_listing_posts_per_page()` for Semrush checks.
- **Reduction**: ~78% smaller vs full-DOM approach, under 2 MB threshold

### Functionality

- ✅ Server-side pagination works (`/insights/`, `/insights/page/2/`)
- ✅ Category links navigate to `/insights/lexikon/`, `/insights/ratgeber/`, `/insights/inside-ordio/`
- ✅ PostCard rendering works
- ✅ SEO elements intact (schema, meta tags, canonical URLs)
- ✅ `blog-index-filter.js` no longer used on index (retained for potential future use)

## Testing

### HTML Size Analysis

```bash
php v2/scripts/blog/analyze-html-size.php
```

- Measures actual HTML output via output buffering
- Verifies Semrush threshold (< 2 MB)
- Reports posts rendered (`ordio_blog_listing_posts_per_page()` per page)

### Success Criteria

- ✅ HTML size < 2 MB (Semrush threshold)
- ✅ Pagination works
- ✅ Category links work
- ✅ PostCards render correctly
- ✅ SEO elements intact

## Related Documentation

- [Category Page Optimization](CATEGORY_PAGE_OPTIMIZATION.md) – Same server-side pagination pattern
- [Template Development Guide](TEMPLATE_DEVELOPMENT_GUIDE.md) – Complete template guide
