'sanitize_text_field', 'default' => '' ) ); register_setting( 'aiflab_chatweb_settings_group', 'aiflab_chatweb_enable_embed', array( 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false ) ); register_setting( 'aiflab_chatweb_settings_group', 'aiflab_chatweb_embed_code', array( 'sanitize_callback' => array($this, 'sanitize_embed_code_setting'), 'default' => '' ) ); register_setting( 'aiflab_chatweb_settings_group', 'aiflab_chatweb_enable_woocommerce_sync', array( 'sanitize_callback' => 'rest_sanitize_boolean', 'default' => false ) ); // Add action to flush rewrite rules after settings are saved add_action('update_option_aiflab_chatweb_enable_embed', function ($old_value, $new_value) { // Check if enable_embed setting has changed if ($old_value !== $new_value) { // Flush rewrite rules flush_rewrite_rules(); // Clear any cache if (function_exists('wp_cache_flush')) { wp_cache_flush(); } } }, 10, 2); } /** * Sanitize settings */ public function sanitize_settings($settings) { // Use public sanitize_settings method from Aiflab_Chatweb_Config return Aiflab_Chatweb_Config::sanitize_settings($settings); } /** * Main admin page */ public function admin_page() { ?>

<?php echo esc_attr(Aiflab_Chatweb_i18n::t('common.logo_alt')); ?>

/>

/>


Floor 11, Viet A Building, No. 9 Duy Tan Street,
Dich Vong Hau Ward, Cau Giay District,
Ha Noi City, Vietnam


hello@chatweb.io
+(84) 978.229.954

