diff --git a/plugins/wordpress/source/igny8-wp-bridge/igny8-bridge.php b/plugins/wordpress/source/igny8-wp-bridge/igny8-bridge.php index de71df86..f304292d 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/igny8-bridge.php +++ b/plugins/wordpress/source/igny8-wp-bridge/igny8-bridge.php @@ -3,7 +3,7 @@ * Plugin Name: IGNY8 WordPress Bridge * Plugin URI: https://igny8.com/igny8-wp-bridge * Description: Lightweight bridge plugin that connects WordPress to IGNY8 API for one-way content publishing. - * Version: 1.2.9 + * Version: 1.3.0 * Author: IGNY8 * Author URI: https://igny8.com/ * License: GPL v2 or later @@ -22,7 +22,7 @@ if (!defined('ABSPATH')) { } // Define plugin constants -define('IGNY8_BRIDGE_VERSION', '1.2.9'); +define('IGNY8_BRIDGE_VERSION', '1.3.0'); define('IGNY8_BRIDGE_PLUGIN_DIR', plugin_dir_path(__FILE__)); define('IGNY8_BRIDGE_PLUGIN_URL', plugin_dir_url(__FILE__)); define('IGNY8_BRIDGE_PLUGIN_FILE', __FILE__); diff --git a/plugins/wordpress/source/igny8-wp-bridge/includes/template-functions.php b/plugins/wordpress/source/igny8-wp-bridge/includes/template-functions.php index 42d27c62..afb3feb1 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/includes/template-functions.php +++ b/plugins/wordpress/source/igny8-wp-bridge/includes/template-functions.php @@ -129,6 +129,28 @@ function igny8_get_featured_image_prompt($post_id) { return null; } +/** + * Get featured image caption from imported images meta + * + * @param int $post_id Post ID + * @return string|null Image caption or null + */ +function igny8_get_featured_image_caption($post_id) { + $imported_images = get_post_meta($post_id, '_igny8_imported_images', true); + + if (empty($imported_images) || !is_array($imported_images)) { + return null; + } + + foreach ($imported_images as $img) { + if (isset($img['is_featured']) && $img['is_featured'] && isset($img['caption'])) { + return $img['caption']; + } + } + + return null; +} + /** * Format status label for display * @@ -202,12 +224,21 @@ function igny8_parse_keywords($keywords) { /** * Get section badges based on keyword/tag matching + * Returns only ONE badge per section and tracks used keywords to avoid repeats * * @param string $heading Section heading text * @param int $post_id Post ID - * @return array Array of badges with 'text' and 'type' keys + * @param array &$used_keywords Reference to array tracking already-used keywords + * @return array Array of badges with 'text' and 'type' keys (max 1) */ -function igny8_get_section_badges($heading, $post_id) { +function igny8_get_section_badges($heading, $post_id, &$used_keywords = null) { + // Initialize static variable to track used keywords across calls if not passed + static $static_used_keywords = []; + + if ($used_keywords === null) { + $used_keywords = &$static_used_keywords; + } + $badges = []; $heading_lower = strtolower($heading); @@ -217,39 +248,49 @@ function igny8_get_section_badges($heading, $post_id) { $primary_kw = get_post_meta($post_id, '_igny8_primary_keyword', true); $secondary_kws = get_post_meta($post_id, '_igny8_secondary_keywords', true); - // Priority 1: Primary keyword - if ($primary_kw && stripos($heading_lower, strtolower($primary_kw)) !== false) { - $badges[] = ['text' => $primary_kw, 'type' => 'primary']; + // Priority 1: Primary keyword (if not already used) + if ($primary_kw && !in_array(strtolower($primary_kw), $used_keywords)) { + if (stripos($heading_lower, strtolower($primary_kw)) !== false) { + $badges[] = ['text' => $primary_kw, 'type' => 'primary']; + $used_keywords[] = strtolower($primary_kw); + return $badges; // Return only 1 + } } - // Priority 2: Tags - if ($tags && !is_wp_error($tags) && count($badges) < 2) { + // Priority 2: Tags (if not already used) + if ($tags && !is_wp_error($tags) && count($badges) < 1) { foreach ($tags as $tag) { - if (stripos($heading_lower, strtolower($tag->name)) !== false) { + $tag_lower = strtolower($tag->name); + if (!in_array($tag_lower, $used_keywords) && stripos($heading_lower, $tag_lower) !== false) { $badges[] = ['text' => $tag->name, 'type' => 'tag']; - if (count($badges) >= 2) break; + $used_keywords[] = $tag_lower; + return $badges; // Return only 1 } } } - // Priority 3: Categories - if ($categories && !is_wp_error($categories) && count($badges) < 2) { + // Priority 3: Categories (if not already used) + if ($categories && !is_wp_error($categories) && count($badges) < 1) { foreach ($categories as $cat) { - if (stripos($heading_lower, strtolower($cat->name)) !== false) { + $cat_lower = strtolower($cat->name); + if (!in_array($cat_lower, $used_keywords) && stripos($heading_lower, $cat_lower) !== false) { $badges[] = ['text' => $cat->name, 'type' => 'category']; - if (count($badges) >= 2) break; + $used_keywords[] = $cat_lower; + return $badges; // Return only 1 } } } - // Priority 4: Secondary keywords - if ($secondary_kws && count($badges) < 2) { + // Priority 4: Secondary keywords (if not already used) + if ($secondary_kws && count($badges) < 1) { $kw_array = is_array($secondary_kws) ? $secondary_kws : explode(',', $secondary_kws); foreach ($kw_array as $kw) { $kw = trim($kw); - if (!empty($kw) && stripos($heading_lower, strtolower($kw)) !== false) { + $kw_lower = strtolower($kw); + if (!empty($kw) && !in_array($kw_lower, $used_keywords) && stripos($heading_lower, $kw_lower) !== false) { $badges[] = ['text' => $kw, 'type' => 'keyword']; - if (count($badges) >= 2) break; + $used_keywords[] = $kw_lower; + return $badges; // Return only 1 } } } @@ -257,6 +298,15 @@ function igny8_get_section_badges($heading, $post_id) { return $badges; } +/** + * Reset the used keywords tracker (call at start of template) + */ +function igny8_reset_used_keywords() { + // Reset the static variable by calling with empty reference + $empty = []; + igny8_get_section_badges('', 0, $empty); +} + /** * Check if section content contains a table * diff --git a/plugins/wordpress/source/igny8-wp-bridge/sync/igny8-to-wp.php b/plugins/wordpress/source/igny8-wp-bridge/sync/igny8-to-wp.php index 1a5a0ef5..d45221c7 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/sync/igny8-to-wp.php +++ b/plugins/wordpress/source/igny8-wp-bridge/sync/igny8-to-wp.php @@ -847,6 +847,7 @@ function igny8_set_featured_image($post_id, $image_data) { /** * Set image gallery for post (1-5 images) + * Also saves structured image metadata with caption, prompt, position, and is_featured * * @param int $post_id Post ID * @param array $gallery_images Array of image URLs or image data @@ -854,11 +855,12 @@ function igny8_set_featured_image($post_id, $image_data) { */ function igny8_set_image_gallery($post_id, $gallery_images) { $attachment_ids = array(); + $imported_images_meta = array(); // Limit to 5 images $gallery_images = array_slice($gallery_images, 0, 5); - foreach ($gallery_images as $image_data) { + foreach ($gallery_images as $index => $image_data) { $image_url = is_array($image_data) ? ($image_data['url'] ?? $image_data['src'] ?? '') : $image_data; if (empty($image_url)) { @@ -875,6 +877,18 @@ function igny8_set_image_gallery($post_id, $gallery_images) { if ($attachment_id) { $attachment_ids[] = $attachment_id; + + // Build structured image data for template use + $img_meta = array( + 'attachment_id' => $attachment_id, + 'url' => wp_get_attachment_url($attachment_id), + 'position' => is_array($image_data) ? (isset($image_data['position']) ? intval($image_data['position']) : $index) : $index, + 'prompt' => is_array($image_data) ? ($image_data['prompt'] ?? '') : '', + 'caption' => is_array($image_data) ? ($image_data['caption'] ?? '') : '', + 'is_featured' => is_array($image_data) ? (isset($image_data['is_featured']) && $image_data['is_featured']) : false, + ); + + $imported_images_meta[] = $img_meta; } } @@ -887,6 +901,11 @@ function igny8_set_image_gallery($post_id, $gallery_images) { update_post_meta($post_id, '_gallery_images', $attachment_ids); // Generic } + // Store structured image metadata for template rendering + if (!empty($imported_images_meta)) { + update_post_meta($post_id, '_igny8_imported_images', $imported_images_meta); + } + return $attachment_ids; } diff --git a/plugins/wordpress/source/igny8-wp-bridge/templates/assets/css/igny8-content-template.css b/plugins/wordpress/source/igny8-wp-bridge/templates/assets/css/igny8-content-template.css index 5bdbb9b1..633539cc 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/templates/assets/css/igny8-content-template.css +++ b/plugins/wordpress/source/igny8-wp-bridge/templates/assets/css/igny8-content-template.css @@ -852,3 +852,97 @@ break-inside: avoid; } } + +/* === Clickable Links & Badges === */ +.igny8-clickable-link { + text-decoration: none; + color: inherit; + transition: color 0.2s ease; +} + +.igny8-clickable-link:hover { + color: var(--igny8-theme-color); +} + +.igny8-clickable-badge { + text-decoration: none; + color: inherit; + transition: background-color 0.2s ease, border-color 0.2s ease; +} + +.igny8-clickable-badge:hover { + background: rgba(59, 130, 246, 0.15); + border-color: rgba(59, 130, 246, 0.3); + color: var(--igny8-theme-color); +} + +/* === Intro Grid Layout (TOC 33% / Content 66%) === */ +.igny8-intro-grid { + display: grid; + grid-template-columns: 1fr; + gap: 2rem; +} + +@media (min-width: 768px) { + .igny8-intro-grid { + grid-template-columns: 1fr 2fr; + gap: 3rem; + } +} + +.igny8-toc-inline { + margin-bottom: 0; + height: fit-content; + position: sticky; + top: 2rem; +} + +.igny8-intro-content { + min-width: 0; +} + +/* === Featured Image Full Width === */ +.igny8-featured-fullwidth { + padding: 0; +} + +.igny8-featured-fullwidth .igny8-featured-image-wrapper { + width: 100%; +} + +.igny8-featured-fullwidth .igny8-featured-image { + width: 100%; + max-width: none; + height: auto; + display: block; +} + +.igny8-featured-fullwidth .igny8-image-caption { + padding: 1rem 2rem; +} + +/* === Landscape Image Card Fit === */ +.igny8-image-landscape-figure { + width: fit-content; + max-width: 100%; + margin: 0 auto 2rem; +} + +.igny8-image-landscape-figure .igny8-image-landscape { + max-width: 100%; + width: auto; + height: auto; +} + +/* === Blockquote Fix (prevent overlap with floated images) === */ +.igny8-prose blockquote { + clear: both; + overflow: hidden; +} + +/* === Ensure proper content flow around floated images === */ +.igny8-section-content::after { + content: ""; + display: table; + clear: both; +} diff --git a/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-content-sections.php b/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-content-sections.php index 6dab9c5e..5626b7aa 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-content-sections.php +++ b/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-content-sections.php @@ -32,18 +32,42 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2
- +
- -
- +
+ + + +
+ +
- + $section): ?>
@@ -52,8 +76,8 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2
$badge): ?> @@ -71,7 +95,7 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2 // Determine which image to use $img_data = null; $img_url = null; - $img_prompt = ''; + $img_caption = ''; $img_align = 'full'; $img_type = 'landscape'; $show_description = igny8_show_image_description($index); @@ -87,10 +111,10 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2 $img_data = $in_article_images[$img_position]; if (isset($img_data['attachment_id'])) { $img_url = wp_get_attachment_image_url($img_data['attachment_id'], 'large'); - $img_prompt = isset($img_data['prompt']) ? $img_data['prompt'] : ''; + $img_caption = isset($img_data['caption']) ? $img_data['caption'] : ''; } elseif (isset($img_data['url'])) { $img_url = $img_data['url']; - $img_prompt = isset($img_data['prompt']) ? $img_data['prompt'] : ''; + $img_caption = isset($img_data['caption']) ? $img_data['caption'] : ''; } } } @@ -133,10 +157,9 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2 alt="" class="" loading="lazy"> - +
-

Visual Direction

-

+

@@ -159,10 +182,9 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2 alt="" class="igny8-in-article-image" loading="lazy"> - +
-

Visual Direction

-

+

@@ -184,15 +206,14 @@ $reuse_pattern = [1, 0, 3, 2]; // Featured, Square1, Landscape2, Square2 } ?>
-
+
<?php echo esc_attr($section['heading']); ?> - +
-

Visual Direction

-

+

diff --git a/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-featured-image.php b/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-featured-image.php index 42d0bd44..9a2ed436 100644 --- a/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-featured-image.php +++ b/plugins/wordpress/source/igny8-wp-bridge/templates/parts/igny8-featured-image.php @@ -1,7 +1,7 @@ -