wp plugin loaded
This commit is contained in:
41
igny8-wp-integration-plugin/sync/hooks.php
Normal file
41
igny8-wp-integration-plugin/sync/hooks.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* WordPress Hooks Registration
|
||||
*
|
||||
* Registers all WordPress hooks for synchronization
|
||||
*
|
||||
* @package Igny8Bridge
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Load sync class
|
||||
require_once IGNY8_BRIDGE_PLUGIN_DIR . 'sync/post-sync.php';
|
||||
|
||||
/**
|
||||
* Register WordPress hooks for IGNY8 sync
|
||||
*/
|
||||
function igny8_register_sync_hooks() {
|
||||
// WordPress → IGNY8 hooks
|
||||
add_action('save_post', 'igny8_sync_post_status_to_igny8', 10, 3);
|
||||
add_action('publish_post', 'igny8_update_keywords_on_post_publish', 10, 1);
|
||||
add_action('publish_page', 'igny8_update_keywords_on_post_publish', 10, 1);
|
||||
add_action('draft_to_publish', 'igny8_update_keywords_on_post_publish', 10, 1);
|
||||
add_action('future_to_publish', 'igny8_update_keywords_on_post_publish', 10, 1);
|
||||
add_action('transition_post_status', 'igny8_sync_post_status_transition', 10, 3);
|
||||
|
||||
// Cron hooks
|
||||
add_action('igny8_sync_post_statuses', 'igny8_cron_sync_post_statuses');
|
||||
add_action('igny8_sync_site_data', 'igny8_cron_sync_site_data');
|
||||
add_action('igny8_sync_from_igny8', 'igny8_cron_sync_from_igny8');
|
||||
add_action('igny8_sync_taxonomies', 'igny8_cron_sync_taxonomies');
|
||||
add_action('igny8_sync_keywords', 'igny8_cron_sync_keywords');
|
||||
add_action('igny8_full_site_scan', 'igny8_cron_full_site_scan');
|
||||
}
|
||||
|
||||
// Register hooks
|
||||
igny8_register_sync_hooks();
|
||||
|
||||
807
igny8-wp-integration-plugin/sync/igny8-to-wp.php
Normal file
807
igny8-wp-integration-plugin/sync/igny8-to-wp.php
Normal file
@@ -0,0 +1,807 @@
|
||||
<?php
|
||||
/**
|
||||
* IGNY8 → WordPress Synchronization
|
||||
*
|
||||
* Handles creating WordPress posts from IGNY8 content
|
||||
*
|
||||
* @package Igny8Bridge
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine WordPress post type for IGNY8 task
|
||||
*
|
||||
* @param array $content_data Task data
|
||||
* @return string
|
||||
*/
|
||||
function igny8_resolve_post_type_for_task($content_data) {
|
||||
$content_type = $content_data['content_type'] ?? $content_data['post_type'] ?? 'post';
|
||||
|
||||
$post_type_map = array(
|
||||
'post' => 'post',
|
||||
'page' => 'page',
|
||||
'product' => 'product',
|
||||
'article' => 'post',
|
||||
'blog' => 'post'
|
||||
);
|
||||
|
||||
$post_type = isset($post_type_map[$content_type]) ? $post_type_map[$content_type] : $content_type;
|
||||
$post_type = apply_filters('igny8_post_type_for_task', $post_type, $content_data);
|
||||
|
||||
if (!post_type_exists($post_type)) {
|
||||
$post_type = 'post';
|
||||
}
|
||||
|
||||
return $post_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache writer brief for a task
|
||||
*
|
||||
* @param int $task_id IGNY8 task ID
|
||||
* @param int $post_id WordPress post ID
|
||||
* @param Igny8API|null $api Optional API client
|
||||
*/
|
||||
function igny8_cache_task_brief($task_id, $post_id, $api = null) {
|
||||
if (!$task_id || !$post_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$api = $api ?: new Igny8API();
|
||||
if (!$api->is_authenticated()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$response = $api->get("/writer/tasks/{$task_id}/brief/");
|
||||
if ($response && !empty($response['success']) && !empty($response['data'])) {
|
||||
update_post_meta($post_id, '_igny8_task_brief', $response['data']);
|
||||
update_post_meta($post_id, '_igny8_brief_cached_at', current_time('mysql'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create WordPress post from IGNY8 task/content
|
||||
*
|
||||
* @param array $content_data Content data from IGNY8
|
||||
* @param array $allowed_post_types Post types allowed to be created automatically
|
||||
* @return int|WP_Error WordPress post ID or error
|
||||
*/
|
||||
function igny8_create_wordpress_post_from_task($content_data, $allowed_post_types = array()) {
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return new WP_Error('igny8_not_authenticated', 'IGNY8 API not authenticated');
|
||||
}
|
||||
|
||||
$post_type = igny8_resolve_post_type_for_task($content_data);
|
||||
|
||||
if (!empty($allowed_post_types) && !in_array($post_type, $allowed_post_types, true)) {
|
||||
return new WP_Error('igny8_post_type_disabled', sprintf('Post type %s is disabled for automation', $post_type));
|
||||
}
|
||||
|
||||
// Prepare post data
|
||||
$post_data = array(
|
||||
'post_title' => $content_data['title'] ?? 'Untitled',
|
||||
'post_content' => $content_data['content'] ?? '',
|
||||
'post_status' => igny8_map_igny8_status_to_wp($content_data['status'] ?? 'draft'),
|
||||
'post_type' => $post_type,
|
||||
'meta_input' => array()
|
||||
);
|
||||
|
||||
// Add IGNY8 meta
|
||||
if (!empty($content_data['task_id'])) {
|
||||
$post_data['meta_input']['_igny8_task_id'] = $content_data['task_id'];
|
||||
}
|
||||
|
||||
if (!empty($content_data['content_id'])) {
|
||||
$post_data['meta_input']['_igny8_content_id'] = $content_data['content_id'];
|
||||
}
|
||||
|
||||
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'];
|
||||
}
|
||||
|
||||
if (!empty($content_data['keyword_ids'])) {
|
||||
$post_data['meta_input']['_igny8_keyword_ids'] = $content_data['keyword_ids'];
|
||||
}
|
||||
|
||||
// Create post
|
||||
$post_id = wp_insert_post($post_data);
|
||||
|
||||
if (is_wp_error($post_id)) {
|
||||
error_log("IGNY8: Failed to create WordPress post: " . $post_id->get_error_message());
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Assign taxonomies if cluster/sector IDs exist
|
||||
if (!empty($content_data['cluster_id'])) {
|
||||
// Find cluster term
|
||||
$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');
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($content_data['sector_id'])) {
|
||||
// Find sector term
|
||||
$sector_terms = get_terms(array(
|
||||
'taxonomy' => 'igny8_sectors',
|
||||
'meta_key' => '_igny8_sector_id',
|
||||
'meta_value' => $content_data['sector_id'],
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
if (!is_wp_error($sector_terms) && !empty($sector_terms)) {
|
||||
wp_set_post_terms($post_id, array($sector_terms[0]->term_id), 'igny8_sectors');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle categories
|
||||
if (!empty($content_data['categories'])) {
|
||||
$category_ids = igny8_process_categories($content_data['categories'], $post_id);
|
||||
if (!empty($category_ids)) {
|
||||
wp_set_post_terms($post_id, $category_ids, 'category');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle tags
|
||||
if (!empty($content_data['tags'])) {
|
||||
$tag_ids = igny8_process_tags($content_data['tags'], $post_id);
|
||||
if (!empty($tag_ids)) {
|
||||
wp_set_post_terms($post_id, $tag_ids, 'post_tag');
|
||||
}
|
||||
}
|
||||
|
||||
// Handle featured image
|
||||
if (!empty($content_data['featured_image'])) {
|
||||
igny8_set_featured_image($post_id, $content_data['featured_image']);
|
||||
}
|
||||
|
||||
// Handle image gallery (1-5 images)
|
||||
if (!empty($content_data['gallery_images'])) {
|
||||
igny8_set_image_gallery($post_id, $content_data['gallery_images']);
|
||||
}
|
||||
|
||||
// Handle meta title and meta description (SEO)
|
||||
if (!empty($content_data['meta_title'])) {
|
||||
update_post_meta($post_id, '_yoast_wpseo_title', $content_data['meta_title']);
|
||||
update_post_meta($post_id, '_seopress_titles_title', $content_data['meta_title']);
|
||||
update_post_meta($post_id, '_aioseo_title', $content_data['meta_title']);
|
||||
// Generic meta
|
||||
update_post_meta($post_id, '_igny8_meta_title', $content_data['meta_title']);
|
||||
}
|
||||
|
||||
if (!empty($content_data['meta_description'])) {
|
||||
update_post_meta($post_id, '_yoast_wpseo_metadesc', $content_data['meta_description']);
|
||||
update_post_meta($post_id, '_seopress_titles_desc', $content_data['meta_description']);
|
||||
update_post_meta($post_id, '_aioseo_description', $content_data['meta_description']);
|
||||
// Generic meta
|
||||
update_post_meta($post_id, '_igny8_meta_description', $content_data['meta_description']);
|
||||
}
|
||||
|
||||
// Get the actual WordPress post status (after creation)
|
||||
$created_post = get_post($post_id);
|
||||
$wp_status = $created_post ? $created_post->post_status : 'draft';
|
||||
|
||||
// Store WordPress status in meta for IGNY8 to read
|
||||
update_post_meta($post_id, '_igny8_wordpress_status', $wp_status);
|
||||
|
||||
// Map WordPress status back to IGNY8 status
|
||||
$igny8_status = igny8_map_wp_status_to_igny8($wp_status);
|
||||
|
||||
// Update IGNY8 task with WordPress post ID, URL, and status
|
||||
if (!empty($content_data['task_id'])) {
|
||||
$update_data = array(
|
||||
'assigned_post_id' => $post_id,
|
||||
'post_url' => get_permalink($post_id),
|
||||
'wordpress_status' => $wp_status, // WordPress actual status (publish/pending/draft)
|
||||
'status' => $igny8_status, // IGNY8 mapped status (completed/pending/draft)
|
||||
'synced_at' => current_time('mysql'),
|
||||
'post_type' => $post_type, // WordPress post type
|
||||
'content_type' => $content_type // IGNY8 content type
|
||||
);
|
||||
|
||||
// Include content_id if provided
|
||||
if (!empty($content_data['content_id'])) {
|
||||
$update_data['content_id'] = $content_data['content_id'];
|
||||
}
|
||||
|
||||
$response = $api->put("/writer/tasks/{$content_data['task_id']}/", $update_data);
|
||||
|
||||
if ($response['success']) {
|
||||
error_log("IGNY8: Updated task {$content_data['task_id']} with WordPress post {$post_id} (status: {$wp_status})");
|
||||
} else {
|
||||
error_log("IGNY8: Failed to update task: " . ($response['error'] ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
// Store content_id if provided (for IGNY8 to query)
|
||||
if (!empty($content_data['content_id'])) {
|
||||
update_post_meta($post_id, '_igny8_content_id', $content_data['content_id']);
|
||||
}
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map IGNY8 task status to WordPress post status
|
||||
*
|
||||
* @param string $igny8_status IGNY8 task status
|
||||
* @return string WordPress post status
|
||||
*/
|
||||
function igny8_map_igny8_status_to_wp($igny8_status) {
|
||||
$status_map = array(
|
||||
'completed' => 'publish',
|
||||
'draft' => 'draft',
|
||||
'pending' => 'pending',
|
||||
'scheduled' => 'future',
|
||||
'archived' => 'trash'
|
||||
);
|
||||
|
||||
return isset($status_map[$igny8_status]) ? $status_map[$igny8_status] : 'draft';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync IGNY8 tasks to WordPress posts
|
||||
* Fetches tasks from IGNY8 and creates/updates WordPress posts
|
||||
*
|
||||
* @param array $filters Optional filters (status, cluster_id, etc.)
|
||||
* @return array Sync results
|
||||
*/
|
||||
function igny8_sync_igny8_tasks_to_wp($filters = array()) {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('success' => false, 'error' => 'Connection disabled', 'disabled' => true);
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return array('success' => false, 'error' => 'Not authenticated');
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('writer')) {
|
||||
return array('success' => true, 'created' => 0, 'updated' => 0, 'failed' => 0, 'skipped' => 0, 'total' => 0, 'disabled' => true);
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
if (!$site_id) {
|
||||
return array('success' => false, 'error' => 'Site ID not configured');
|
||||
}
|
||||
|
||||
$enabled_post_types = function_exists('igny8_get_enabled_post_types') ? igny8_get_enabled_post_types() : array('post', 'page');
|
||||
|
||||
// Build endpoint with filters
|
||||
$endpoint = '/writer/tasks/';
|
||||
$query_params = array();
|
||||
|
||||
$query_params[] = 'site_id=' . intval($site_id);
|
||||
|
||||
if (!empty($filters['status'])) {
|
||||
$query_params[] = 'status=' . urlencode($filters['status']);
|
||||
}
|
||||
|
||||
if (!empty($filters['cluster_id'])) {
|
||||
$query_params[] = 'cluster_id=' . intval($filters['cluster_id']);
|
||||
}
|
||||
|
||||
if (!empty($query_params)) {
|
||||
$endpoint .= '?' . implode('&', $query_params);
|
||||
}
|
||||
|
||||
// Get tasks from IGNY8
|
||||
$response = $api->get($endpoint);
|
||||
|
||||
if (!$response['success']) {
|
||||
return array('success' => false, 'error' => $response['error'] ?? 'Unknown error');
|
||||
}
|
||||
|
||||
$tasks = $response['results'] ?? array();
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
$failed = 0;
|
||||
$skipped = 0;
|
||||
|
||||
foreach ($tasks as $task) {
|
||||
// Check if post already exists
|
||||
$existing_posts = get_posts(array(
|
||||
'meta_key' => '_igny8_task_id',
|
||||
'meta_value' => $task['id'],
|
||||
'post_type' => 'any',
|
||||
'posts_per_page' => 1
|
||||
));
|
||||
|
||||
if (!empty($existing_posts)) {
|
||||
// Update existing post
|
||||
$post_id = $existing_posts[0]->ID;
|
||||
|
||||
$update_data = array(
|
||||
'ID' => $post_id,
|
||||
'post_title' => $task['title'] ?? get_the_title($post_id),
|
||||
'post_status' => igny8_map_igny8_status_to_wp($task['status'] ?? 'draft')
|
||||
);
|
||||
|
||||
if (!empty($task['content'])) {
|
||||
$update_data['post_content'] = $task['content'];
|
||||
}
|
||||
|
||||
$result = wp_update_post($update_data);
|
||||
|
||||
// Update categories, tags, images, and meta
|
||||
if ($result && !is_wp_error($result)) {
|
||||
// Update categories
|
||||
if (!empty($task['categories'])) {
|
||||
$category_ids = igny8_process_categories($task['categories'], $post_id);
|
||||
if (!empty($category_ids)) {
|
||||
wp_set_post_terms($post_id, $category_ids, 'category');
|
||||
}
|
||||
}
|
||||
|
||||
// Update tags
|
||||
if (!empty($task['tags'])) {
|
||||
$tag_ids = igny8_process_tags($task['tags'], $post_id);
|
||||
if (!empty($tag_ids)) {
|
||||
wp_set_post_terms($post_id, $tag_ids, 'post_tag');
|
||||
}
|
||||
}
|
||||
|
||||
// Update featured image
|
||||
if (!empty($task['featured_image']) || !empty($task['featured_media'])) {
|
||||
igny8_set_featured_image($post_id, $task['featured_image'] ?? $task['featured_media']);
|
||||
}
|
||||
|
||||
// Update gallery
|
||||
if (!empty($task['gallery_images']) || !empty($task['images'])) {
|
||||
igny8_set_image_gallery($post_id, $task['gallery_images'] ?? $task['images']);
|
||||
}
|
||||
|
||||
// Update meta title and description
|
||||
if (!empty($task['meta_title']) || !empty($task['seo_title'])) {
|
||||
$meta_title = $task['meta_title'] ?? $task['seo_title'];
|
||||
update_post_meta($post_id, '_yoast_wpseo_title', $meta_title);
|
||||
update_post_meta($post_id, '_seopress_titles_title', $meta_title);
|
||||
update_post_meta($post_id, '_aioseo_title', $meta_title);
|
||||
update_post_meta($post_id, '_igny8_meta_title', $meta_title);
|
||||
}
|
||||
|
||||
if (!empty($task['meta_description']) || !empty($task['seo_description'])) {
|
||||
$meta_desc = $task['meta_description'] ?? $task['seo_description'];
|
||||
update_post_meta($post_id, '_yoast_wpseo_metadesc', $meta_desc);
|
||||
update_post_meta($post_id, '_seopress_titles_desc', $meta_desc);
|
||||
update_post_meta($post_id, '_aioseo_description', $meta_desc);
|
||||
update_post_meta($post_id, '_igny8_meta_description', $meta_desc);
|
||||
}
|
||||
}
|
||||
|
||||
if ($result && !is_wp_error($result)) {
|
||||
igny8_cache_task_brief($task['id'], $post_id, $api);
|
||||
$updated++;
|
||||
} else {
|
||||
$failed++;
|
||||
}
|
||||
} else {
|
||||
// Create new post
|
||||
$task_post_type = igny8_resolve_post_type_for_task($task);
|
||||
if (!empty($enabled_post_types) && !in_array($task_post_type, $enabled_post_types, true)) {
|
||||
$skipped++;
|
||||
continue;
|
||||
}
|
||||
$content_data = array(
|
||||
'task_id' => $task['id'],
|
||||
'title' => $task['title'] ?? 'Untitled',
|
||||
'content' => $task['content'] ?? '',
|
||||
'status' => $task['status'] ?? 'draft',
|
||||
'cluster_id' => $task['cluster_id'] ?? null,
|
||||
'sector_id' => $task['sector_id'] ?? null,
|
||||
'keyword_ids' => $task['keyword_ids'] ?? array(),
|
||||
'content_type' => $task['content_type'] ?? $task['post_type'] ?? 'post',
|
||||
'post_type' => $task['post_type'] ?? null, // Keep for backward compatibility
|
||||
'categories' => $task['categories'] ?? array(),
|
||||
'tags' => $task['tags'] ?? array(),
|
||||
'featured_image' => $task['featured_image'] ?? $task['featured_media'] ?? null,
|
||||
'gallery_images' => $task['gallery_images'] ?? $task['images'] ?? array(),
|
||||
'meta_title' => $task['meta_title'] ?? $task['seo_title'] ?? null,
|
||||
'meta_description' => $task['meta_description'] ?? $task['seo_description'] ?? null
|
||||
);
|
||||
|
||||
$post_id = igny8_create_wordpress_post_from_task($content_data, $enabled_post_types);
|
||||
|
||||
if (is_wp_error($post_id)) {
|
||||
if ($post_id->get_error_code() === 'igny8_post_type_disabled') {
|
||||
$skipped++;
|
||||
} else {
|
||||
$failed++;
|
||||
}
|
||||
} elseif ($post_id) {
|
||||
igny8_cache_task_brief($task['id'], $post_id, $api);
|
||||
$created++;
|
||||
} else {
|
||||
$failed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'created' => $created,
|
||||
'updated' => $updated,
|
||||
'failed' => $failed,
|
||||
'skipped' => $skipped,
|
||||
'total' => count($tasks)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle webhook from IGNY8 (when content is published from IGNY8)
|
||||
* This can be called via REST API endpoint or scheduled sync
|
||||
*
|
||||
* @param array $webhook_data Webhook data from IGNY8
|
||||
* @return int|false WordPress post ID or false on failure
|
||||
*/
|
||||
function igny8_handle_igny8_webhook($webhook_data) {
|
||||
if (empty($webhook_data['task_id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
// Get full task data from IGNY8
|
||||
$task_response = $api->get("/writer/tasks/{$webhook_data['task_id']}/");
|
||||
|
||||
if (!$task_response['success']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$task = $task_response['data'];
|
||||
|
||||
// Prepare content data
|
||||
$content_data = array(
|
||||
'task_id' => $task['id'],
|
||||
'content_id' => $task['content_id'] ?? null,
|
||||
'title' => $task['title'] ?? 'Untitled',
|
||||
'content' => $task['content'] ?? '',
|
||||
'status' => $task['status'] ?? 'draft',
|
||||
'cluster_id' => $task['cluster_id'] ?? null,
|
||||
'sector_id' => $task['sector_id'] ?? null,
|
||||
'keyword_ids' => $task['keyword_ids'] ?? array(),
|
||||
'post_type' => $task['post_type'] ?? 'post'
|
||||
);
|
||||
|
||||
return igny8_create_wordpress_post_from_task($content_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process categories from IGNY8
|
||||
*
|
||||
* @param array $categories Category data (IDs, names, or slugs)
|
||||
* @param int $post_id Post ID
|
||||
* @return array Category term IDs
|
||||
*/
|
||||
function igny8_process_categories($categories, $post_id) {
|
||||
$category_ids = array();
|
||||
|
||||
foreach ($categories as $category) {
|
||||
$term_id = null;
|
||||
|
||||
// If it's an ID
|
||||
if (is_numeric($category)) {
|
||||
$term = get_term($category, 'category');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$term_id = $term->term_id;
|
||||
}
|
||||
}
|
||||
// If it's an array with name/slug
|
||||
elseif (is_array($category)) {
|
||||
$name = $category['name'] ?? $category['slug'] ?? null;
|
||||
$slug = $category['slug'] ?? sanitize_title($name);
|
||||
|
||||
if ($name) {
|
||||
// Try to find existing term
|
||||
$term = get_term_by('slug', $slug, 'category');
|
||||
if (!$term) {
|
||||
$term = get_term_by('name', $name, 'category');
|
||||
}
|
||||
|
||||
// Create if doesn't exist
|
||||
if (!$term || is_wp_error($term)) {
|
||||
$term_result = wp_insert_term($name, 'category', array('slug' => $slug));
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
}
|
||||
} else {
|
||||
$term_id = $term->term_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;
|
||||
} else {
|
||||
// Create new category
|
||||
$term_result = wp_insert_term($category, 'category');
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($term_id) {
|
||||
$category_ids[] = $term_id;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($category_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process tags from IGNY8
|
||||
*
|
||||
* @param array $tags Tag data (IDs, names, or slugs)
|
||||
* @param int $post_id Post ID
|
||||
* @return array Tag term IDs
|
||||
*/
|
||||
function igny8_process_tags($tags, $post_id) {
|
||||
$tag_ids = array();
|
||||
|
||||
foreach ($tags as $tag) {
|
||||
$term_id = null;
|
||||
|
||||
// If it's an ID
|
||||
if (is_numeric($tag)) {
|
||||
$term = get_term($tag, 'post_tag');
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$term_id = $term->term_id;
|
||||
}
|
||||
}
|
||||
// If it's an array with name/slug
|
||||
elseif (is_array($tag)) {
|
||||
$name = $tag['name'] ?? $tag['slug'] ?? null;
|
||||
$slug = $tag['slug'] ?? sanitize_title($name);
|
||||
|
||||
if ($name) {
|
||||
// Try to find existing term
|
||||
$term = get_term_by('slug', $slug, 'post_tag');
|
||||
if (!$term) {
|
||||
$term = get_term_by('name', $name, 'post_tag');
|
||||
}
|
||||
|
||||
// Create if doesn't exist
|
||||
if (!$term || is_wp_error($term)) {
|
||||
$term_result = wp_insert_term($name, 'post_tag', array('slug' => $slug));
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
}
|
||||
} else {
|
||||
$term_id = $term->term_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
// If it's a string (name or slug)
|
||||
elseif (is_string($tag)) {
|
||||
$term = get_term_by('slug', $tag, 'post_tag');
|
||||
if (!$term) {
|
||||
$term = get_term_by('name', $tag, 'post_tag');
|
||||
}
|
||||
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$term_id = $term->term_id;
|
||||
} else {
|
||||
// Create new tag
|
||||
$term_result = wp_insert_term($tag, 'post_tag');
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($term_id) {
|
||||
$tag_ids[] = $term_id;
|
||||
}
|
||||
}
|
||||
|
||||
return array_unique($tag_ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set featured image for post
|
||||
*
|
||||
* @param int $post_id Post ID
|
||||
* @param string|array $image_data Image URL or array with image data
|
||||
* @return int|false Attachment ID or false on failure
|
||||
*/
|
||||
function igny8_set_featured_image($post_id, $image_data) {
|
||||
$image_url = is_array($image_data) ? ($image_data['url'] ?? $image_data['src'] ?? '') : $image_data;
|
||||
|
||||
if (empty($image_url)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if image already exists
|
||||
$attachment_id = igny8_get_attachment_by_url($image_url);
|
||||
|
||||
if (!$attachment_id) {
|
||||
// Download and attach image
|
||||
$attachment_id = igny8_import_image($image_url, $post_id);
|
||||
}
|
||||
|
||||
if ($attachment_id) {
|
||||
set_post_thumbnail($post_id, $attachment_id);
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set image gallery for post (1-5 images)
|
||||
*
|
||||
* @param int $post_id Post ID
|
||||
* @param array $gallery_images Array of image URLs or image data
|
||||
* @return array Attachment IDs
|
||||
*/
|
||||
function igny8_set_image_gallery($post_id, $gallery_images) {
|
||||
$attachment_ids = array();
|
||||
|
||||
// Limit to 5 images
|
||||
$gallery_images = array_slice($gallery_images, 0, 5);
|
||||
|
||||
foreach ($gallery_images as $image_data) {
|
||||
$image_url = is_array($image_data) ? ($image_data['url'] ?? $image_data['src'] ?? '') : $image_data;
|
||||
|
||||
if (empty($image_url)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if image already exists
|
||||
$attachment_id = igny8_get_attachment_by_url($image_url);
|
||||
|
||||
if (!$attachment_id) {
|
||||
// Download and attach image
|
||||
$attachment_id = igny8_import_image($image_url, $post_id);
|
||||
}
|
||||
|
||||
if ($attachment_id) {
|
||||
$attachment_ids[] = $attachment_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Store gallery as post meta (WordPress native)
|
||||
if (!empty($attachment_ids)) {
|
||||
update_post_meta($post_id, '_igny8_gallery_images', $attachment_ids);
|
||||
|
||||
// Also store in format compatible with plugins
|
||||
update_post_meta($post_id, '_product_image_gallery', implode(',', $attachment_ids)); // WooCommerce
|
||||
update_post_meta($post_id, '_gallery_images', $attachment_ids); // Generic
|
||||
}
|
||||
|
||||
return $attachment_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment ID by image URL
|
||||
*
|
||||
* @param string $image_url Image URL
|
||||
* @return int|false Attachment ID or false
|
||||
*/
|
||||
function igny8_get_attachment_by_url($image_url) {
|
||||
global $wpdb;
|
||||
|
||||
$attachment_id = $wpdb->get_var($wpdb->prepare(
|
||||
"SELECT ID FROM {$wpdb->posts} WHERE guid = %s AND post_type = 'attachment'",
|
||||
$image_url
|
||||
));
|
||||
|
||||
return $attachment_id ? intval($attachment_id) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Import image from URL and attach to post
|
||||
*
|
||||
* @param string $image_url Image URL
|
||||
* @param int $post_id Post ID to attach to
|
||||
* @return int|false Attachment ID or false on failure
|
||||
*/
|
||||
function igny8_import_image($image_url, $post_id) {
|
||||
require_once(ABSPATH . 'wp-admin/includes/image.php');
|
||||
require_once(ABSPATH . 'wp-admin/includes/file.php');
|
||||
require_once(ABSPATH . 'wp-admin/includes/media.php');
|
||||
|
||||
// Download image
|
||||
$tmp = download_url($image_url);
|
||||
|
||||
if (is_wp_error($tmp)) {
|
||||
error_log("IGNY8: Failed to download image {$image_url}: " . $tmp->get_error_message());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get file extension
|
||||
$file_array = array(
|
||||
'name' => basename(parse_url($image_url, PHP_URL_PATH)),
|
||||
'tmp_name' => $tmp
|
||||
);
|
||||
|
||||
// Upload to WordPress media library
|
||||
$attachment_id = media_handle_sideload($file_array, $post_id);
|
||||
|
||||
// Clean up temp file
|
||||
@unlink($tmp);
|
||||
|
||||
if (is_wp_error($attachment_id)) {
|
||||
error_log("IGNY8: Failed to import image {$image_url}: " . $attachment_id->get_error_message());
|
||||
return false;
|
||||
}
|
||||
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled sync from IGNY8 to WordPress
|
||||
* Fetches new/updated tasks from IGNY8 and creates/updates WordPress posts
|
||||
*/
|
||||
function igny8_cron_sync_from_igny8() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
error_log('IGNY8: Connection disabled, skipping sync from IGNY8');
|
||||
return;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
|
||||
if (!$site_id) {
|
||||
error_log('IGNY8: Site ID not set, skipping sync from IGNY8');
|
||||
return;
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('writer')) {
|
||||
error_log('IGNY8: Writer module disabled, skipping sync from IGNY8');
|
||||
return;
|
||||
}
|
||||
|
||||
// Get last sync time
|
||||
$last_sync = get_option('igny8_last_sync_from_igny8', 0);
|
||||
|
||||
// Sync only completed/published tasks
|
||||
$filters = array(
|
||||
'status' => 'completed'
|
||||
);
|
||||
|
||||
// If we have a last sync time, we could filter by updated date
|
||||
// For now, sync all completed tasks (API should handle deduplication)
|
||||
|
||||
$result = igny8_sync_igny8_tasks_to_wp($filters);
|
||||
|
||||
if ($result['success']) {
|
||||
update_option('igny8_last_sync_from_igny8', time());
|
||||
update_option('igny8_last_writer_sync', current_time('timestamp'));
|
||||
error_log(sprintf(
|
||||
'IGNY8: Synced from IGNY8 - Created %d posts, updated %d posts, %d failed, %d skipped',
|
||||
$result['created'],
|
||||
$result['updated'],
|
||||
$result['failed'],
|
||||
$result['skipped'] ?? 0
|
||||
));
|
||||
} else {
|
||||
error_log('IGNY8: Failed to sync from IGNY8: ' . ($result['error'] ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
363
igny8-wp-integration-plugin/sync/post-sync.php
Normal file
363
igny8-wp-integration-plugin/sync/post-sync.php
Normal file
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
/**
|
||||
* Post Synchronization Functions
|
||||
*
|
||||
* Handles WordPress → IGNY8 post synchronization
|
||||
*
|
||||
* @package Igny8Bridge
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync WordPress post status to IGNY8 when post is saved
|
||||
*
|
||||
* @param int $post_id Post ID
|
||||
* @param WP_Post $post Post object
|
||||
* @param bool $update Whether this is an update
|
||||
*/
|
||||
function igny8_sync_post_status_to_igny8($post_id, $post, $update) {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip autosaves and revisions
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wp_is_post_revision($post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only sync IGNY8-managed posts
|
||||
if (!igny8_is_igny8_managed_post($post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get task ID
|
||||
$task_id = get_post_meta($post_id, '_igny8_task_id', true);
|
||||
if (!$task_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get post status
|
||||
$post_status = $post->post_status;
|
||||
|
||||
// Map WordPress status to IGNY8 task status
|
||||
$task_status = igny8_map_wp_status_to_igny8($post_status);
|
||||
|
||||
// Sync to IGNY8 API
|
||||
$api = new Igny8API();
|
||||
|
||||
// Get content_id if available
|
||||
$content_id = get_post_meta($post_id, '_igny8_content_id', true);
|
||||
|
||||
$update_data = array(
|
||||
'status' => $task_status,
|
||||
'assigned_post_id' => $post_id,
|
||||
'post_url' => get_permalink($post_id),
|
||||
'wordpress_status' => $post_status, // Actual WordPress status
|
||||
'synced_at' => current_time('mysql')
|
||||
);
|
||||
|
||||
// Include content_id if available
|
||||
if ($content_id) {
|
||||
$update_data['content_id'] = $content_id;
|
||||
}
|
||||
|
||||
$response = $api->put("/writer/tasks/{$task_id}/", $update_data);
|
||||
|
||||
if ($response['success']) {
|
||||
// Update WordPress status in meta for IGNY8 to read
|
||||
update_post_meta($post_id, '_igny8_wordpress_status', $post_status);
|
||||
update_post_meta($post_id, '_igny8_last_synced', current_time('mysql'));
|
||||
error_log("IGNY8: Synced post {$post_id} status ({$post_status}) to task {$task_id}");
|
||||
} else {
|
||||
error_log("IGNY8: Failed to sync post status: " . ($response['error'] ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update keyword status when WordPress post is published
|
||||
*
|
||||
* @param int $post_id Post ID
|
||||
*/
|
||||
function igny8_update_keywords_on_post_publish($post_id) {
|
||||
// Get task ID from post meta
|
||||
$task_id = get_post_meta($post_id, '_igny8_task_id', true);
|
||||
if (!$task_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
// Get task details to find associated cluster/keywords
|
||||
$task_response = $api->get("/writer/tasks/{$task_id}/");
|
||||
|
||||
if (!$task_response['success']) {
|
||||
return;
|
||||
}
|
||||
|
||||
$task = $task_response['data'];
|
||||
$cluster_id = $task['cluster_id'] ?? null;
|
||||
|
||||
if ($cluster_id) {
|
||||
// Get keywords in this cluster
|
||||
$keywords_response = $api->get("/planner/keywords/?cluster_id={$cluster_id}");
|
||||
|
||||
if ($keywords_response['success']) {
|
||||
$keywords = $keywords_response['results'];
|
||||
|
||||
// Update each keyword status to 'mapped'
|
||||
foreach ($keywords as $keyword) {
|
||||
$api->put("/planner/keywords/{$keyword['id']}/", array(
|
||||
'status' => 'mapped'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update task status to completed
|
||||
$api->put("/writer/tasks/{$task_id}/", array(
|
||||
'status' => 'completed',
|
||||
'assigned_post_id' => $post_id,
|
||||
'post_url' => get_permalink($post_id)
|
||||
));
|
||||
|
||||
update_post_meta($post_id, '_igny8_last_synced', current_time('mysql'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync post status changes to IGNY8
|
||||
*
|
||||
* @param string $new_status New post status
|
||||
* @param string $old_status Old post status
|
||||
* @param WP_Post $post Post object
|
||||
*/
|
||||
function igny8_sync_post_status_transition($new_status, $old_status, $post) {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if status hasn't changed
|
||||
if ($new_status === $old_status) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only sync IGNY8-managed posts
|
||||
if (!igny8_is_igny8_managed_post($post->ID)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$task_id = get_post_meta($post->ID, '_igny8_task_id', true);
|
||||
if (!$task_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
// Map WordPress status to IGNY8 task status
|
||||
$task_status = igny8_map_wp_status_to_igny8($new_status);
|
||||
|
||||
// Sync to IGNY8
|
||||
$response = $api->put("/writer/tasks/{$task_id}/", array(
|
||||
'status' => $task_status,
|
||||
'assigned_post_id' => $post->ID,
|
||||
'post_url' => get_permalink($post->ID)
|
||||
));
|
||||
|
||||
if ($response['success']) {
|
||||
update_post_meta($post->ID, '_igny8_last_synced', current_time('mysql'));
|
||||
do_action('igny8_post_status_synced', $post->ID, $task_id, $new_status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch sync all IGNY8-managed posts status to IGNY8 API
|
||||
*
|
||||
* @return array Sync results
|
||||
*/
|
||||
function igny8_batch_sync_post_statuses() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array(
|
||||
'synced' => 0,
|
||||
'failed' => 0,
|
||||
'total' => 0,
|
||||
'disabled' => true
|
||||
);
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
// Get all posts with IGNY8 task ID
|
||||
$posts = $wpdb->get_results("
|
||||
SELECT p.ID, p.post_status, p.post_title, pm.meta_value as task_id
|
||||
FROM {$wpdb->posts} p
|
||||
INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
|
||||
WHERE pm.meta_key = '_igny8_task_id'
|
||||
AND p.post_type IN ('post', 'page', 'product')
|
||||
AND p.post_status != 'trash'
|
||||
");
|
||||
|
||||
$api = new Igny8API();
|
||||
$synced = 0;
|
||||
$failed = 0;
|
||||
|
||||
foreach ($posts as $post_data) {
|
||||
$post_id = $post_data->ID;
|
||||
$task_id = intval($post_data->task_id);
|
||||
$wp_status = $post_data->post_status;
|
||||
|
||||
// Map status
|
||||
$task_status = igny8_map_wp_status_to_igny8($wp_status);
|
||||
|
||||
// Sync to IGNY8
|
||||
$response = $api->put("/writer/tasks/{$task_id}/", array(
|
||||
'status' => $task_status,
|
||||
'assigned_post_id' => $post_id,
|
||||
'post_url' => get_permalink($post_id)
|
||||
));
|
||||
|
||||
if ($response['success']) {
|
||||
update_post_meta($post_id, '_igny8_last_synced', current_time('mysql'));
|
||||
$synced++;
|
||||
} else {
|
||||
$failed++;
|
||||
error_log("IGNY8: Failed to sync post {$post_id}: " . ($response['error'] ?? 'Unknown error'));
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'synced' => $synced,
|
||||
'failed' => $failed,
|
||||
'total' => count($posts)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled sync of WordPress post statuses to IGNY8
|
||||
*/
|
||||
function igny8_cron_sync_post_statuses() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
error_log('IGNY8: Connection disabled, skipping post status sync');
|
||||
return;
|
||||
}
|
||||
|
||||
$result = igny8_batch_sync_post_statuses();
|
||||
|
||||
error_log(sprintf(
|
||||
'IGNY8: Synced %d posts, %d failed',
|
||||
$result['synced'],
|
||||
$result['failed']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled sync of site data
|
||||
*/
|
||||
function igny8_cron_sync_site_data() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
error_log('IGNY8: Connection disabled, skipping site data sync');
|
||||
return;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
|
||||
if (!$site_id) {
|
||||
error_log('IGNY8: Site ID not set, skipping site data sync');
|
||||
return;
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('sites')) {
|
||||
error_log('IGNY8: Sites module disabled, skipping incremental site sync');
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = igny8_get_site_scan_settings(array(
|
||||
'mode' => 'incremental',
|
||||
'since' => get_option('igny8_last_site_sync', 0)
|
||||
));
|
||||
|
||||
$result = igny8_sync_incremental_site_data($site_id, $settings);
|
||||
|
||||
if ($result) {
|
||||
error_log(sprintf(
|
||||
'IGNY8: Synced %d posts to site %d',
|
||||
$result['synced'],
|
||||
$site_id
|
||||
));
|
||||
} else {
|
||||
error_log('IGNY8: Site data sync failed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scheduled full site scan (runs at most once per week)
|
||||
*/
|
||||
function igny8_cron_full_site_scan() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
|
||||
if (!$site_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('sites')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$last_full = intval(get_option('igny8_last_full_site_scan', 0));
|
||||
if ($last_full && (time() - $last_full) < WEEK_IN_SECONDS) {
|
||||
return;
|
||||
}
|
||||
|
||||
$settings = igny8_get_site_scan_settings(array(
|
||||
'mode' => 'full',
|
||||
'since' => null
|
||||
));
|
||||
|
||||
$result = igny8_perform_full_site_scan($site_id, $settings);
|
||||
|
||||
if ($result) {
|
||||
error_log('IGNY8: Full site scan completed');
|
||||
} else {
|
||||
error_log('IGNY8: Full site scan failed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Two-way sync class
|
||||
*/
|
||||
class Igny8WordPressSync {
|
||||
|
||||
/**
|
||||
* API instance
|
||||
*
|
||||
* @var Igny8API
|
||||
*/
|
||||
private $api;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->api = new Igny8API();
|
||||
|
||||
// WordPress → IGNY8 hooks are registered in hooks.php
|
||||
// IGNY8 → WordPress hooks can be added here if needed
|
||||
}
|
||||
}
|
||||
|
||||
425
igny8-wp-integration-plugin/sync/taxonomy-sync.php
Normal file
425
igny8-wp-integration-plugin/sync/taxonomy-sync.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
/**
|
||||
* Taxonomy Synchronization
|
||||
*
|
||||
* Handles synchronization between WordPress taxonomies and IGNY8 sectors/clusters
|
||||
*
|
||||
* @package Igny8Bridge
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync WordPress taxonomy to IGNY8
|
||||
*
|
||||
* @param string $taxonomy Taxonomy name
|
||||
* @return array|false Sync result or false on failure
|
||||
*/
|
||||
function igny8_sync_taxonomy_to_igny8($taxonomy) {
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
if (!$site_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get taxonomy data
|
||||
$taxonomy_obj = get_taxonomy($taxonomy);
|
||||
if (!$taxonomy_obj) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get all terms
|
||||
$terms = get_terms(array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
if (is_wp_error($terms)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Format taxonomy data
|
||||
$taxonomy_data = array(
|
||||
'name' => $taxonomy,
|
||||
'label' => $taxonomy_obj->label,
|
||||
'hierarchical' => $taxonomy_obj->hierarchical,
|
||||
'terms' => array()
|
||||
);
|
||||
|
||||
foreach ($terms as $term) {
|
||||
$taxonomy_data['terms'][] = array(
|
||||
'id' => $term->term_id,
|
||||
'name' => $term->name,
|
||||
'slug' => $term->slug,
|
||||
'description' => $term->description,
|
||||
'parent' => $term->parent
|
||||
);
|
||||
}
|
||||
|
||||
// Send to IGNY8
|
||||
$response = $api->post("/planner/sites/{$site_id}/taxonomies/", array(
|
||||
'taxonomy' => $taxonomy_data
|
||||
));
|
||||
|
||||
return $response['success'] ? $response['data'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync IGNY8 sectors to WordPress taxonomies
|
||||
*
|
||||
* @return array|false Sync result or false on failure
|
||||
*/
|
||||
function igny8_sync_igny8_sectors_to_wp() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('synced' => 0, 'total' => 0, 'skipped' => true, 'disabled' => true);
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
if (!$site_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Respect module toggle
|
||||
$enabled_modules = function_exists('igny8_get_enabled_modules') ? igny8_get_enabled_modules() : array();
|
||||
if (!in_array('planner', $enabled_modules, true)) {
|
||||
return array('synced' => 0, 'total' => 0, 'skipped' => true);
|
||||
}
|
||||
|
||||
// Get sectors from IGNY8
|
||||
$response = $api->get("/planner/sites/{$site_id}/sectors/");
|
||||
|
||||
if (!$response['success']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sectors = $response['results'] ?? array();
|
||||
$synced = 0;
|
||||
|
||||
foreach ($sectors as $sector) {
|
||||
$term = term_exists($sector['name'], 'igny8_sectors');
|
||||
if (!$term) {
|
||||
$term = wp_insert_term(
|
||||
$sector['name'],
|
||||
'igny8_sectors',
|
||||
array(
|
||||
'description' => $sector['description'] ?? '',
|
||||
'slug' => $sector['slug'] ?? sanitize_title($sector['name'])
|
||||
)
|
||||
);
|
||||
} else {
|
||||
wp_update_term($term['term_id'], 'igny8_sectors', array(
|
||||
'description' => $sector['description'] ?? '',
|
||||
'slug' => $sector['slug'] ?? sanitize_title($sector['name'])
|
||||
));
|
||||
}
|
||||
|
||||
if (!is_wp_error($term)) {
|
||||
$term_id = is_array($term) ? $term['term_id'] : $term;
|
||||
update_term_meta($term_id, '_igny8_sector_id', $sector['id']);
|
||||
$synced++;
|
||||
}
|
||||
}
|
||||
|
||||
return array('synced' => $synced, 'total' => count($sectors));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync IGNY8 clusters to WordPress taxonomies
|
||||
*
|
||||
* @param int $sector_id Optional sector ID to filter clusters
|
||||
* @return array|false Sync result or false on failure
|
||||
*/
|
||||
function igny8_sync_igny8_clusters_to_wp($sector_id = null) {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('synced' => 0, 'total' => 0, 'skipped' => true, 'disabled' => true);
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
if (!$site_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$enabled_modules = function_exists('igny8_get_enabled_modules') ? igny8_get_enabled_modules() : array();
|
||||
if (!in_array('planner', $enabled_modules, true)) {
|
||||
return array('synced' => 0, 'total' => 0, 'skipped' => true);
|
||||
}
|
||||
|
||||
// Build endpoint
|
||||
$endpoint = "/planner/sites/{$site_id}/clusters/";
|
||||
if ($sector_id) {
|
||||
$endpoint .= "?sector_id={$sector_id}";
|
||||
}
|
||||
|
||||
// Get clusters from IGNY8
|
||||
$response = $api->get($endpoint);
|
||||
|
||||
if (!$response['success']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$clusters = $response['results'] ?? array();
|
||||
$synced = 0;
|
||||
|
||||
foreach ($clusters as $cluster) {
|
||||
// Get parent sector term if sector_id exists
|
||||
$parent = 0;
|
||||
if (!empty($cluster['sector_id'])) {
|
||||
$sector_terms = get_terms(array(
|
||||
'taxonomy' => 'igny8_sectors',
|
||||
'meta_key' => '_igny8_sector_id',
|
||||
'meta_value' => $cluster['sector_id'],
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
if (!is_wp_error($sector_terms) && !empty($sector_terms)) {
|
||||
$parent = $sector_terms[0]->term_id;
|
||||
}
|
||||
}
|
||||
|
||||
$term_id = 0;
|
||||
$existing = get_terms(array(
|
||||
'taxonomy' => 'igny8_clusters',
|
||||
'meta_key' => '_igny8_cluster_id',
|
||||
'meta_value' => $cluster['id'],
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
if (!is_wp_error($existing) && !empty($existing)) {
|
||||
$term_id = $existing[0]->term_id;
|
||||
}
|
||||
|
||||
if (!$term_id) {
|
||||
$term = term_exists($cluster['name'], 'igny8_clusters');
|
||||
} else {
|
||||
$term = array('term_id' => $term_id);
|
||||
}
|
||||
if (!$term) {
|
||||
$term = wp_insert_term(
|
||||
$cluster['name'],
|
||||
'igny8_clusters',
|
||||
array(
|
||||
'description' => $cluster['description'] ?? '',
|
||||
'slug' => $cluster['slug'] ?? sanitize_title($cluster['name']),
|
||||
'parent' => $parent
|
||||
)
|
||||
);
|
||||
} else {
|
||||
wp_update_term($term['term_id'], 'igny8_clusters', array(
|
||||
'description' => $cluster['description'] ?? '',
|
||||
'slug' => $cluster['slug'] ?? sanitize_title($cluster['name']),
|
||||
'parent' => $parent
|
||||
));
|
||||
}
|
||||
|
||||
if (!is_wp_error($term)) {
|
||||
$term_id = is_array($term) ? $term['term_id'] : $term;
|
||||
update_term_meta($term_id, '_igny8_cluster_id', $cluster['id']);
|
||||
if (!empty($cluster['sector_id'])) {
|
||||
update_term_meta($term_id, '_igny8_sector_id', $cluster['sector_id']);
|
||||
}
|
||||
$synced++;
|
||||
}
|
||||
}
|
||||
|
||||
return array('synced' => $synced, 'total' => count($clusters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron handler: sync sectors/clusters automatically
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function igny8_cron_sync_taxonomies() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
error_log('IGNY8: Connection disabled, skipping taxonomy sync');
|
||||
return array('sectors' => array('skipped' => true), 'clusters' => array('skipped' => true));
|
||||
}
|
||||
|
||||
$results = array(
|
||||
'sectors' => igny8_sync_igny8_sectors_to_wp(),
|
||||
'clusters' => igny8_sync_igny8_clusters_to_wp()
|
||||
);
|
||||
|
||||
update_option('igny8_last_taxonomy_sync', current_time('timestamp'));
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync planner keywords for all referenced clusters
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function igny8_sync_keywords_from_planner() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('synced_clusters' => 0, 'synced_posts' => 0, 'skipped' => true, 'disabled' => true);
|
||||
}
|
||||
|
||||
$api = new Igny8API();
|
||||
|
||||
if (!$api->is_authenticated()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$site_id = get_option('igny8_site_id');
|
||||
if (!$site_id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$enabled_modules = function_exists('igny8_get_enabled_modules') ? igny8_get_enabled_modules() : array();
|
||||
if (!in_array('planner', $enabled_modules, true)) {
|
||||
return array('synced_clusters' => 0, 'synced_posts' => 0, 'skipped' => true);
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
|
||||
$cluster_ids = $wpdb->get_col("
|
||||
SELECT DISTINCT meta_value
|
||||
FROM {$wpdb->postmeta}
|
||||
WHERE meta_key = '_igny8_cluster_id'
|
||||
AND meta_value IS NOT NULL
|
||||
AND meta_value != ''
|
||||
");
|
||||
|
||||
if (empty($cluster_ids)) {
|
||||
return array('synced_clusters' => 0, 'synced_posts' => 0);
|
||||
}
|
||||
|
||||
$enabled_post_types = function_exists('igny8_get_enabled_post_types') ? igny8_get_enabled_post_types() : array('post', 'page');
|
||||
|
||||
$synced_clusters = 0;
|
||||
$synced_posts = 0;
|
||||
|
||||
foreach ($cluster_ids as $cluster_id) {
|
||||
$cluster_id = intval($cluster_id);
|
||||
if (!$cluster_id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$response = $api->get("/planner/keywords/?cluster_id={$cluster_id}&page_size=500");
|
||||
if (!$response['success']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$keywords = $response['results'] ?? array();
|
||||
$keyword_ids = array_map('intval', wp_list_pluck($keywords, 'id'));
|
||||
|
||||
// Update cluster term meta
|
||||
$cluster_terms = get_terms(array(
|
||||
'taxonomy' => 'igny8_clusters',
|
||||
'meta_key' => '_igny8_cluster_id',
|
||||
'meta_value' => $cluster_id,
|
||||
'hide_empty' => false
|
||||
));
|
||||
|
||||
if (!is_wp_error($cluster_terms) && !empty($cluster_terms)) {
|
||||
foreach ($cluster_terms as $term) {
|
||||
update_term_meta($term->term_id, '_igny8_keyword_ids', $keyword_ids);
|
||||
}
|
||||
}
|
||||
|
||||
// Update posts tied to this cluster
|
||||
$posts = get_posts(array(
|
||||
'post_type' => $enabled_post_types,
|
||||
'meta_query' => array(
|
||||
array(
|
||||
'key' => '_igny8_cluster_id',
|
||||
'value' => $cluster_id,
|
||||
'compare' => '='
|
||||
)
|
||||
),
|
||||
'post_status' => 'any',
|
||||
'fields' => 'ids',
|
||||
'nopaging' => true
|
||||
));
|
||||
|
||||
foreach ($posts as $post_id) {
|
||||
update_post_meta($post_id, '_igny8_keyword_ids', $keyword_ids);
|
||||
$synced_posts++;
|
||||
}
|
||||
|
||||
$synced_clusters++;
|
||||
}
|
||||
|
||||
return array(
|
||||
'synced_clusters' => $synced_clusters,
|
||||
'synced_posts' => $synced_posts
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron handler: sync planner keywords
|
||||
*
|
||||
* @return array|false
|
||||
*/
|
||||
function igny8_cron_sync_keywords() {
|
||||
// Skip if connection is disabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
error_log('IGNY8: Connection disabled, skipping keyword sync');
|
||||
return array('synced_clusters' => 0, 'synced_posts' => 0, 'skipped' => true);
|
||||
}
|
||||
|
||||
$result = igny8_sync_keywords_from_planner();
|
||||
if ($result !== false) {
|
||||
update_option('igny8_last_keyword_sync', current_time('timestamp'));
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map WordPress taxonomy term to IGNY8 cluster
|
||||
*
|
||||
* @param int $term_id Term ID
|
||||
* @param string $taxonomy Taxonomy name
|
||||
* @param int $cluster_id IGNY8 cluster ID
|
||||
* @return bool True on success
|
||||
*/
|
||||
function igny8_map_term_to_cluster($term_id, $taxonomy, $cluster_id) {
|
||||
if ($taxonomy !== 'igny8_clusters') {
|
||||
return false;
|
||||
}
|
||||
|
||||
update_term_meta($term_id, '_igny8_cluster_id', $cluster_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map WordPress taxonomy to IGNY8 sector
|
||||
*
|
||||
* @param string $taxonomy Taxonomy name
|
||||
* @param int $sector_id IGNY8 sector ID
|
||||
* @return bool True on success
|
||||
*/
|
||||
function igny8_map_taxonomy_to_sector($taxonomy, $sector_id) {
|
||||
// Store mapping in options
|
||||
$mappings = get_option('igny8_taxonomy_sector_mappings', array());
|
||||
$mappings[$taxonomy] = $sector_id;
|
||||
update_option('igny8_taxonomy_sector_mappings', $mappings);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user