Files
igny8/docs/WP-CONTENT-TEMPLATE-IMPLEMENTATION-PLAN.md
IGNY8 VPS (Salman) a38626ba67 wp content temalpate
2025-12-01 11:05:22 +00:00

30 KiB

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

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
/**
 * Single Post Template for IGNY8-Generated Content
 * 
 * This template is automatically loaded for posts that have _igny8_content_id meta.
 * It mirrors the design of the IGNY8 app content view template.
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

get_header();

// Get IGNY8 metadata
$content_id = get_post_meta(get_the_ID(), '_igny8_content_id', true);
$task_id = get_post_meta(get_the_ID(), '_igny8_task_id', true);
$content_type = get_post_meta(get_the_ID(), '_igny8_content_type', true);
$structure = get_post_meta(get_the_ID(), '_igny8_content_structure', true);
$primary_keyword = get_post_meta(get_the_ID(), '_igny8_primary_keyword', true);
$secondary_keywords = get_post_meta(get_the_ID(), '_igny8_secondary_keywords', true);
$cluster_name = get_post_meta(get_the_ID(), '_igny8_cluster_name', true);
$meta_title = get_post_meta(get_the_ID(), '_igny8_meta_title', true);
$meta_description = get_post_meta(get_the_ID(), '_igny8_meta_description', true);
$gallery_images = get_post_meta(get_the_ID(), '_igny8_gallery_images', true);
$imported_images = get_post_meta(get_the_ID(), '_igny8_imported_images', true);

// Parse secondary keywords
$keywords_array = !empty($secondary_keywords) ? explode(',', $secondary_keywords) : [];

// Get WordPress data
$categories = get_the_category();
$tags = get_the_tags();
$word_count = str_word_count(strip_tags(get_the_content()));
?>

<div class="igny8-content-wrapper">
    <div class="igny8-content-container">
        
        <?php
        // Include template parts
        include plugin_dir_path(__FILE__) . 'parts/igny8-header.php';
        include plugin_dir_path(__FILE__) . 'parts/igny8-featured-image.php';
        include plugin_dir_path(__FILE__) . 'parts/igny8-content-sections.php';
        include plugin_dir_path(__FILE__) . 'parts/igny8-metadata.php';
        ?>
        
    </div>
</div>

<?php
get_footer();

Phase 3: Template Parts

3.1 Header Part

File: templates/parts/igny8-header.php

<?php
/**
 * IGNY8 Content Header
 * Displays title, status, and metadata
 */

$status = get_post_status();
$status_labels = [
    'draft' => 'Draft',
    'pending' => 'Pending Review',
    'publish' => 'Published',
    'private' => 'Private'
];
$status_label = $status_labels[$status] ?? ucfirst($status);
?>

