# WordPress Content Template Implementation Plan
**Date:** December 1, 2025
**Purpose:** Create a custom WordPress post template for IGNY8-generated content that mirrors the igny8 app ContentViewTemplate
---
## 📋 Overview
We need to create a **custom single post template** in WordPress that:
1. Only applies to posts where `_igny8_content_id` meta exists (IGNY8-generated content)
2. Mirrors the design and structure of `/writer/content/[id]` from the igny8 app
3. Uses WordPress theme colors and fonts (fully theme-compatible)
4. Works with any WordPress theme without breaking appearance
---
## 🔍 Analysis: Current IGNY8 App Template
### Key Components in ContentViewTemplate.tsx
#### 1. **Header Section**
- Back button
- Post title (large, prominent)
- Status badge (draft/review/publish)
- Metadata row: Created date, word count, tags, categories
- SEO metadata (meta title, meta description)
#### 2. **Content Organization**
- **Featured Image Block**
- Large hero image with rounded corners
- Image status pill (generated/pending/failed)
- Prompt display (if available)
- **Introduction Section**
- "Opening Narrative" label
- First paragraph(s) before first H2
- **Content Sections** (Dynamic, one per H2)
- Section number badge
- Section heading (H2)
- Section content (parsed HTML)
- In-article image (side-by-side on large screens)
- Image prompts displayed
- **Metadata Footer**
- Collapsible JSON metadata viewer
#### 3. **Design Characteristics**
- Max width: 1200px, centered
- Rounded corners (rounded-3xl = 24px)
- Soft shadows and borders
- Gradient backgrounds
- Prose typography (1.85 line-height, 1.05rem base)
- Responsive grid layouts
---
## 🎨 WordPress Implementation Strategy
### File Structure
```
igny8-wp-plugin/
templates/
single-igny8-content.php # Main template file
parts/
igny8-header.php # Header with metadata
igny8-featured-image.php # Featured image block
igny8-content-sections.php # Parsed content sections
igny8-metadata.php # SEO and metadata footer
assets/
css/
igny8-content-template.css # Template styles
js/
igny8-content-template.js # JavaScript (if needed)
```
---
## 📊 Data Mapping: IGNY8 → WordPress
### Meta Fields Available in WordPress
(All stored via `update_post_meta()` during sync)
| IGNY8 Field | WordPress Meta Key | Usage in Template |
|-------------|-------------------|-------------------|
| `content_id` | `_igny8_content_id` | ✅ Identifier (required to activate template) |
| `task_id` | `_igny8_task_id` | Link back to IGNY8 |
| `content_type` | `_igny8_content_type` | Display content type badge |
| `content_structure` | `_igny8_content_structure` | Article/Guide/Hub indicator |
| `source` | `_igny8_source` | Show content source |
| `primary_keyword` | `_igny8_primary_keyword` | Display in metadata |
| `secondary_keywords` | `_igny8_secondary_keywords` | Display as tags/badges |
| `cluster_name` | `_igny8_cluster_name` | Show cluster info |
| `cluster_id` | `_igny8_cluster_id` | - |
| `sector_id` | `_igny8_sector_id` | - |
| `meta_title` | `_igny8_meta_title` | SEO title display |
| `meta_description` | `_igny8_meta_description` | SEO description display |
| `last_sync` | `_igny8_last_synced` | Show last sync time |
| Featured image | `_thumbnail_id` | Standard WP featured image |
| Gallery images | `_igny8_gallery_images` | Array of image IDs |
| In-article images | `_igny8_imported_images` | Array of image data with prompts |
### WordPress Native Fields
| Field | How to Access | Usage |
|-------|--------------|-------|
| Title | `get_the_title()` | Main heading |
| Content | `get_the_content()` | Post content HTML |
| Excerpt | `get_the_excerpt()` | - |
| Author | `get_the_author()` | Display author |
| Date | `get_the_date()` | Created date |
| Modified | `get_the_modified_date()` | Last updated |
| Categories | `get_the_category()` | Category badges |
| Tags | `get_the_tags()` | Tag badges |
| Word Count | `str_word_count(strip_tags())` | Calculate |
| Status | `get_post_status()` | draft/publish |
---
## 🎯 Implementation Plan
### Phase 1: Template Detection & Loading
**File:** `igny8-wp-plugin/includes/class-template-loader.php`
```php
class Igny8_Template_Loader {
public function __construct() {
add_filter('single_template', [$this, 'load_igny8_template'], 99);
add_action('wp_enqueue_scripts', [$this, 'enqueue_template_styles']);
}
public function load_igny8_template($template) {
global $post;
// Only for single posts
if (!is_singular('post')) {
return $template;
}
// Check if post has IGNY8 content ID
$content_id = get_post_meta($post->ID, '_igny8_content_id', true);
if (empty($content_id)) {
return $template; // Use default theme template
}
// Load our custom template
$custom_template = plugin_dir_path(dirname(__FILE__)) . 'templates/single-igny8-content.php';
if (file_exists($custom_template)) {
return $custom_template;
}
return $template;
}
public function enqueue_template_styles() {
global $post;
if (!is_singular('post')) {
return;
}
$content_id = get_post_meta($post->ID, '_igny8_content_id', true);
if (empty($content_id)) {
return;
}
// Enqueue custom styles
wp_enqueue_style(
'igny8-content-template',
plugin_dir_url(dirname(__FILE__)) . 'templates/assets/css/igny8-content-template.css',
array(),
'1.0.0'
);
// Enqueue custom JS if needed
wp_enqueue_script(
'igny8-content-template',
plugin_dir_url(dirname(__FILE__)) . 'templates/assets/js/igny8-content-template.js',
array('jquery'),
'1.0.0',
true
);
}
}
new Igny8_Template_Loader();
```
---
### Phase 2: Main Template Structure
**File:** `templates/single-igny8-content.php`
```php
'Draft',
'pending' => 'Pending Review',
'publish' => 'Published',
'private' => 'Private'
];
$status_label = $status_labels[$status] ?? ucfirst($status);
?>
```
#### 3.2 Featured Image Part
**File:** `templates/parts/igny8-featured-image.php`
```php
```
#### 3.3 Content Sections Part
**File:** `templates/parts/igny8-content-sections.php`
```php
$section): ?>
Visual Direction
```
#### 3.4 Metadata Footer Part
**File:** `templates/parts/igny8-metadata.php`
```php
```
---
### Phase 4: Helper Functions
**File:** `includes/template-functions.php`
```php
string, 'sections' => array]
*/
function igny8_parse_content_sections($content) {
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML('' . $content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();
$intro_html = '';
$sections = [];
$current_section = null;
foreach ($dom->getElementsByTagName('body')->item(0)->childNodes as $node) {
if ($node->nodeName === 'h2') {
// Save previous section
if ($current_section !== null) {
$sections[] = $current_section;
}
// Start new section
$current_section = [
'heading' => $node->textContent,
'content' => ''
];
} elseif ($current_section !== null) {
// Add to current section
$current_section['content'] .= $dom->saveHTML($node);
} else {
// Add to intro
$intro_html .= $dom->saveHTML($node);
}
}
// Save last section
if ($current_section !== null) {
$sections[] = $current_section;
}
return [
'intro' => $intro_html,
'sections' => $sections
];
}
```
---
### Phase 5: CSS Styling
**File:** `templates/assets/css/igny8-content-template.css`
```css
/**
* IGNY8 Content Template Styles
* Theme-compatible styles using CSS custom properties
*/
:root {
--igny8-max-width: 1200px;
--igny8-spacing: 2rem;
--igny8-border-radius: 24px;
--igny8-border-radius-sm: 16px;
--igny8-border-radius-xs: 8px;
}
/* Use theme's colors as fallback */
.igny8-content-wrapper {
background: var(--wp--preset--color--background, #f9fafb);
color: var(--wp--preset--color--foreground, #1f2937);
padding: var(--igny8-spacing) 0;
font-family: inherit; /* Inherit theme font */
}
.igny8-content-container {
max-width: var(--igny8-max-width);
margin: 0 auto;
padding: 0 1rem;
}
/* Header Styles */
.igny8-header {
background: var(--wp--preset--color--base, #ffffff);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius);
padding: var(--igny8-spacing);
margin-bottom: var(--igny8-spacing);
box-shadow: 0 10px 25px -10px rgba(0, 0, 0, 0.1);
}
.igny8-back-button {
display: inline-flex;
align-items: center;
gap: 0.5rem;
color: inherit;
text-decoration: none;
font-size: 0.875rem;
opacity: 0.7;
transition: opacity 0.2s;
}
.igny8-back-button:hover {
opacity: 1;
}
.igny8-header-title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
margin: 1.5rem 0;
}
.igny8-title {
font-size: 2.5rem;
font-weight: 700;
line-height: 1.2;
margin: 0;
color: inherit;
}
.igny8-status-badge {
display: inline-flex;
align-items: center;
padding: 0.5rem 1rem;
border-radius: var(--igny8-border-radius-xs);
font-size: 0.875rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.igny8-status-draft {
background: rgba(251, 191, 36, 0.15);
color: rgba(180, 83, 9, 1);
}
.igny8-status-publish {
background: rgba(16, 185, 129, 0.15);
color: rgba(5, 150, 105, 1);
}
.igny8-metadata-row {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
padding-top: 1rem;
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
.igny8-meta-item {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
}
.igny8-meta-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.igny8-category-badge,
.igny8-tag-badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: var(--igny8-border-radius-xs);
font-size: 0.75rem;
background: rgba(0, 0, 0, 0.05);
color: inherit;
}
/* Featured Image */
.igny8-featured-image-block {
background: var(--wp--preset--color--base, #ffffff);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius);
overflow: hidden;
margin-bottom: var(--igny8-spacing);
box-shadow: 0 10px 25px -10px rgba(0, 0, 0, 0.1);
}
.igny8-featured-header {
padding: 2rem 2rem 1rem;
}
.igny8-featured-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.2em;
opacity: 0.6;
}
.igny8-featured-image {
width: 100%;
height: auto;
display: block;
}
.igny8-image-prompt {
padding: 1.5rem 2rem;
border-top: 1px solid rgba(0, 0, 0, 0.08);
background: rgba(0, 0, 0, 0.02);
}
.igny8-prompt-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.15em;
opacity: 0.5;
margin-bottom: 0.75rem;
}
.igny8-prompt-text {
font-size: 0.875rem;
line-height: 1.6;
margin: 0;
}
/* Content Sections */
.igny8-content-body {
display: flex;
flex-direction: column;
gap: 3rem;
}
.igny8-intro-section,
.igny8-content-section {
background: var(--wp--preset--color--base, #ffffff);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius);
overflow: hidden;
box-shadow: 0 10px 25px -10px rgba(0, 0, 0, 0.1);
}
.igny8-intro-section {
padding: 2rem;
}
.igny8-section-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.2em;
opacity: 0.6;
margin-bottom: 1.5rem;
}
.igny8-section-container {
padding: 2.5rem;
}
.igny8-section-header {
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 2rem;
}
.igny8-section-number {
display: inline-flex;
align-items: center;
justify-content: center;
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
background: rgba(59, 130, 246, 0.1);
color: rgba(37, 99, 235, 1);
font-weight: 600;
font-size: 0.875rem;
flex-shrink: 0;
}
.igny8-section-heading {
font-size: 2rem;
font-weight: 700;
margin: 0;
color: inherit;
}
.igny8-section-content {
display: grid;
gap: 2.5rem;
}
.igny8-section-content.igny8-has-image {
grid-template-columns: 1fr;
}
@media (min-width: 1024px) {
.igny8-section-content.igny8-has-image {
grid-template-columns: 3fr 2fr;
}
}
/* Prose Styles */
.igny8-prose {
font-size: 1.0625rem;
line-height: 1.85;
color: inherit;
}
.igny8-prose h2,
.igny8-prose h3,
.igny8-prose h4 {
margin-top: 2.5rem;
margin-bottom: 1.25rem;
font-weight: 600;
color: inherit;
}
.igny8-prose h3 {
font-size: 1.6rem;
}
.igny8-prose h4 {
font-size: 1.35rem;
}
.igny8-prose p {
margin-bottom: 1.3rem;
}
.igny8-prose ul,
.igny8-prose ol {
margin-bottom: 1.5rem;
padding-left: 1.75rem;
}
.igny8-prose li {
margin-bottom: 0.6rem;
}
.igny8-prose a {
color: inherit;
text-decoration: underline;
text-decoration-color: rgba(0, 0, 0, 0.3);
transition: text-decoration-color 0.2s;
}
.igny8-prose a:hover {
text-decoration-color: rgba(0, 0, 0, 0.6);
}
.igny8-prose img {
max-width: 100%;
height: auto;
border-radius: var(--igny8-border-radius-sm);
margin: 1.75rem auto;
}
/* In-Article Images */
.igny8-image-figure {
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius-sm);
overflow: hidden;
background: rgba(0, 0, 0, 0.02);
}
.igny8-in-article-image {
width: 100%;
height: auto;
display: block;
}
.igny8-image-caption {
padding: 1.25rem;
border-top: 1px solid rgba(0, 0, 0, 0.08);
}
.igny8-caption-label {
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.15em;
opacity: 0.5;
margin-bottom: 0.75rem;
}
.igny8-caption-text {
font-size: 0.875rem;
line-height: 1.6;
margin: 0;
}
/* Metadata Footer */
.igny8-metadata-footer {
margin-top: 3rem;
padding: 2rem;
background: rgba(0, 0, 0, 0.02);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius);
}
.igny8-metadata-summary {
cursor: pointer;
font-weight: 600;
font-size: 0.875rem;
user-select: none;
}
.igny8-metadata-summary:hover {
opacity: 0.7;
}
.igny8-metadata-content {
margin-top: 1.5rem;
padding: 1.5rem;
background: var(--wp--preset--color--base, #ffffff);
border: 1px solid rgba(0, 0, 0, 0.08);
border-radius: var(--igny8-border-radius-xs);
}
.igny8-metadata-table {
width: 100%;
border-collapse: collapse;
}
.igny8-metadata-table th,
.igny8-metadata-table td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
}
.igny8-metadata-table th {
font-weight: 600;
width: 30%;
}
.igny8-keyword-tag {
display: inline-block;
padding: 0.25rem 0.75rem;
margin-right: 0.5rem;
margin-bottom: 0.5rem;
border-radius: var(--igny8-border-radius-xs);
background: rgba(0, 0, 0, 0.05);
font-size: 0.875rem;
}
/* Responsive */
@media (max-width: 768px) {
.igny8-title {
font-size: 1.875rem;
}
.igny8-section-heading {
font-size: 1.5rem;
}
.igny8-prose {
font-size: 1rem;
}
}
```
---
## 🎨 Theme Compatibility Strategy
### 1. **Use Theme Colors**
- Rely on `inherit` for text colors
- Use CSS custom properties with fallbacks
- Detect theme colors: `var(--wp--preset--color--foreground, fallback)`
### 2. **Use Theme Fonts**
- Always use `font-family: inherit`
- Let theme control all typography
### 3. **Minimal Override**
- Only style structure and spacing
- Don't set absolute colors unless necessary
- Use `rgba()` with opacity for neutrals
### 4. **Dark Mode Support**
```css
@media (prefers-color-scheme: dark) {
.igny8-content-wrapper {
background: var(--wp--preset--color--background, #111827);
}
/* Adjust opacity for better contrast */
}
```
---
## ✅ Implementation Checklist
### Backend
- [ ] Create `class-template-loader.php`
- [ ] Add `template-functions.php` with parser
- [ ] Register template loader in main plugin file
- [ ] Test template detection logic
### Templates
- [ ] Create `single-igny8-content.php`
- [ ] Create `parts/igny8-header.php`
- [ ] Create `parts/igny8-featured-image.php`
- [ ] Create `parts/igny8-content-sections.php`
- [ ] Create `parts/igny8-metadata.php`
### Styles & Assets
- [ ] Create `igny8-content-template.css`
- [ ] Add responsive breakpoints
- [ ] Test with multiple themes (Twenty Twenty-Four, Astra, GeneratePress)
- [ ] Add dark mode support
### Testing
- [ ] Test with posts that have `_igny8_content_id`
- [ ] Test with posts without `_igny8_content_id` (should use default theme)
- [ ] Test image display (featured + in-article)
- [ ] Test section parsing with various HTML structures
- [ ] Test metadata display
- [ ] Test on mobile devices
### Documentation
- [ ] Add usage docs to plugin README
- [ ] Document theme compatibility
- [ ] Create troubleshooting guide
---
## 🚀 Next Steps
1. **Review this plan** - Confirm approach and structure
2. **Create base template files** - Start with template loader
3. **Implement template parts** - One by one
4. **Style incrementally** - Test as we go
5. **Iterate based on testing** - Refine for different themes
---
## ⚠️ Important Notes
1. **Non-destructive**: Only affects IGNY8-generated posts
2. **Theme-first**: Always respect theme's design decisions
3. **Graceful fallback**: If something fails, show basic content
4. **Performance**: Minimal CSS, no heavy JavaScript
5. **Accessibility**: Semantic HTML, proper ARIA labels