From b2012e9563f4876b2672539c7c7a87e39780e9fe Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Mon, 1 Dec 2025 07:59:19 +0000 Subject: [PATCH] plugin fixes --- .../publishing/services/publisher_service.py | 12 +- frontend/src/pages/Writer/Review.tsx | 35 +- igny8-wp-plugin/admin/class-admin.php | 12 +- .../admin/class-post-meta-boxes.php | 365 ++++++++++++++++++ igny8-wp-plugin/admin/settings.php | 29 +- igny8-wp-plugin/sync/igny8-to-wp.php | 53 ++- 6 files changed, 449 insertions(+), 57 deletions(-) create mode 100644 igny8-wp-plugin/admin/class-post-meta-boxes.php diff --git a/backend/igny8_core/business/publishing/services/publisher_service.py b/backend/igny8_core/business/publishing/services/publisher_service.py index ac08f62f..b0339eb8 100644 --- a/backend/igny8_core/business/publishing/services/publisher_service.py +++ b/backend/igny8_core/business/publishing/services/publisher_service.py @@ -188,13 +188,21 @@ class PublisherService: 'success': result.get('success', False), 'publishing_record_id': record.id, 'external_id': result.get('external_id'), - 'url': result.get('url') + 'url': result.get('url'), + 'error': result.get('error') if not result.get('success') else None } except Exception as e: record.status = 'failed' record.error_message = str(e) record.save() - raise + logger.error(f"[PublisherService._publish_to_destination] ❌ Exception during publish: {str(e)}") + # Don't raise - return error result instead + return { + 'destination': destination, + 'success': False, + 'publishing_record_id': record.id, + 'error': str(e) + } def publish_to_multiple_destinations( self, diff --git a/frontend/src/pages/Writer/Review.tsx b/frontend/src/pages/Writer/Review.tsx index e0b223ab..8498b812 100644 --- a/frontend/src/pages/Writer/Review.tsx +++ b/frontend/src/pages/Writer/Review.tsx @@ -171,19 +171,23 @@ export default function Review() { console.log('📬 Full API Response:', JSON.parse(JSON.stringify(response))); console.log('📊 Response Structure:', { success: response.success, - has_results: !!response.results, - results_count: response.results?.length || 0, + has_data: !!response.data, + has_results: !!response.data?.results, + results_count: response.data?.results?.length || 0, has_error: !!response.error, has_message: !!response.message }); // Handle the response with results array - if (response.success && response.results) { + // Note: Backend wraps result in 'data' key via success_response() + const result = response.data || response; // Fallback to response if no data wrapper + + if (result.success && result.results) { console.log('✅ Overall publish success: true'); - console.log('📋 Publish Results:', response.results); + console.log('📋 Publish Results:', result.results); // Check individual destination results - const wordpressResult = response.results.find((r: any) => r.destination === 'wordpress'); + const wordpressResult = result.results.find((r: any) => r.destination === 'wordpress'); console.log('🎯 WordPress Result:', wordpressResult); if (wordpressResult && wordpressResult.success) { @@ -204,18 +208,18 @@ export default function Review() { }); toast.error(`Failed to publish: ${error}`); } - } else if (!response.success) { + } else if (!result.success) { // Handle overall failure console.error('❌ Publish failed (overall):', { - error: response.error, - message: response.message, - results: response.results + error: result.error, + message: result.message, + results: result.results }); // Try to extract error from results - let errorMsg = response.error || response.message || 'Publishing failed'; - if (response.results && response.results.length > 0) { - const failedResult = response.results[0]; + let errorMsg = result.error || result.message || 'Publishing failed'; + if (result.results && result.results.length > 0) { + const failedResult = result.results[0]; errorMsg = failedResult.error || failedResult.message || errorMsg; } @@ -255,11 +259,14 @@ export default function Review() { }) }); - if (response.success) { + // Backend wraps result in 'data' key via success_response() + const result = response.data || response; + + if (result.success) { successCount++; } else { failedCount++; - console.warn(`Failed to publish content ${id}:`, response.error); + console.warn(`Failed to publish content ${id}:`, result.error); } } catch (error) { failedCount++; diff --git a/igny8-wp-plugin/admin/class-admin.php b/igny8-wp-plugin/admin/class-admin.php index 8dc297ff..8fcd766f 100644 --- a/igny8-wp-plugin/admin/class-admin.php +++ b/igny8-wp-plugin/admin/class-admin.php @@ -220,7 +220,6 @@ class Igny8Admin { */ private function handle_connection() { $api_key = sanitize_text_field($_POST['igny8_api_key'] ?? ''); - $site_id = sanitize_text_field($_POST['igny8_site_id'] ?? ''); // API key is required if (empty($api_key)) { @@ -233,12 +232,17 @@ class Igny8Admin { return; } - // Site ID is required + // Extract site_id from API key format: igny8_site_{site_id}_{timestamp}_{random} + $site_id = null; + if (preg_match('/^igny8_site_(\d+)_/', $api_key, $matches)) { + $site_id = (int) $matches[1]; + } + if (empty($site_id)) { add_settings_error( 'igny8_settings', 'igny8_error', - __('Site ID is required. Create a site in IGNY8 app first.', 'igny8-bridge'), + __('Invalid API key format. Please copy the complete API key from IGNY8 app.', 'igny8-bridge'), 'error' ); return; @@ -253,7 +257,7 @@ class Igny8Admin { $api = new Igny8API(); $test_response = $api->post('/v1/integration/integrations/test-connection/', array( - 'site_id' => (int) $site_id, + 'site_id' => $site_id, 'api_key' => $api_key, 'site_url' => $site_url )); diff --git a/igny8-wp-plugin/admin/class-post-meta-boxes.php b/igny8-wp-plugin/admin/class-post-meta-boxes.php new file mode 100644 index 00000000..1f939f49 --- /dev/null +++ b/igny8-wp-plugin/admin/class-post-meta-boxes.php @@ -0,0 +1,365 @@ +post_type === 'post') { + // Keywords meta box + add_meta_box( + 'igny8_keywords', + __('IGNY8 Keywords', 'igny8-bridge'), + array($this, 'render_keywords_meta_box'), + 'post', + 'side', + 'high' + ); + + // SEO meta box + add_meta_box( + 'igny8_seo', + __('IGNY8 SEO', 'igny8-bridge'), + array($this, 'render_seo_meta_box'), + 'post', + 'normal', + 'high' + ); + + // Sync data meta box (read-only info) + add_meta_box( + 'igny8_sync_data', + __('IGNY8 Sync Data', 'igny8-bridge'), + array($this, 'render_sync_data_meta_box'), + 'post', + 'side', + 'default' + ); + } + } + + /** + * Render Keywords meta box + */ + public function render_keywords_meta_box($post) { + wp_nonce_field('igny8_keywords_nonce', 'igny8_keywords_nonce'); + + $primary_keyword = get_post_meta($post->ID, '_igny8_primary_keyword', true); + $secondary_keywords = get_post_meta($post->ID, '_igny8_secondary_keywords', true); + + // Convert comma-separated string to array for display + $secondary_keywords_array = !empty($secondary_keywords) ? explode(',', $secondary_keywords) : array(); + ?> +
+

