# IGNY8 WordPress Plugin - Complete Refactor Plan **Created**: 2025-12-01 **Scope**: Simplify to one-way publishing only, remove all automatic sync, fix broken features --- ## 🎯 Refactor Goals 1. **One-Way Publishing Only**: IGNY8 → WordPress, no bidirectional sync 2. **Immediate Response**: WordPress returns all IDs right after post creation 3. **Clean UI**: Proper meta boxes for keywords, SEO, and tracking data 4. **Pure Taxonomies**: Cluster/sector as taxonomies only (remove post_meta duplication) 5. **Working Images**: Fix gallery image saving 6. **User Control**: Draft vs publish setting in WP admin 7. **Remove Complexity**: Delete all automatic sync, cron jobs, hooks --- ## 📋 Refactor Tasks ### Phase 1: Remove Automatic Sync (Clean Up) #### Task 1.1: Delete Sync Hooks **File**: `sync/hooks.php` **Action**: Delete entire file **Reason**: All automatic sync hooks removed **Files to remove:** ``` sync/hooks.php (DELETE) sync/post-sync.php (DELETE - bidirectional sync) sync/taxonomy-sync.php (DELETE - bidirectional sync) ``` **Code to remove from other files:** - Remove `require_once 'sync/hooks.php'` from main plugin file - Remove all cron job registrations - Remove all `save_post`, `publish_post`, `transition_post_status` hooks --- #### Task 1.2: Remove Brief Meta Box **File**: `admin/class-post-meta-boxes.php` **Changes**: ```php // REMOVE these lines from add_meta_boxes() method: add_meta_box( 'igny8-planner-brief', __('IGNY8 Planner Brief', 'igny8-bridge'), array($this, 'render_planner_brief_box'), $post_type, 'side', 'default' ); // REMOVE entire method: public function render_planner_brief_box($post) { ... } // REMOVE AJAX handlers: add_action('wp_ajax_igny8_fetch_planner_brief', array($this, 'fetch_planner_brief')); add_action('wp_ajax_igny8_refresh_planner_task', array($this, 'refresh_planner_task')); // REMOVE methods: public function fetch_planner_brief() { ... } public function refresh_planner_task() { ... } ``` **Reason**: No brief data exists in IGNY8 --- #### Task 1.3: Clean Up task_id References **Investigation needed**: Determine if `_igny8_task_id` is: - Writer task (remove completely) - Celery task for async operations (keep for tracking) **Action**: If writer task, remove all references to `_igny8_task_id` --- ### Phase 2: Fix Core Publishing #### Task 2.1: Fix Gallery Images Function **File**: `sync/igny8-to-wp.php` **Current**: Line 290 calls `igny8_set_gallery_images()` but function is named `igny8_set_image_gallery()` **Fix**: ```php // Option 1: Rename function call if (!empty($content_data['gallery_images'])) { Igny8_Logger::info("{$log_prefix} STEP: Setting gallery with " . count($content_data['gallery_images']) . " images"); igny8_set_image_gallery($post_id, $content_data['gallery_images']); // Changed from igny8_set_gallery_images } // OR Option 2: Add alias function function igny8_set_gallery_images($post_id, $gallery_images) { return igny8_set_image_gallery($post_id, $gallery_images); } ``` **Test**: Verify gallery images are saved to `_igny8_gallery_images` post_meta --- #### Task 2.2: Fix Cluster/Sector Storage **File**: `sync/igny8-to-wp.php` **Current**: Lines 141-175 save cluster_id and sector_id as post_meta **Remove these lines**: ```php // REMOVE (lines ~163-175): if (!empty($content_data['cluster_id'])) { $post_data['meta_input']['_igny8_cluster_id'] = $content_data['cluster_id']; } if (!empty($content_data['sector_id'])) { $post_data['meta_input']['_igny8_sector_id'] = $content_data['sector_id']; } ``` **Keep only taxonomy assignment** (lines ~195-230): ```php // KEEP: This correctly assigns taxonomies if (!empty($content_data['cluster_id'])) { $cluster_terms = get_terms(array( 'taxonomy' => 'igny8_clusters', 'meta_key' => '_igny8_cluster_id', 'meta_value' => $content_data['cluster_id'], 'hide_empty' => false )); if (!is_wp_error($cluster_terms) && !empty($cluster_terms)) { wp_set_post_terms($post_id, array($cluster_terms[0]->term_id), 'igny8_clusters'); } } // Same for sector... ``` **Issue**: This searches for terms by meta_key, but terms need to exist first! **Better approach**: ```php if (!empty($content_data['cluster_id'])) { // Get cluster name from IGNY8 (need to send cluster_name in payload) $cluster_name = $content_data['cluster_name'] ?? ''; if (!empty($cluster_name)) { $term = wp_insert_term($cluster_name, 'igny8_clusters', array( 'slug' => sanitize_title($cluster_name) )); if (!is_wp_error($term)) { // Store IGNY8 cluster_id as term meta for future lookups update_term_meta($term['term_id'], '_igny8_cluster_id', $content_data['cluster_id']); wp_set_post_terms($post_id, array($term['term_id']), 'igny8_clusters'); } } } ``` **Backend change needed**: `wordpress_adapter.py` must send `cluster_name` and `sector_name` in payload --- #### Task 2.3: Add Draft/Publish Setting **File**: `admin/settings.php` **Add new setting field**: ```php // In settings registration (around line ~100): add_settings_field( 'igny8_default_post_status', __('Default Post Status', 'igny8-bridge'), 'igny8_render_default_post_status_field', 'igny8-settings', 'igny8_settings_section' ); // Add field renderer: function igny8_render_default_post_status_field() { $status = get_option('igny8_default_post_status', 'draft'); ?>

