1145 lines
30 KiB
Markdown
1145 lines
30 KiB
Markdown
# 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
|
|
<?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
|
|
<?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>
|
|
```
|
|
|
|
#### 3.2 Featured Image Part
|
|
|
|
**File:** `templates/parts/igny8-featured-image.php`
|
|
|
|
```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
|
|
<?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>
|
|
```
|
|
|
|
#### 3.4 Metadata Footer Part
|
|
|
|
**File:** `templates/parts/igny8-metadata.php`
|
|
|
|
```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
|
|
<?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`
|
|
|
|
```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
|
|
|