|
|
@@ -33,67 +33,132 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
|
|
|
// Register AJAX handlers
|
|
|
add_action('wp_ajax_studiou_wcpcm_move_products', array($this, 'handle_move_products_ajax'));
|
|
|
+
|
|
|
+ // Add a test AJAX handler to verify AJAX is working
|
|
|
+ add_action('wp_ajax_studiou_wcpcm_test', array($this, 'handle_test_ajax'));
|
|
|
+
|
|
|
+ // Debug: Log that the handler is being registered
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: AJAX handler wp_ajax_studiou_wcpcm_move_products registered');
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Test AJAX handler to verify AJAX is working
|
|
|
+ */
|
|
|
+ public function handle_test_ajax() {
|
|
|
+ error_log('STUDIOU WC: Test AJAX handler called');
|
|
|
+ wp_send_json_success(array('message' => 'AJAX is working'));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Handle AJAX move products request
|
|
|
*/
|
|
|
public function handle_move_products_ajax() {
|
|
|
- // Check nonce
|
|
|
- if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'studiou-wcpcm-nonce')) {
|
|
|
- wp_send_json_error(array(
|
|
|
- 'message' => __('Security check failed', 'studiou-wc-product-cat-manage')
|
|
|
- ));
|
|
|
+ // Clean all output buffers and prevent any output
|
|
|
+ while (ob_get_level()) {
|
|
|
+ ob_end_clean();
|
|
|
}
|
|
|
|
|
|
- // Check permissions
|
|
|
- if (!current_user_can('manage_woocommerce')) {
|
|
|
- wp_send_json_error(array(
|
|
|
- 'message' => __('You do not have sufficient permissions', 'studiou-wc-product-cat-manage')
|
|
|
- ));
|
|
|
- }
|
|
|
+ // Start a new output buffer to catch any unwanted output
|
|
|
+ ob_start();
|
|
|
|
|
|
- // Validate input
|
|
|
- if (!isset($_POST['source_category']) || !isset($_POST['target_category'])) {
|
|
|
- wp_send_json_error(array(
|
|
|
- 'message' => __('Missing required parameters', 'studiou-wc-product-cat-manage')
|
|
|
- ));
|
|
|
- }
|
|
|
+ // Suppress PHP errors/notices during AJAX to prevent JSON corruption
|
|
|
+ $original_error_reporting = error_reporting();
|
|
|
+ error_reporting(0);
|
|
|
|
|
|
- $source_category_id = intval($_POST['source_category']);
|
|
|
- $target_category_id = intval($_POST['target_category']);
|
|
|
-
|
|
|
- // Validate categories
|
|
|
- if ($source_category_id === $target_category_id) {
|
|
|
- wp_send_json_error(array(
|
|
|
- 'message' => __('Source and target categories must be different', 'studiou-wc-product-cat-manage')
|
|
|
- ));
|
|
|
- }
|
|
|
-
|
|
|
- if ($source_category_id <= 0 || $target_category_id <= 0) {
|
|
|
- wp_send_json_error(array(
|
|
|
- 'message' => __('Invalid category selection', 'studiou-wc-product-cat-manage')
|
|
|
- ));
|
|
|
+ // Enable error logging only
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: AJAX handler called');
|
|
|
+ error_log('STUDIOU WC: POST data: ' . print_r($_POST, true));
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
+ // Check nonce
|
|
|
+ if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'studiou-wcpcm-nonce')) {
|
|
|
+ wp_send_json_error(array(
|
|
|
+ 'message' => __('Security check failed', 'studiou-wc-product-cat-manage')
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Check permissions
|
|
|
+ if (!current_user_can('manage_woocommerce')) {
|
|
|
+ wp_send_json_error(array(
|
|
|
+ 'message' => __('You do not have sufficient permissions', 'studiou-wc-product-cat-manage')
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate input
|
|
|
+ if (!isset($_POST['source_category']) || !isset($_POST['target_category'])) {
|
|
|
+ wp_send_json_error(array(
|
|
|
+ 'message' => __('Missing required parameters', 'studiou-wc-product-cat-manage')
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ $source_category_id = intval($_POST['source_category']);
|
|
|
+ $target_category_id = intval($_POST['target_category']);
|
|
|
+
|
|
|
+ // Debug logging
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Move operation started - Source: ' . $source_category_id . ', Target: ' . $target_category_id);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Validate categories
|
|
|
+ if ($source_category_id === $target_category_id) {
|
|
|
+ wp_send_json_error(array(
|
|
|
+ 'message' => __('Source and target categories must be different', 'studiou-wc-product-cat-manage')
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($source_category_id <= 0 || $target_category_id <= 0) {
|
|
|
+ wp_send_json_error(array(
|
|
|
+ 'message' => __('Invalid category selection', 'studiou-wc-product-cat-manage')
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
// Execute move operation
|
|
|
$result = $this->move_products_between_categories($source_category_id, $target_category_id);
|
|
|
|
|
|
+ // Debug logging
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Move operation completed - Moved: ' . $result['moved_count'] . ' products');
|
|
|
+ error_log('STUDIOU WC: Sending success response: ' . print_r($result, true));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Clean any output that might have been generated
|
|
|
+ ob_clean();
|
|
|
+
|
|
|
// Return success response
|
|
|
wp_send_json_success(array(
|
|
|
'message' => $result['message'],
|
|
|
'moved_count' => $result['moved_count'],
|
|
|
'source_count' => $result['source_count'],
|
|
|
- 'target_count' => $result['target_count']
|
|
|
+ 'target_count' => $result['target_count'],
|
|
|
+ 'failed_count' => isset($result['failed_count']) ? $result['failed_count'] : 0
|
|
|
));
|
|
|
+
|
|
|
} catch (Exception $e) {
|
|
|
+ // Debug logging
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Move operation failed - ' . $e->getMessage());
|
|
|
+ error_log('STUDIOU WC: Exception trace: ' . $e->getTraceAsString());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Clean any output that might have been generated
|
|
|
+ ob_clean();
|
|
|
+
|
|
|
wp_send_json_error(array(
|
|
|
'message' => sprintf(
|
|
|
__('Error during move operation: %s', 'studiou-wc-product-cat-manage'),
|
|
|
$e->getMessage()
|
|
|
)
|
|
|
));
|
|
|
+ } finally {
|
|
|
+ // Restore original error reporting
|
|
|
+ error_reporting($original_error_reporting);
|
|
|
+
|
|
|
+ // End the output buffer
|
|
|
+ ob_end_clean();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -114,23 +179,32 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
throw new Exception(__('Invalid category specified', 'studiou-wc-product-cat-manage'));
|
|
|
}
|
|
|
|
|
|
- // Get all products in source category
|
|
|
- $product_args = array(
|
|
|
- 'post_type' => 'product',
|
|
|
- 'post_status' => array('publish', 'private', 'draft'),
|
|
|
- 'posts_per_page' => -1,
|
|
|
- 'fields' => 'ids',
|
|
|
- 'tax_query' => array(
|
|
|
- array(
|
|
|
- 'taxonomy' => 'product_cat',
|
|
|
- 'field' => 'term_id',
|
|
|
- 'terms' => $source_category_id,
|
|
|
- )
|
|
|
- )
|
|
|
- );
|
|
|
+ // Get initial count of products in source category using direct DB query
|
|
|
+ $initial_source_count = $this->get_category_product_count($source_category_id);
|
|
|
|
|
|
- $products = get_posts($product_args);
|
|
|
+ // Check if source category has any products
|
|
|
+ if ($initial_source_count === 0) {
|
|
|
+ $message = sprintf(
|
|
|
+ __('No products found in source category "%s". Nothing to move.', 'studiou-wc-product-cat-manage'),
|
|
|
+ $source_category->name
|
|
|
+ );
|
|
|
+
|
|
|
+ return array(
|
|
|
+ 'moved_count' => 0,
|
|
|
+ 'source_count' => 0,
|
|
|
+ 'target_count' => $this->get_category_product_count($target_category_id),
|
|
|
+ 'message' => $message
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ // Get all products in source category using direct DB query
|
|
|
+ $products = $this->get_products_in_category($source_category_id);
|
|
|
$moved_count = 0;
|
|
|
+ $failed_count = 0;
|
|
|
+
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Found ' . count($products) . ' products in category ' . $source_category->name . ' for moving');
|
|
|
+ }
|
|
|
|
|
|
// Move each product
|
|
|
foreach ($products as $product_id) {
|
|
|
@@ -138,6 +212,10 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
$current_categories = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids'));
|
|
|
|
|
|
if (is_wp_error($current_categories)) {
|
|
|
+ $failed_count++;
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Error getting categories for product ' . $product_id . ': ' . $current_categories->get_error_message());
|
|
|
+ }
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
@@ -150,27 +228,52 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
|
|
|
if (!is_wp_error($result)) {
|
|
|
$moved_count++;
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Successfully moved product ' . $product_id . ' from category ' . $source_category_id . ' to ' . $target_category_id);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ $failed_count++;
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Error moving product ' . $product_id . ': ' . $result->get_error_message());
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Get updated counts
|
|
|
+ // Get updated counts using direct DB query
|
|
|
$source_count = $this->get_category_product_count($source_category_id);
|
|
|
$target_count = $this->get_category_product_count($target_category_id);
|
|
|
|
|
|
- // Generate result message
|
|
|
- $message = sprintf(
|
|
|
- __('Moved %d products from "%s" to "%s". Source category now has %d products, target category now has %d products.', 'studiou-wc-product-cat-manage'),
|
|
|
- $moved_count,
|
|
|
- $source_category->name,
|
|
|
- $target_category->name,
|
|
|
- $source_count,
|
|
|
- $target_count
|
|
|
- );
|
|
|
+ // Generate detailed result message
|
|
|
+ if ($moved_count === 0 && count($products) > 0) {
|
|
|
+ $message = sprintf(
|
|
|
+ __('Failed to move any products from "%s" to "%s". All %d products encountered errors during the move operation.', 'studiou-wc-product-cat-manage'),
|
|
|
+ $source_category->name,
|
|
|
+ $target_category->name,
|
|
|
+ count($products)
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ $message = sprintf(
|
|
|
+ __('Moved %d products from "%s" to "%s". Source category now has %d products, target category now has %d products.', 'studiou-wc-product-cat-manage'),
|
|
|
+ $moved_count,
|
|
|
+ $source_category->name,
|
|
|
+ $target_category->name,
|
|
|
+ $source_count,
|
|
|
+ $target_count
|
|
|
+ );
|
|
|
+
|
|
|
+ if ($failed_count > 0) {
|
|
|
+ $message .= ' ' . sprintf(
|
|
|
+ __('Note: %d products failed to move due to errors.', 'studiou-wc-product-cat-manage'),
|
|
|
+ $failed_count
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return array(
|
|
|
'moved_count' => $moved_count,
|
|
|
'source_count' => $source_count,
|
|
|
'target_count' => $target_count,
|
|
|
+ 'failed_count' => $failed_count,
|
|
|
'message' => $message
|
|
|
);
|
|
|
}
|
|
|
@@ -182,22 +285,60 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
* @return int Product count
|
|
|
*/
|
|
|
private function get_category_product_count($category_id) {
|
|
|
- $args = array(
|
|
|
- 'post_type' => 'product',
|
|
|
- 'post_status' => array('publish', 'private', 'draft'),
|
|
|
- 'posts_per_page' => -1,
|
|
|
- 'fields' => 'ids',
|
|
|
- 'tax_query' => array(
|
|
|
- array(
|
|
|
- 'taxonomy' => 'product_cat',
|
|
|
- 'field' => 'term_id',
|
|
|
- 'terms' => $category_id,
|
|
|
- )
|
|
|
- )
|
|
|
- );
|
|
|
+ global $wpdb;
|
|
|
+
|
|
|
+ // Use direct database query for more accurate counting
|
|
|
+ $sql = "
|
|
|
+ SELECT COUNT(DISTINCT p.ID)
|
|
|
+ FROM {$wpdb->posts} p
|
|
|
+ INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
|
|
|
+ INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
|
|
|
+ WHERE tt.term_id = %d
|
|
|
+ AND tt.taxonomy = 'product_cat'
|
|
|
+ AND p.post_type = 'product'
|
|
|
+ AND p.post_status IN ('publish', 'private', 'draft')
|
|
|
+ ";
|
|
|
+
|
|
|
+ $count = $wpdb->get_var($wpdb->prepare($sql, $category_id));
|
|
|
+
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Category ' . $category_id . ' product count (direct DB query): ' . intval($count));
|
|
|
+ }
|
|
|
+
|
|
|
+ return intval($count);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Get all products in a category
|
|
|
+ *
|
|
|
+ * @param int $category_id Category ID
|
|
|
+ * @return array Array of product IDs
|
|
|
+ */
|
|
|
+ private function get_products_in_category($category_id) {
|
|
|
+ global $wpdb;
|
|
|
+
|
|
|
+ // Use direct database query to get products
|
|
|
+ $sql = "
|
|
|
+ SELECT DISTINCT p.ID
|
|
|
+ FROM {$wpdb->posts} p
|
|
|
+ INNER JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
|
|
|
+ INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
|
|
|
+ WHERE tt.term_id = %d
|
|
|
+ AND tt.taxonomy = 'product_cat'
|
|
|
+ AND p.post_type = 'product'
|
|
|
+ AND p.post_status IN ('publish', 'private', 'draft')
|
|
|
+ ";
|
|
|
+
|
|
|
+ $products = $wpdb->get_col($wpdb->prepare($sql, $category_id));
|
|
|
+
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
+ error_log('STUDIOU WC: Found ' . count($products) . ' products in category ' . $category_id . ' (direct DB query)');
|
|
|
+ if (!empty($products)) {
|
|
|
+ error_log('STUDIOU WC: Product IDs: ' . implode(', ', array_slice($products, 0, 10)) . (count($products) > 10 ? ' (showing first 10)' : ''));
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $products = get_posts($args);
|
|
|
- return count($products);
|
|
|
+ return $products ? array_map('intval', $products) : array();
|
|
|
}
|
|
|
|
|
|
/**
|