igny8_map_igny8_status_to_wp($content_data['status'] ?? 'draft'), // NEW: 'post_status' => get_option('igny8_default_post_status', 'draft'), ``` --- #### Task 2.4: Return All Term IDs Immediately **File**: `includes/class-igny8-rest-api.php` **Modify `publish_content_to_wordpress()` return** (around line 615): ```php // After post creation (line ~605), collect term IDs: $term_ids = array( 'categories' => array(), 'tags' => array(), 'igny8_clusters' => array(), 'igny8_sectors' => array() ); // Get assigned category IDs $category_terms = wp_get_post_terms($post_id, 'category', array('fields' => 'ids')); if (!is_wp_error($category_terms)) { $term_ids['categories'] = $category_terms; } // Get assigned tag IDs $tag_terms = wp_get_post_terms($post_id, 'post_tag', array('fields' => 'ids')); if (!is_wp_error($tag_terms)) { $term_ids['tags'] = $tag_terms; } // Get assigned cluster IDs $cluster_terms = wp_get_post_terms($post_id, 'igny8_clusters', array('fields' => 'ids')); if (!is_wp_error($cluster_terms)) { $term_ids['igny8_clusters'] = $cluster_terms; } // Get assigned sector IDs $sector_terms = wp_get_post_terms($post_id, 'igny8_sectors', array('fields' => 'ids')); if (!is_wp_error($sector_terms)) { $term_ids['igny8_sectors'] = $sector_terms; } // Return enhanced response: return $this->build_unified_response( true, array( 'post_id' => $post_id, 'post_url' => get_permalink($post_id), 'post_status' => get_post_status($post_id), 'content_id' => $content_id, 'task_id' => $task_id, 'term_ids' => $term_ids // NEW ), 'Content successfully published to WordPress', null, null, 201 ); ``` **Backend change needed**: `wordpress_adapter.py` must capture and save `term_ids` from response --- ### Phase 3: Add Custom Meta Boxes #### Task 3.1: Add IGNY8 Keywords Meta Box **File**: `admin/class-post-meta-boxes.php` **Add meta box registration**: ```php public function add_meta_boxes() { $post_types = array('post', 'page', 'product'); foreach ($post_types as $post_type) { // NEW: IGNY8 Keywords add_meta_box( 'igny8-keywords', __('IGNY8 Keywords', 'igny8-bridge'), array($this, 'render_keywords_box'), $post_type, 'side', 'high' ); // NEW: IGNY8 SEO add_meta_box( 'igny8-seo', __('IGNY8 SEO', 'igny8-bridge'), array($this, 'render_seo_box'), $post_type, 'normal', 'high' ); // NEW: IGNY8 Sync Data (read-only) add_meta_box( 'igny8-sync-data', __('IGNY8 Sync Data', 'igny8-bridge'), array($this, 'render_sync_data_box'), $post_type, 'side', 'low' ); // KEEP: IGNY8 Optimizer (existing) add_meta_box( 'igny8-optimizer', __('IGNY8 Optimizer', 'igny8-bridge'), array($this, 'render_optimizer_box'), $post_type, 'side', 'default' ); } } ``` **Add render methods**: ```php /** * Render Keywords meta box */ public function render_keywords_box($post) { $primary_keyword = get_post_meta($post->ID, '_igny8_primary_keyword', true); $secondary_keywords = get_post_meta($post->ID, '_igny8_secondary_keywords', true); // Decode JSON if needed if (is_string($secondary_keywords)) { $secondary_keywords = json_decode($secondary_keywords, true); } if (!is_array($secondary_keywords)) { $secondary_keywords = array(); } wp_nonce_field('igny8_keywords_nonce', 'igny8_keywords_nonce'); ?>

ID, '_igny8_meta_title', true); $meta_description = get_post_meta($post->ID, '_igny8_meta_description', true); wp_nonce_field('igny8_seo_nonce', 'igny8_seo_nonce'); ?>

ID, '_igny8_content_id', true); $content_type = get_post_meta($post->ID, '_igny8_content_type', true); $content_structure = get_post_meta($post->ID, '_igny8_content_structure', true); $cluster_id = get_post_meta($post->ID, '_igny8_cluster_id', true); $sector_id = get_post_meta($post->ID, '_igny8_sector_id', true); ?>