db = $db; // Register AJAX handlers add_action('wp_ajax_studiou_wcpcm_move_products', array($this, 'handle_move_products_ajax')); } /** * 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') )); } // 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']); // 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') )); } try { // Execute move operation $result = $this->move_products_between_categories($source_category_id, $target_category_id); // 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'] )); } catch (Exception $e) { wp_send_json_error(array( 'message' => sprintf( __('Error during move operation: %s', 'studiou-wc-product-cat-manage'), $e->getMessage() ) )); } } /** * Move all products from source category to target category * * @param int $source_category_id Source category ID * @param int $target_category_id Target category ID * @return array Result with counts and message * @throws Exception On error */ public function move_products_between_categories($source_category_id, $target_category_id) { // Get source and target category terms $source_category = get_term($source_category_id, 'product_cat'); $target_category = get_term($target_category_id, 'product_cat'); if (is_wp_error($source_category) || is_wp_error($target_category)) { 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, ) ) ); $products = get_posts($product_args); $moved_count = 0; // Move each product foreach ($products as $product_id) { // Get current categories for the product $current_categories = wp_get_post_terms($product_id, 'product_cat', array('fields' => 'ids')); if (is_wp_error($current_categories)) { continue; } // Remove source category and add target category $new_categories = array_diff($current_categories, array($source_category_id)); $new_categories[] = $target_category_id; // Update product categories $result = wp_set_post_terms($product_id, $new_categories, 'product_cat'); if (!is_wp_error($result)) { $moved_count++; } } // Get updated counts $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 ); return array( 'moved_count' => $moved_count, 'source_count' => $source_count, 'target_count' => $target_count, 'message' => $message ); } /** * Get product count for a category * * @param int $category_id Category ID * @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, ) ) ); $products = get_posts($args); return count($products); } /** * Get all categories with product counts for select lists * * @return array Array of categories with ID, name, and product count */ public function get_categories_with_counts() { $args = array( 'taxonomy' => 'product_cat', 'orderby' => 'name', 'hide_empty' => false, ); $categories = get_terms($args); $categories_with_counts = array(); if (!is_wp_error($categories)) { foreach ($categories as $category) { $product_count = $this->get_category_product_count($category->term_id); $categories_with_counts[] = array( 'id' => $category->term_id, 'name' => $category->name, 'count' => $product_count, 'display_name' => sprintf('%s (%d products)', $category->name, $product_count) ); } } return $categories_with_counts; } }