0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('api_key.auth_error') . $e->getMessage() )); return; } if (!current_user_can('manage_options')) { while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } $api_key = isset($_POST['api_key']) ? sanitize_text_field(wp_unslash($_POST['api_key'])) : ''; $debug_log = isset($_POST['debug_log']) ? (bool)$_POST['debug_log'] : true; // Always enable debug log if (empty($api_key)) { while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('api_key.empty_error') )); return; } try { // Initialize API with new key $api = new Aiflab_Chatweb_API(); $api->set_api_key($api_key); // Step 1: Check if activation is needed (new API key) if ($api->needs_activation()) { $activate_result = $api->activate_website(); if ($activate_result['success']) { // Mark this API key as activated $api->mark_as_activated(); } else { // Activation failed - return error while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => $activate_result['error'] ?? Aiflab_Chatweb_i18n::t('api_key.activation_failed') )); return; } } // Step 2: Get embed code (existing logic) $embed_result = $api->get_website_embed(); if ($embed_result['success']) { // Save API key to settings try { $api_key_saved = Aiflab_Chatweb_Config::update_setting('api_key', $api_key); // Backup: Save API key directly update_option('aiflab_chatweb_api_key', $api_key); } catch (Exception $e) { // Log error but continue error_log('ChatWeb: Failed to save API key: ' . $e->getMessage()); } $embed_code = ''; // If embed code was returned, save it if (isset($embed_result['data']['embed_code'])) { try { $embed_code = $embed_result['data']['embed_code']; // Save embed code to settings (use only 1 method) $embed_saved = Aiflab_Chatweb_Config::set_embed_code($embed_code); // Clear cache after saving embed code if ($embed_saved) { // Clear WordPress object cache if (function_exists('wp_cache_flush')) { @wp_cache_flush(); } // Clear plugin caches @Aiflab_Chatweb_Config::clear_plugin_caches(); } // Automatically enable embed feature if embed code is retrieved Aiflab_Chatweb_Config::update_setting('enable_embed', true); // Check again if embed code has been saved $saved_embed_code = Aiflab_Chatweb_Config::get_embed_code(); } catch (Exception $e) { // Log error but continue error_log('ChatWeb: Failed to save embed code: ' . $e->getMessage()); } } while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => true, 'message' => Aiflab_Chatweb_i18n::t('api_key.save_success'), 'embed_code' => $embed_code, 'auto_enabled' => true, 'debug_info' => $embed_result )); } else { // Ensure error is a string $error_message = is_string($embed_result['error']) ? $embed_result['error'] : (is_array($embed_result['error']) ? json_encode($embed_result['error']) : Aiflab_Chatweb_i18n::t('api_key.invalid_error')); while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => $error_message, 'debug_info' => $embed_result )); } } catch (Exception $e) { while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('api_key.test_error') . $e->getMessage() )); } catch (Error $e) { while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('api_key.critical_error') . $e->getMessage() )); } } /** * AJAX get embed code */ public function ajax_get_embed_code() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } $api = new Aiflab_Chatweb_API(); // Check if API key is configured if (!$api->has_api_key()) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('api_key.not_configured') )); return; } // Log for debugging // Get embed code from API $result = $api->get_website_embed(); // Log the result for debugging if ($result['success'] && isset($result['data']['embed_code'])) { // Save embed code to settings (use set_embed_code for consistency) $embed_saved = Aiflab_Chatweb_Config::set_embed_code($result['data']['embed_code']); // Clear cache after saving embed code if ($embed_saved) { // Clear WordPress object cache if (function_exists('wp_cache_flush')) { wp_cache_flush(); } // Clear plugin caches Aiflab_Chatweb_Config::clear_plugin_caches(); // Verify the embed code was saved correctly $saved_embed_code = Aiflab_Chatweb_Config::get_embed_code(); } ob_end_clean(); wp_send_json(array( 'success' => true, 'data' => array( 'embed_code' => $result['data']['embed_code'] ), 'message' => Aiflab_Chatweb_i18n::t('embed.refresh_success'), 'saved' => $embed_saved )); } else { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => isset($result['error']) ? $result['error'] : Aiflab_Chatweb_i18n::t('embed.refresh_error') )); } } /** * AJAX get dashboard data */ public function ajax_get_dashboard_data() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } $api = new Aiflab_Chatweb_API(); $result = $api->get_dashboard_data(); ob_end_clean(); wp_send_json($result); } /** * AJAX clear cache */ public function ajax_clear_cache() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } Aiflab_Chatweb_Config::clear_cache(); ob_end_clean(); wp_send_json(array( 'success' => true, 'message' => Aiflab_Chatweb_i18n::t('cache.clear_success') )); } /** * AJAX clear embed code */ public function ajax_clear_embed_code() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } Aiflab_Chatweb_Config::clear_embed_code(); ob_end_clean(); wp_send_json(array( 'success' => true, 'message' => Aiflab_Chatweb_i18n::t('embed.delete_success') )); } /** * AJAX sync all products */ public function ajax_sync_all_products() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } // Check if WooCommerce is active if (!class_exists('WooCommerce')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('woocommerce.not_activated') )); return; } // Get batch parameters $batch_size = 50; // Number of products per batch $batch = isset($_POST['batch']) ? intval($_POST['batch']) : 1; $is_first_batch = $batch === 1; // Initialize WooCommerce sync $woocommerce_sync = new Aiflab_Chatweb_WooCommerce(); // Get products across syncable statuses so manual sync can reconcile hidden items too. $args = array( 'post_type' => 'product', 'post_status' => array('publish', 'private', 'draft', 'pending'), 'posts_per_page' => -1, 'fields' => 'ids' ); $all_product_ids = get_posts($args); $total_products = count($all_product_ids); if (empty($all_product_ids)) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('sync_products.no_products') )); return; } // If first batch, store product IDs in transient to ensure consistency if ($is_first_batch) { set_transient('aiflab_chatweb_sync_product_ids', $all_product_ids, 3600); // 1 hour expiration $this->log_sync_start($total_products); } else { // Get stored product IDs from transient $stored_product_ids = get_transient('aiflab_chatweb_sync_product_ids'); if ($stored_product_ids) { $all_product_ids = $stored_product_ids; $total_products = count($all_product_ids); } } // Calculate offset and get current batch of products $offset = ($batch - 1) * $batch_size; $current_batch_ids = array_slice($all_product_ids, $offset, $batch_size); // If no more products in this batch, we're done if (empty($current_batch_ids)) { // Clean up transient delete_transient('aiflab_chatweb_sync_product_ids'); // Log completion $this->log_sync_complete($total_products); ob_end_clean(); wp_send_json(array( 'success' => true, 'data' => array( 'total' => $total_products, 'synced' => $total_products, // Assume all synced 'failed' => 0, 'is_complete' => true ), 'message' => Aiflab_Chatweb_i18n::t('sync_products.complete', array($total_products)) )); return; } // Prepare product data for bulk sync $synced = 0; $failed = 0; $failed_products = array(); $products_data = array(); // Collect product data for all products in batch foreach ($current_batch_ids as $product_id) { $product_data = $woocommerce_sync->prepare_product_data_for_bulk($product_id); if ($product_data) { $products_data[] = $product_data; } else { // Product data preparation failed $failed++; $product = wc_get_product($product_id); $failed_products[] = array( 'id' => $product_id, 'name' => $product ? $product->get_name() : 'Unknown', 'error' => 'Failed to prepare product data' ); } } // Bulk sync all products in this batch if (!empty($products_data)) { $result = $woocommerce_sync->bulk_sync_products($products_data); if ($result['success']) { // All products in batch synced successfully $synced = count($products_data); } else { // Entire batch failed $failed += count($products_data); // Add all products to failed list foreach ($products_data as $product_data) { $product_id = isset($product_data['source_product_id']) ? (int) $product_data['source_product_id'] : 0; $product = wc_get_product($product_id); $failed_products[] = array( 'id' => $product_id, 'name' => $product ? $product->get_name() : 'Unknown', 'error' => isset($result['error']) ? $result['error'] : 'Bulk sync failed' ); } } } // Log batch progress $processed_so_far = $offset + count($current_batch_ids); $this->log_sync_batch_progress($batch, $processed_so_far, $total_products, $synced, $failed, $failed_products); // Calculate progress $is_complete = $processed_so_far >= $total_products; $next_batch = $is_complete ? null : $batch + 1; // If complete, clean up transient if ($is_complete) { delete_transient('aiflab_chatweb_sync_product_ids'); $this->log_sync_complete($total_products); } ob_end_clean(); wp_send_json(array( 'success' => true, 'data' => array( 'total' => $total_products, 'processed' => $processed_so_far, 'synced' => $synced, 'failed' => $failed, 'failed_products' => $failed_products, 'is_complete' => $is_complete, 'next_batch' => $next_batch, 'batch_size' => $batch_size, 'batch' => $batch ), 'message' => $is_complete ? Aiflab_Chatweb_i18n::t('sync_products.complete', array($processed_so_far)) : Aiflab_Chatweb_i18n::t('sync_products.progress', array($processed_so_far, $total_products)) )); } /** * Log sync start * * @param int $total_products */ private function log_sync_start($total_products) { $log_data = array( 'time' => current_time('mysql'), 'action' => 'sync_start', 'total_products' => $total_products, 'user_id' => get_current_user_id(), 'user_login' => wp_get_current_user()->user_login ); // $this->write_to_sync_log($log_data); } /** * Log sync batch progress * * @param int $batch * @param int $processed * @param int $total * @param int $synced * @param int $failed * @param array $failed_products */ private function log_sync_batch_progress($batch, $processed, $total, $synced, $failed, $failed_products) { $log_data = array( 'time' => current_time('mysql'), 'action' => 'sync_batch_progress', 'batch' => $batch, 'processed' => $processed, 'total' => $total, 'synced' => $synced, 'failed' => $failed, 'failed_products' => $failed_products ); // $this->write_to_sync_log($log_data); } /** * Log sync complete * * @param int $total_products */ private function log_sync_complete($total_products) { $log_data = array( 'time' => current_time('mysql'), 'action' => 'sync_complete', 'total_products' => $total_products, 'user_id' => get_current_user_id(), 'user_login' => wp_get_current_user()->user_login ); // $this->write_to_sync_log($log_data); } /** * Write to sync log file * * @param array $log_data * @return bool Success or failure */ private function write_to_sync_log($log_data) { try { // Get upload directory $upload_dir = wp_upload_dir(); // Check if upload directory is writable if (isset($upload_dir['error']) && $upload_dir['error'] !== false) { return false; } $logs_dir = $upload_dir['basedir'] . '/aiflab-chatweb-logs'; // Try to create logs directory if it doesn't exist if (!file_exists($logs_dir)) { $dir_created = wp_mkdir_p($logs_dir); if (!$dir_created) { return false; } // Create .htaccess to protect logs $htaccess_file = $logs_dir . '/.htaccess'; $htaccess_content = "Order deny,allow\nDeny from all"; $htaccess_written = @file_put_contents($htaccess_file, $htaccess_content); // Create index.php to prevent directory listing $index_file = $logs_dir . '/index.php'; $index_content = ' false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } // Chuyển đổi giá trị từ POST thành boolean $enable_embed = isset($_POST['enable_embed']) && sanitize_text_field(wp_unslash($_POST['enable_embed'])) ? true : false; $enable_embed_bool = (bool) $enable_embed; // Lấy giá trị hiện tại và normalize về boolean để so sánh $current_value_raw = Aiflab_Chatweb_Config::get_setting('enable_embed', false); $current_value = filter_var($current_value_raw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if ($current_value === null) { $current_value = (bool) $current_value_raw; } // Cập nhật cài đặt thông qua Aiflab_Chatweb_Config $result = Aiflab_Chatweb_Config::update_setting('enable_embed', $enable_embed_bool); // update_option() trả về false nếu giá trị không thay đổi // Nếu result là false, kiểm tra xem giá trị có thực sự khác không // Nếu giá trị giống nhau (sau khi normalize), coi như thành công $value_changed = false; if ($result === false) { // Kiểm tra lại giá trị sau khi update để xác định có phải do không thay đổi không $updated_value_raw = Aiflab_Chatweb_Config::get_setting('enable_embed', false); $updated_value = filter_var($updated_value_raw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if ($updated_value === null) { $updated_value = (bool) $updated_value_raw; } // Nếu giá trị sau khi update giống với giá trị muốn set, coi như thành công $success = ($updated_value === $enable_embed_bool); $value_changed = ($current_value !== $enable_embed_bool); } else { $success = true; $value_changed = ($current_value !== $enable_embed_bool); } // Flush rewrite rules nếu cần và giá trị đã thay đổi if ($success && $value_changed) { // Suppress any output from these functions @flush_rewrite_rules(); // Clear cache if (function_exists('wp_cache_flush')) { @wp_cache_flush(); } // Clear plugin caches @Aiflab_Chatweb_Config::clear_plugin_caches(); } // Clean any buffered output before sending JSON while (ob_get_level() > 0) { ob_end_clean(); } wp_send_json(array( 'success' => $success, 'message' => $success ? Aiflab_Chatweb_i18n::t('embed_settings.save_success') : Aiflab_Chatweb_i18n::t('embed_settings.save_error'), 'data' => array( 'enable_embed' => $enable_embed_bool ) )); } /** * AJAX update WooCommerce settings */ public function ajax_update_woocommerce_settings() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } // Chuyển đổi giá trị từ POST thành boolean $enable_woocommerce_sync = isset($_POST['enable_woocommerce_sync']) && sanitize_text_field(wp_unslash($_POST['enable_woocommerce_sync'])) ? true : false; $enable_woocommerce_sync_bool = (bool) $enable_woocommerce_sync; // Lấy giá trị hiện tại và normalize về boolean để so sánh $current_value_raw = Aiflab_Chatweb_Config::get_setting('enable_woocommerce_sync', false); $current_value = filter_var($current_value_raw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if ($current_value === null) { $current_value = (bool) $current_value_raw; } // Cập nhật cài đặt thông qua Aiflab_Chatweb_Config $result = Aiflab_Chatweb_Config::update_setting('enable_woocommerce_sync', $enable_woocommerce_sync_bool); // update_option() trả về false nếu giá trị không thay đổi // Nếu result là false, kiểm tra xem giá trị có thực sự khác không // Nếu giá trị giống nhau (sau khi normalize), coi như thành công if ($result === false) { // Kiểm tra lại giá trị sau khi update để xác định có phải do không thay đổi không $updated_value_raw = Aiflab_Chatweb_Config::get_setting('enable_woocommerce_sync', false); $updated_value = filter_var($updated_value_raw, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); if ($updated_value === null) { $updated_value = (bool) $updated_value_raw; } // Nếu giá trị sau khi update giống với giá trị muốn set, coi như thành công $success = ($updated_value === $enable_woocommerce_sync_bool); } else { $success = true; } ob_end_clean(); wp_send_json(array( 'success' => $success, 'message' => $success ? Aiflab_Chatweb_i18n::t('woocommerce.save_success') : Aiflab_Chatweb_i18n::t('embed_settings.save_error'), 'data' => array( 'enable_woocommerce_sync' => $enable_woocommerce_sync_bool ) )); } /** * AJAX get sync logs */ public function ajax_get_sync_logs() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } // Get date parameter $date = isset($_POST['date']) ? sanitize_text_field(wp_unslash($_POST['date'])) : gmdate('Y-m-d'); $log_type = isset($_POST['log_type']) ? sanitize_text_field(wp_unslash($_POST['log_type'])) : 'summary'; // Get upload directory $upload_dir = wp_upload_dir(); if (isset($upload_dir['error']) && $upload_dir['error'] !== false) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('logs.upload_access_error') . $upload_dir['error'] )); return; } $logs_dir = $upload_dir['basedir'] . '/aiflab-chatweb-logs'; if (!file_exists($logs_dir)) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('logs.dir_not_found') )); return; } // Determine log file path based on log type $log_file = ''; if ($log_type === 'detailed') { $log_file = $logs_dir . '/product-sync-detailed-' . $date . '.log'; } else { $log_file = $logs_dir . '/product-sync-' . $date . '.log'; } if (!file_exists($log_file)) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('logs.file_not_found') )); return; } // Read log file $log_content = file_get_contents($log_file); if ($log_content === false) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('logs.read_error') )); return; } // Parse log entries $log_entries = array(); $entries = explode("\n", $log_content); foreach ($entries as $entry) { if (empty(trim($entry)) || $entry === '---') { continue; } $parsed_entry = json_decode($entry, true); if ($parsed_entry) { $log_entries[] = $parsed_entry; } } // Get available log dates $available_dates = array(); $log_files = glob($logs_dir . '/product-sync-*.log'); foreach ($log_files as $file) { if (preg_match('/product-sync-(\d{4}-\d{2}-\d{2})\.log$/', $file, $matches)) { $available_dates[] = $matches[1]; } } // Sort dates in descending order rsort($available_dates); ob_end_clean(); wp_send_json(array( 'success' => true, 'data' => array( 'entries' => $log_entries, 'available_dates' => $available_dates, 'current_date' => $date, 'log_type' => $log_type ) )); } /** * AJAX sync all posts */ public function ajax_sync_all_posts() { // Suppress any output that might interfere with JSON response ob_start(); check_ajax_referer('aiflab_chatweb_nonce', 'nonce'); if (!current_user_can('manage_options')) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('common.no_permission') )); return; } // Get batch parameters $batch_size = 10; // Number of posts per batch $batch = isset($_POST['batch']) ? intval($_POST['batch']) : 1; $is_first_batch = $batch === 1; // Initialize Posts sync $posts_sync = new Aiflab_Chatweb_Posts(); // Get all published posts $args = array( 'post_type' => 'post', 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids' ); $all_post_ids = get_posts($args); $total_posts = count($all_post_ids); if (empty($all_post_ids)) { ob_end_clean(); wp_send_json(array( 'success' => false, 'error' => Aiflab_Chatweb_i18n::t('sync_posts.no_posts') )); return; } // If first batch, store post IDs and reset counters in transient if ($is_first_batch) { set_transient('aiflab_chatweb_sync_post_ids', $all_post_ids, 3600); // 1 hour expiration set_transient('aiflab_chatweb_sync_post_synced', 0, 3600); set_transient('aiflab_chatweb_sync_post_failed', 0, 3600); set_transient('aiflab_chatweb_sync_post_failed_posts', array(), 3600); } else { // Get stored post IDs from transient $stored_post_ids = get_transient('aiflab_chatweb_sync_post_ids'); if ($stored_post_ids) { $all_post_ids = $stored_post_ids; $total_posts = count($all_post_ids); } } // Get accumulated counts from previous batches $total_synced = (int) get_transient('aiflab_chatweb_sync_post_synced'); $total_failed = (int) get_transient('aiflab_chatweb_sync_post_failed'); $all_failed_posts = get_transient('aiflab_chatweb_sync_post_failed_posts'); if (!is_array($all_failed_posts)) { $all_failed_posts = array(); } // Calculate offset and get current batch of posts $offset = ($batch - 1) * $batch_size; $current_batch_ids = array_slice($all_post_ids, $offset, $batch_size); // If no more posts in this batch, we're done if (empty($current_batch_ids)) { // Clean up transients delete_transient('aiflab_chatweb_sync_post_ids'); delete_transient('aiflab_chatweb_sync_post_synced'); delete_transient('aiflab_chatweb_sync_post_failed'); delete_transient('aiflab_chatweb_sync_post_failed_posts'); // Cleanup temp JSON files $posts_sync->cleanup_temp_files(); ob_end_clean(); wp_send_json(array( 'success' => true, 'data' => array( 'total' => $total_posts, 'synced' => $total_synced, 'failed' => $total_failed, 'failed_posts' => $all_failed_posts, 'is_complete' => true ), 'message' => Aiflab_Chatweb_i18n::t('sync_posts.result', array($total_posts, $total_synced, $total_failed)) )); return; } // Sync posts in current batch $batch_results = $posts_sync->sync_posts_batch($current_batch_ids); // Accumulate counts $batch_synced = $batch_results['synced']; $batch_failed = $batch_results['failed']; $batch_failed_posts = $batch_results['failed_posts']; $total_synced += $batch_synced; $total_failed += $batch_failed; $all_failed_posts = array_merge($all_failed_posts, $batch_failed_posts); // Save accumulated counts to transient set_transient('aiflab_chatweb_sync_post_synced', $total_synced, 3600); set_transient('aiflab_chatweb_sync_post_failed', $total_failed, 3600); set_transient('aiflab_chatweb_sync_post_failed_posts', $all_failed_posts, 3600); // Calculate total processed $processed = $offset + count($current_batch_ids); // Determine if there are more batches $has_more = $processed < $total_posts; $next_batch = $has_more ? $batch + 1 : null; // If this is the last batch, cleanup transients and temp files if (!$has_more) { delete_transient('aiflab_chatweb_sync_post_ids'); delete_transient('aiflab_chatweb_sync_post_synced'); delete_transient('aiflab_chatweb_sync_post_failed'); delete_transient('aiflab_chatweb_sync_post_failed_posts'); $posts_sync->cleanup_temp_files(); } ob_end_clean(); // Build accurate completion message $complete_message = ''; if (!$has_more) { $complete_message = Aiflab_Chatweb_i18n::t('sync_posts.result', array($total_posts, $total_synced, $total_failed)); } else { $complete_message = Aiflab_Chatweb_i18n::t('sync_posts.progress', array($processed, $total_posts)); } wp_send_json(array( 'success' => true, 'data' => array( 'total' => $total_posts, 'processed' => $processed, 'synced' => $total_synced, 'failed' => $total_failed, 'failed_posts' => $all_failed_posts, 'is_complete' => !$has_more, 'next_batch' => $next_batch ), 'message' => $complete_message )); } // Debug page removed in v1.0.3 }