|
@@ -34,13 +34,15 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
// Register AJAX handlers
|
|
// Register AJAX handlers
|
|
|
add_action('wp_ajax_studiou_wcpcm_move_products', array($this, 'handle_move_products_ajax'));
|
|
add_action('wp_ajax_studiou_wcpcm_move_products', array($this, 'handle_move_products_ajax'));
|
|
|
add_action('wp_ajax_studiou_wcpcm_batch_description', array($this, 'handle_batch_description_ajax'));
|
|
add_action('wp_ajax_studiou_wcpcm_batch_description', array($this, 'handle_batch_description_ajax'));
|
|
|
-
|
|
|
|
|
|
|
+ add_action('wp_ajax_studiou_wcpcm_delete_products', array($this, 'handle_delete_products_ajax'));
|
|
|
|
|
+ add_action('wp_ajax_studiou_wcpcm_delete_products_batch', array($this, 'handle_delete_products_batch_ajax'));
|
|
|
|
|
+
|
|
|
// Add a test AJAX handler to verify AJAX is working
|
|
// Add a test AJAX handler to verify AJAX is working
|
|
|
add_action('wp_ajax_studiou_wcpcm_test', array($this, 'handle_test_ajax'));
|
|
add_action('wp_ajax_studiou_wcpcm_test', array($this, 'handle_test_ajax'));
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
// Debug: Log that the handler is being registered
|
|
// Debug: Log that the handler is being registered
|
|
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
- error_log('STUDIOU WC: AJAX handlers registered - move_products and batch_description');
|
|
|
|
|
|
|
+ error_log('STUDIOU WC: AJAX handlers registered - move_products, batch_description, and delete_products');
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -527,14 +529,14 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
'orderby' => 'name',
|
|
'orderby' => 'name',
|
|
|
'hide_empty' => false,
|
|
'hide_empty' => false,
|
|
|
);
|
|
);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$categories = get_terms($args);
|
|
$categories = get_terms($args);
|
|
|
$categories_with_counts = array();
|
|
$categories_with_counts = array();
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
if (!is_wp_error($categories)) {
|
|
if (!is_wp_error($categories)) {
|
|
|
foreach ($categories as $category) {
|
|
foreach ($categories as $category) {
|
|
|
$product_count = $this->get_category_product_count($category->term_id);
|
|
$product_count = $this->get_category_product_count($category->term_id);
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
$categories_with_counts[] = array(
|
|
$categories_with_counts[] = array(
|
|
|
'id' => $category->term_id,
|
|
'id' => $category->term_id,
|
|
|
'name' => $category->name,
|
|
'name' => $category->name,
|
|
@@ -543,7 +545,313 @@ class Studiou_WC_Product_Cat_Manage_Manipulator {
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
return $categories_with_counts;
|
|
return $categories_with_counts;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handle AJAX delete products request (initial request to get product IDs)
|
|
|
|
|
+ */
|
|
|
|
|
+ public function handle_delete_products_ajax() {
|
|
|
|
|
+ // Clean all output buffers and prevent any output
|
|
|
|
|
+ while (ob_get_level()) {
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Start a new output buffer to catch any unwanted output
|
|
|
|
|
+ ob_start();
|
|
|
|
|
+
|
|
|
|
|
+ // Suppress PHP errors/notices during AJAX to prevent JSON corruption
|
|
|
|
|
+ $original_error_reporting = error_reporting();
|
|
|
|
|
+ error_reporting(0);
|
|
|
|
|
+
|
|
|
|
|
+ // Enable error logging only
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Delete products 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['delete_categories'])) {
|
|
|
|
|
+ wp_send_json_error(array(
|
|
|
|
|
+ 'message' => __('Missing required parameters', 'studiou-wc-product-cat-manage')
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $category_ids = array_map('intval', $_POST['delete_categories']);
|
|
|
|
|
+
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Delete products operation started - Categories: ' . implode(', ', $category_ids));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Validate categories
|
|
|
|
|
+ if (empty($category_ids)) {
|
|
|
|
|
+ wp_send_json_error(array(
|
|
|
|
|
+ 'message' => __('Please select at least one category', 'studiou-wc-product-cat-manage')
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Get all products from selected categories
|
|
|
|
|
+ $product_ids = $this->get_products_from_categories($category_ids);
|
|
|
|
|
+
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Found ' . count($product_ids) . ' products to delete');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Clean any output that might have been generated
|
|
|
|
|
+ ob_clean();
|
|
|
|
|
+
|
|
|
|
|
+ // Return product IDs for batch processing
|
|
|
|
|
+ wp_send_json_success(array(
|
|
|
|
|
+ 'product_ids' => $product_ids,
|
|
|
|
|
+ 'total_count' => count($product_ids),
|
|
|
|
|
+ 'message' => sprintf(
|
|
|
|
|
+ __('Found %d products to delete', 'studiou-wc-product-cat-manage'),
|
|
|
|
|
+ count($product_ids)
|
|
|
|
|
+ )
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Delete products 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 delete 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();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Handle AJAX delete products batch request (processes products in batches)
|
|
|
|
|
+ */
|
|
|
|
|
+ public function handle_delete_products_batch_ajax() {
|
|
|
|
|
+ // Clean all output buffers and prevent any output
|
|
|
|
|
+ while (ob_get_level()) {
|
|
|
|
|
+ ob_end_clean();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Start a new output buffer to catch any unwanted output
|
|
|
|
|
+ ob_start();
|
|
|
|
|
+
|
|
|
|
|
+ // Suppress PHP errors/notices during AJAX to prevent JSON corruption
|
|
|
|
|
+ $original_error_reporting = error_reporting();
|
|
|
|
|
+ error_reporting(0);
|
|
|
|
|
+
|
|
|
|
|
+ // Enable error logging only
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Delete products batch 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['product_ids'])) {
|
|
|
|
|
+ wp_send_json_error(array(
|
|
|
|
|
+ 'message' => __('Missing required parameters', 'studiou-wc-product-cat-manage')
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $product_ids = array_map('intval', $_POST['product_ids']);
|
|
|
|
|
+
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Processing batch of ' . count($product_ids) . ' products for deletion');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Delete products in this batch
|
|
|
|
|
+ $result = $this->delete_products_batch($product_ids);
|
|
|
|
|
+
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Batch deletion completed - Deleted: ' . $result['deleted_count'] . ', Failed: ' . $result['failed_count']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Clean any output that might have been generated
|
|
|
|
|
+ ob_clean();
|
|
|
|
|
+
|
|
|
|
|
+ // Return success response
|
|
|
|
|
+ wp_send_json_success(array(
|
|
|
|
|
+ 'deleted_count' => $result['deleted_count'],
|
|
|
|
|
+ 'failed_count' => $result['failed_count'],
|
|
|
|
|
+ 'failed_products' => $result['failed_products']
|
|
|
|
|
+ ));
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ // Debug logging
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Delete products batch 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 delete batch 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();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Get all products from multiple categories
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param array $category_ids Array of category IDs
|
|
|
|
|
+ * @return array Array of unique product IDs (including parent products with variants)
|
|
|
|
|
+ */
|
|
|
|
|
+ private function get_products_from_categories($category_ids) {
|
|
|
|
|
+ global $wpdb;
|
|
|
|
|
+
|
|
|
|
|
+ if (empty($category_ids)) {
|
|
|
|
|
+ return array();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $placeholders = implode(',', array_fill(0, count($category_ids), '%d'));
|
|
|
|
|
+
|
|
|
|
|
+ // Get all products from selected categories (both simple and parent 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 IN ($placeholders)
|
|
|
|
|
+ AND tt.taxonomy = 'product_cat'
|
|
|
|
|
+ AND p.post_type = 'product'
|
|
|
|
|
+ AND p.post_status IN ('publish', 'private', 'draft', 'pending', 'trash')
|
|
|
|
|
+ ";
|
|
|
|
|
+
|
|
|
|
|
+ $products = $wpdb->get_col($wpdb->prepare($sql, $category_ids));
|
|
|
|
|
+
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Found ' . count($products) . ' products in categories ' . implode(', ', $category_ids));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return $products ? array_map('intval', $products) : array();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Delete a batch of products and their variants
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param array $product_ids Array of product IDs to delete
|
|
|
|
|
+ * @return array Result with counts
|
|
|
|
|
+ */
|
|
|
|
|
+ private function delete_products_batch($product_ids) {
|
|
|
|
|
+ $deleted_count = 0;
|
|
|
|
|
+ $failed_count = 0;
|
|
|
|
|
+ $failed_products = array();
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($product_ids as $product_id) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Get the product object
|
|
|
|
|
+ $product = wc_get_product($product_id);
|
|
|
|
|
+
|
|
|
|
|
+ if (!$product) {
|
|
|
|
|
+ $failed_count++;
|
|
|
|
|
+ $failed_products[] = $product_id;
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Product ' . $product_id . ' not found');
|
|
|
|
|
+ }
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If it's a variable product, delete all variations first
|
|
|
|
|
+ if ($product->is_type('variable')) {
|
|
|
|
|
+ $variations = $product->get_children();
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Deleting ' . count($variations) . ' variations for product ' . $product_id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ foreach ($variations as $variation_id) {
|
|
|
|
|
+ $variation = wc_get_product($variation_id);
|
|
|
|
|
+ if ($variation) {
|
|
|
|
|
+ $variation->delete(true); // true = force delete permanently
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Delete the product permanently
|
|
|
|
|
+ $result = $product->delete(true); // true = force delete permanently
|
|
|
|
|
+
|
|
|
|
|
+ if ($result) {
|
|
|
|
|
+ $deleted_count++;
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Successfully deleted product ' . $product_id);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $failed_count++;
|
|
|
|
|
+ $failed_products[] = $product_id;
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Failed to delete product ' . $product_id);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } catch (Exception $e) {
|
|
|
|
|
+ $failed_count++;
|
|
|
|
|
+ $failed_products[] = $product_id;
|
|
|
|
|
+ if (defined('WP_DEBUG') && WP_DEBUG) {
|
|
|
|
|
+ error_log('STUDIOU WC: Exception deleting product ' . $product_id . ': ' . $e->getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return array(
|
|
|
|
|
+ 'deleted_count' => $deleted_count,
|
|
|
|
|
+ 'failed_count' => $failed_count,
|
|
|
|
|
+ 'failed_products' => $failed_products
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|