<div class="igny8-header">
    <!-- Back Button -->
    <div class="igny8-header-back">
        <a href="<?php echo esc_url(get_post_type_archive_link('post')); ?>" class="igny8-back-button">
            <span class="igny8-back-icon">←</span>
            <span>Back to Posts</span>
        </a>
    </div>
    
    <!-- Title & Status -->
    <div class="igny8-header-title-row">
        <h1 class="igny8-title"><?php the_title(); ?></h1>
        <span class="igny8-status-badge igny8-status-<?php echo esc_attr($status); ?>">
            <?php echo esc_html($status_label); ?>
        </span>
    </div>
    
    <!-- Metadata Row -->
    <div class="igny8-metadata-row">
        <!-- Created Date -->
        <div class="igny8-meta-item">
            <span class="igny8-meta-icon">📅</span>
            <span class="igny8-meta-value"><?php echo get_the_date(); ?></span>
        </div>
        
        <!-- Word Count -->
        <div class="igny8-meta-item">
            <span class="igny8-meta-icon">📝</span>
            <span class="igny8-meta-value"><?php echo number_format($word_count); ?> words</span>
        </div>
        
        <!-- Categories -->
        <?php if ($categories): ?>
        <div class="igny8-meta-item">
            <span class="igny8-meta-icon">📁</span>
            <div class="igny8-meta-badges">
                <?php foreach ($categories as $cat): ?>
                    <span class="igny8-category-badge"><?php echo esc_html($cat->name); ?></span>
                <?php endforeach; ?>
            </div>
        </div>
        <?php endif; ?>
        
        <!-- Tags -->
        <?php if ($tags): ?>
        <div class="igny8-meta-item">
            <span class="igny8-meta-icon">🏷️</span>
            <div class="igny8-meta-badges">
                <?php foreach ($tags as $tag): ?>
                    <span class="igny8-tag-badge"><?php echo esc_html($tag->name); ?></span>
                <?php endforeach; ?>
            </div>
        </div>
        <?php endif; ?>
    </div>
    
    <!-- SEO Metadata (if different from post title) -->
    <?php if ($meta_title && $meta_title !== get_the_title()): ?>
    <div class="igny8-seo-section">
        <div class="igny8-seo-item">
            <label class="igny8-seo-label">SEO Title:</label>
            <div class="igny8-seo-value"><?php echo esc_html($meta_title); ?></div>
        </div>
    </div>
    <?php endif; ?>
    
    <?php if ($meta_description): ?>
    <div class="igny8-seo-section">
        <div class="igny8-seo-item">
            <label class="igny8-seo-label">Meta Description:</label>
            <div class="igny8-seo-value"><?php echo esc_html($meta_description); ?></div>
        </div>
    </div>
    <?php endif; ?>
    
    <!-- IGNY8 Specific Info -->
    <?php if ($cluster_name || $primary_keyword): ?>
    <div class="igny8-info-section">
        <?php if ($cluster_name): ?>
        <div class="igny8-info-item">
            <label>Cluster:</label>
            <span><?php echo esc_html($cluster_name); ?></span>
        </div>
        <?php endif; ?>
        
        <?php if ($primary_keyword): ?>
        <div class="igny8-info-item">
            <label>Primary Keyword:</label>
            <span><?php echo esc_html($primary_keyword); ?></span>
        </div>
        <?php endif; ?>
    </div>
    <?php endif; ?>
</div>

File: templates/parts/igny8-featured-image.php

<?php
/**
 * IGNY8 Featured Image Block
 */

$featured_image_id = get_post_thumbnail_id();
if (!$featured_image_id) {
    return;
}

$image_url = wp_get_attachment_image_url($featured_image_id, 'full');
$image_alt = get_post_meta($featured_image_id, '_wp_attachment_image_alt', true);

// Get image prompt if available from imported images data
$image_prompt = '';
if (!empty($imported_images) && is_array($imported_images)) {
    foreach ($imported_images as $img) {
        if (isset($img['is_featured']) && $img['is_featured']) {
            $image_prompt = $img['prompt'] ?? '';
            break;
        }
    }
}
?>

<div class="igny8-featured-image-block">
    <div class="igny8-featured-header">
        <span class="igny8-featured-label">Featured Visual</span>
    </div>
    
    <div class="igny8-featured-image-wrapper">
        <img src="<?php echo esc_url($image_url); ?>" 
             alt="<?php echo esc_attr($image_alt ?: get_the_title()); ?>"
             class="igny8-featured-image"
             loading="lazy">
    </div>
    
    <?php if ($image_prompt): ?>
    <div class="igny8-image-prompt">
        <p class="igny8-prompt-label">AI Image Prompt</p>
        <p class="igny8-prompt-text"><?php echo esc_html($image_prompt); ?></p>
    </div>
    <?php endif; ?>
</div>

3.3 Content Sections Part

File: templates/parts/igny8-content-sections.php

<?php
/**
 * IGNY8 Content Sections
 * Parses content HTML and displays sections with in-article images
 */

$content = get_the_content();
$content = apply_filters('the_content', $content);

// Parse content into intro and H2 sections
$sections = igny8_parse_content_sections($content);

// Get in-article images
$in_article_images = [];
if (!empty($imported_images) && is_array($imported_images)) {
    foreach ($imported_images as $img) {
        if (!isset($img['is_featured']) || !$img['is_featured']) {
            $position = $img['position'] ?? count($in_article_images) + 1;
            $in_article_images[$position] = $img;
        }
    }
}
?>