+
+ +

+ +

+
+ + +

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

+
+ + + + +

+ +

+
+ + + + +

+ +

+ + +

+
+ + + + + ID, '_igny8_content_id', true); + $task_id = get_post_meta($post->ID, '_igny8_task_id', true); + $last_sync = get_post_meta($post->ID, '_igny8_last_sync', true); + $cluster_id = get_post_meta($post->ID, '_igny8_cluster_id', true); + $sector_id = get_post_meta($post->ID, '_igny8_sector_id', true); + + ?> +
+ +

+
+ +

+ + + +

+
+ +

+ + + +

+
+ +

+ + + +

+
+ +

+ + + +

+
+ +

+ + + +

+ +

+ +
+ + + post_type !== 'post') { + return; + } + + // Check user permissions + if (!current_user_can('edit_post', $post_id)) { + return; + } + + // Save keywords + if (isset($_POST['igny8_keywords_nonce']) && wp_verify_nonce($_POST['igny8_keywords_nonce'], 'igny8_keywords_nonce')) { + // Save primary keyword + if (isset($_POST['igny8_primary_keyword'])) { + $primary_keyword = sanitize_text_field($_POST['igny8_primary_keyword']); + update_post_meta($post_id, '_igny8_primary_keyword', $primary_keyword); + } + + // Save secondary keywords + if (isset($_POST['igny8_secondary_keywords'])) { + $secondary_keywords_raw = sanitize_textarea_field($_POST['igny8_secondary_keywords']); + // Convert newlines to commas for storage + $secondary_keywords_array = array_filter(array_map('trim', explode("\n", $secondary_keywords_raw))); + $secondary_keywords = implode(',', $secondary_keywords_array); + update_post_meta($post_id, '_igny8_secondary_keywords', $secondary_keywords); + } + } + + // Save SEO fields + if (isset($_POST['igny8_seo_nonce']) && wp_verify_nonce($_POST['igny8_seo_nonce'], 'igny8_seo_nonce')) { + // Save meta title + if (isset($_POST['igny8_meta_title'])) { + $meta_title = sanitize_text_field($_POST['igny8_meta_title']); + update_post_meta($post_id, '_igny8_meta_title', $meta_title); + + // Also update for SEO plugins + $this->sync_seo_title($post_id, $meta_title); + } + + // Save meta description + if (isset($_POST['igny8_meta_description'])) { + $meta_description = sanitize_textarea_field($_POST['igny8_meta_description']); + update_post_meta($post_id, '_igny8_meta_description', $meta_description); + + // Also update for SEO plugins + $this->sync_seo_description($post_id, $meta_description); + } + } + } + + /** + * Sync SEO title to popular SEO plugins + */ + private function sync_seo_title($post_id, $title) { + if (empty($title)) { + return; + } + + // Yoast SEO + update_post_meta($post_id, '_yoast_wpseo_title', $title); + + // Rank Math + update_post_meta($post_id, 'rank_math_title', $title); + + // All in One SEO + update_post_meta($post_id, '_aioseo_title', $title); + } + + /** + * Sync SEO description to popular SEO plugins + */ + private function sync_seo_description($post_id, $description) { + if (empty($description)) { + return; + } + + // Yoast SEO + update_post_meta($post_id, '_yoast_wpseo_metadesc', $description); + + // Rank Math + update_post_meta($post_id, 'rank_math_description', $description); + + // All in One SEO + update_post_meta($post_id, '_aioseo_description', $description); + } +} + +// Initialize +new IGNY8_Post_Meta_Boxes(); diff --git a/igny8-wp-plugin/admin/settings.php b/igny8-wp-plugin/admin/settings.php index 51fd3b4f..ac5d2fe6 100644 --- a/igny8-wp-plugin/admin/settings.php +++ b/igny8-wp-plugin/admin/settings.php @@ -92,29 +92,6 @@ $default_post_status = get_option('igny8_default_post_status', 'draft');
-
- - -

