# Blog Embed Handling Guide

**Last Updated:** 2026-01-09

Complete guide for handling embedded content (YouTube, Podigee, videos, etc.) in blog posts.

## Overview

This guide documents how embedded content is extracted, sanitized, displayed, and maintained in the migrated blog system.

## Supported Embed Types

### YouTube Videos

- **Format**: WordPress oEmbed blocks or direct iframes
- **Example**: `<iframe src="https://www.youtube.com/embed/VIDEO_ID"></iframe>`
- **Aspect Ratio**: 16:9 (automatic via CSS)

### Podigee Podcasts

- **Format**: Script tag with Podigee player
- **Example**: `<script class="podigee-podcast-player" data-configuration="..." src="..."></script>`
- **Responsive**: Yes, handled by Podigee player

### Vimeo Videos

- **Format**: WordPress oEmbed blocks or direct iframes
- **Example**: `<iframe src="https://player.vimeo.com/video/VIDEO_ID"></iframe>`
- **Aspect Ratio**: Maintained via CSS

### Video Tags

- **Format**: HTML5 video elements
- **Example**: `<video controls src="..."></video>`
- **Supported**: Self-hosted videos on ordio.com

### Demo Embeds

- **Format**: Arcade Software demo iframes
- **Example**: `<iframe src="https://demo.arcade.software/..."></iframe>`
- **Responsive**: Yes

## Extraction Process

### From WordPress

Embeds are extracted as part of the main content HTML:

1. **WordPress oEmbed Blocks**: Preserved as `<figure class="wp-block-embed">` containers
2. **Direct iframes**: Preserved as-is
3. **Script embeds**: Preserved with all attributes
4. **Video tags**: Preserved with controls and source

### Extraction Script

The extraction script (`scripts/blog/extract-content.py`) preserves all embed elements:

- Iframes are extracted with all attributes
- Script tags are preserved (especially Podigee)
- WordPress embed wrapper divs are maintained
- Video tags are preserved

## Sanitization

### Safe Embed Domains

The sanitization function (`sanitizeHtmlOutput()` in `v2/config/blog-template-helpers.php`) includes a whitelist of allowed embed domains:

- `youtube.com`, `www.youtube.com`, `youtu.be`
- `vimeo.com`, `www.vimeo.com`, `player.vimeo.com`
- `podigee.io`, `player.podigee-cdn.net`
- `demo.arcade.software`
- `ordio.com`, `www.ordio.com`

### Iframe Sanitization

Allowed iframe attributes:

- `src` (validated against domain whitelist)
- `width`, `height`
- `frameborder`
- `allow` (permissions policy)
- `allowfullscreen`
- `loading` (lazy/eager)
- `title`
- `referrerpolicy`
- `class`

Blocked:

- `javascript:` protocol in src
- Unlisted domains
- Dangerous event handlers (onclick, etc.)

### Script Sanitization

Allowed script attributes:

- `src` (validated against domain whitelist)
- `class` (for Podigee identification)
- `data-configuration` (Podigee config URL)

Blocked:

- Inline scripts (only external scripts allowed)
- Unlisted domains

### Video Sanitization

Allowed video attributes:

- `src` (validated or relative paths)
- `controls`
- `poster` (thumbnail image)
- `width`, `height`

## Component Rendering

### PostContent Component

The `PostContent` component (`v2/components/blog/PostContent.php`) preserves embeds during content cleaning:

1. **Embed Blocks Preserved**: WordPress `wp-block-embed` containers are not removed
2. **Iframes Preserved**: Iframe elements are excluded from image removal logic
3. **Scripts Preserved**: Script tags are maintained
4. **Videos Preserved**: Video tags are maintained

### Cleaning Logic

The component:

- Removes images and figures (but NOT embed blocks)
- Removes WordPress wrapper divs (but preserves embed containers)
- Removes CTAs and author info
- Preserves all embed-related elements

## CSS Styling

### Responsive Embeds

Embed styling is in `v2/css/blog-post.css`:

**YouTube/Vimeo (16:9 aspect ratio)**:

```css
.wp-block-embed.wp-embed-aspect-16-9 {
  position: relative;
  padding-bottom: 56.25%; /* 16:9 */
  height: 0;
}
```

**4:3 aspect ratio**:

```css
.wp-block-embed.wp-embed-aspect-4-3 {
  padding-bottom: 75%; /* 4:3 */
}
```

**Mobile Responsive**:

- Full width on mobile
- Proper spacing (2rem margins)
- Maintains aspect ratios

### Podigee Player

Podigee player handles its own responsive behavior. CSS ensures:

- Full width container
- Proper margins
- No overflow issues

## Adding New Embed Types

### 1. Update Domain Whitelist

Add new domain to `$allowed_embed_domains` array in `v2/config/blog-template-helpers.php`:

```php
$allowed_embed_domains = [
    // ... existing domains ...
    'new-embed-domain.com',
];
```

### 2. Update Sanitization

If new embed type requires special handling, add sanitization logic in `sanitizeHtmlOutput()` function.

### 3. Add CSS (if needed)

If new embed type needs custom styling, add to `v2/css/blog-post.css`.

### 4. Test

- Test extraction preserves embed
- Test sanitization allows embed
- Test component renders embed
- Test responsive behavior

## Troubleshooting

### Embeds Not Displaying

1. **Check extraction**: Verify embed is in `blog-posts-content-full.json`
2. **Check post file**: Verify embed is in individual post JSON file
3. **Check sanitization**: Verify domain is whitelisted
4. **Check component**: Verify PostContent preserves embed
5. **Check browser console**: Look for blocked content errors

### Embeds Blocked by Sanitization

- Check domain is in whitelist
- Verify URL format is correct
- Check for `javascript:` protocol (blocked)
- Review sanitization logs

### Responsive Issues

- Verify CSS is loaded (`blog-base.min.css` + `blog-post.min.css`)
- Check aspect ratio classes are present
- Test on mobile device or browser dev tools
- Verify iframe has proper width/height attributes

## Audit Scripts

### Audit Embeds

Run embed audit to find all embeds:

```bash
python3 scripts/blog/audit-embeds.py
```

Generates:

- `docs/content/blog/EMBED_AUDIT_REPORT.md` - Human-readable report
- `docs/data/blog-embeds-audit.json` - Detailed JSON data

### Sync Embeds

If embeds are missing from post files, sync from full content:

```bash
python3 scripts/blog/sync-embeds-to-posts.py
```

### Test Embeds

Validate embed URLs and structure:

```bash
python3 scripts/blog/test-embeds.py
```

## Related Documentation

- [Content Extraction Guide](CONTENT_EXTRACTION_GUIDE.md) - Extraction process
- [Migration Requirements](MIGRATION_REQUIREMENTS.md) - Migration requirements
- [Blog Template Helpers](../v2/config/blog-template-helpers.php) - Sanitization code