<div class="igny8-content-body">
    
    <!-- Introduction (content before first H2) -->
    <?php if (!empty($sections['intro'])): ?>
    <section class="igny8-intro-section">
        <div class="igny8-section-label">Opening Narrative</div>
        <div class="igny8-prose">
            <?php echo $sections['intro']; ?>
        </div>
    </section>
    <?php endif; ?>
    
    <!-- H2 Sections with Images -->
    <?php if (!empty($sections['sections'])): ?>
        <?php foreach ($sections['sections'] as $index => $section): ?>
        <section class="igny8-content-section" id="section-<?php echo $index + 1; ?>">
            <div class="igny8-section-container">
                
                <div class="igny8-section-header">
                    <span class="igny8-section-number"><?php echo $index + 1; ?></span>
                    <div class="igny8-section-heading-wrapper">
                        <span class="igny8-section-label">Section Spotlight</span>
                        <h2 class="igny8-section-heading"><?php echo esc_html($section['heading']); ?></h2>
                    </div>
                </div>
                
                <div class="igny8-section-content<?php echo isset($in_article_images[$index + 1]) ? ' igny8-has-image' : ''; ?>">
                    <div class="igny8-section-text">
                        <div class="igny8-prose">
                            <?php echo $section['content']; ?>
                        </div>
                    </div>
                    
                    <?php if (isset($in_article_images[$index + 1])): 
                        $img_data = $in_article_images[$index + 1];
                        $img_id = $img_data['attachment_id'] ?? null;
                        if ($img_id):
                            $img_url = wp_get_attachment_image_url($img_id, 'large');
                            $img_alt = get_post_meta($img_id, '_wp_attachment_image_alt', true);
                            $img_prompt = $img_data['prompt'] ?? '';
                    ?>
                    <div class="igny8-section-image">
                        <figure class="igny8-image-figure">
                            <img src="<?php echo esc_url($img_url); ?>" 
                                 alt="<?php echo esc_attr($img_alt ?: $section['heading']); ?>"
                                 class="igny8-in-article-image"
                                 loading="lazy">
                            <?php if ($img_prompt): ?>
                            <figcaption class="igny8-image-caption">
                                <p class="igny8-caption-label">Visual Direction</p>
                                <p class="igny8-caption-text"><?php echo esc_html($img_prompt); ?></p>
                            </figcaption>
                            <?php endif; ?>
                        </figure>
                    </div>
                    <?php endif; endif; ?>
                </div>
                
            </div>
        </section>
        <?php endforeach; ?>
    <?php endif; ?>
    
</div>

File: templates/parts/igny8-metadata.php

<?php
/**
 * IGNY8 Metadata Footer
 * Shows IGNY8-specific metadata in collapsible format
 */

// Only show if we have IGNY8 content ID
if (!$content_id) {
    return;
}
?>

<div class="igny8-metadata-footer">
    <details class="igny8-metadata-details">
        <summary class="igny8-metadata-summary">
            View IGNY8 Metadata
        </summary>
        <div class="igny8-metadata-content">
            <table class="igny8-metadata-table">
                <tr>
                    <th>Content ID:</th>
                    <td><?php echo esc_html($content_id); ?></td>
                </tr>
                <?php if ($task_id): ?>
                <tr>
                    <th>Task ID:</th>
                    <td><?php echo esc_html($task_id); ?></td>
                </tr>
                <?php endif; ?>
                <?php if ($content_type): ?>
                <tr>
                    <th>Content Type:</th>
                    <td><?php echo esc_html($content_type); ?></td>
                </tr>
                <?php endif; ?>
                <?php if ($structure): ?>
                <tr>
                    <th>Structure:</th>
                    <td><?php echo esc_html($structure); ?></td>
                </tr>
                <?php endif; ?>
                <?php if ($keywords_array): ?>
                <tr>
                    <th>Secondary Keywords:</th>
                    <td>
                        <?php foreach ($keywords_array as $kw): ?>
                            <span class="igny8-keyword-tag"><?php echo esc_html(trim($kw)); ?></span>
                        <?php endforeach; ?>
                    </td>
                </tr>
                <?php endif; ?>
                <tr>
                    <th>Last Synced:</th>
                    <td><?php echo get_post_meta(get_the_ID(), '_igny8_last_synced', true) ?: 'Never'; ?></td>
                </tr>
            </table>
        </div>
    </details>
</div>

Phase 4: Helper Functions

File: includes/template-functions.php

<?php
/**
 * Helper functions for IGNY8 content template
 */

/**
 * Parse content HTML into intro and H2 sections
 * 
 * @param string $content HTML content
 * @return array ['intro' => string, 'sections' => array]
 */
function igny8_parse_content_sections($content) {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML('<?xml encoding="UTF-8">' . $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

/**
 * 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

@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