# 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); ?>
Back to Posts

📅
📝 words
📁
name); ?>
🏷️
name); ?>
``` #### 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): ?>

<?php echo esc_attr($img_alt ?: $section['heading']); ?>

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