- -

-
    -
  • -
  • -
  • -
-
-
diff --git a/igny8-wp-plugin/sync/igny8-to-wp.php b/igny8-wp-plugin/sync/igny8-to-wp.php index b679c46a..af1bbfb2 100644 --- a/igny8-wp-plugin/sync/igny8-to-wp.php +++ b/igny8-wp-plugin/sync/igny8-to-wp.php @@ -682,18 +682,49 @@ function igny8_process_categories($categories, $post_id) { } // If it's a string (name or slug) elseif (is_string($category)) { - $term = get_term_by('slug', $category, 'category'); - if (!$term) { - $term = get_term_by('name', $category, 'category'); - } - - if ($term && !is_wp_error($term)) { - $term_id = $term->term_id; + // Check if it's a hierarchical category (e.g., "Gardening > Plant Care") + if (strpos($category, ' > ') !== false) { + $parts = array_map('trim', explode(' > ', $category)); + $parent_id = 0; + + // Process each level of the hierarchy + foreach ($parts as $part) { + $term = get_term_by('name', $part, 'category'); + + if (!$term || is_wp_error($term)) { + // Create term with parent + $term_result = wp_insert_term($part, 'category', array( + 'parent' => $parent_id, + 'slug' => sanitize_title($part) + )); + if (!is_wp_error($term_result)) { + $parent_id = $term_result['term_id']; + $term_id = $term_result['term_id']; // Last one is what we assign + } + } else { + // Update parent if it doesn't match + if ($parent_id > 0 && $term->parent != $parent_id) { + wp_update_term($term->term_id, 'category', array('parent' => $parent_id)); + } + $parent_id = $term->term_id; + $term_id = $term->term_id; // Last one is what we assign + } + } } else { - // Create new category - $term_result = wp_insert_term($category, 'category'); - if (!is_wp_error($term_result)) { - $term_id = $term_result['term_id']; + // Simple category (no hierarchy) + $term = get_term_by('slug', $category, 'category'); + if (!$term) { + $term = get_term_by('name', $category, 'category'); + } + + if ($term && !is_wp_error($term)) { + $term_id = $term->term_id; + } else { + // Create new category + $term_result = wp_insert_term($category, 'category'); + if (!is_wp_error($term_result)) { + $term_id = $term_result['term_id']; + } } } }