function agpd_update_variation_products($base_products = null, $child_products_subset = null) { global $wpdb; agpd_log("Starting agpd_update_variation_products", true); if (!function_exists('wc_get_product')) { agpd_log("WooCommerce function wc_get_product not available", true, 'error'); wp_die('WooCommerce not active or wc_get_product function missing.'); } if (is_null($base_products)) { $base_products = $wpdb->get_results(" SELECT post_id AS id, meta_value AS sku FROM {$wpdb->postmeta} WHERE meta_key = '_sku' AND meta_value REGEXP '^[^-]+-[^-]+$' "); } if (empty($base_products)) { agpd_log("No base products found to update variations.", true); return; } $batch_size = 50; $start_time = microtime(true); agpd_log("Starting title update process at " . date('Y-m-d H:i:s'), true); foreach ($base_products as $base) { $base_id = $base->id; $base_sku = $base->sku; $base_title = get_the_title($base_id); $base_product = wc_get_product($base_id); if (!$base_product) { agpd_log("Failed to load base product ID $base_id (SKU: $base_sku)", true, 'error'); continue; } $restrictions = get_restrictions_for_sku($base_sku); $part_numbers = get_manufacturer_part_numbers($base_product); $grouped_restrictions = group_restrictions_by_model($restrictions); if (empty($grouped_restrictions) || empty($part_numbers)) { agpd_log("No fitment data or part numbers for base SKU: $base_sku (ID: $base_id)", true); continue; } if (is_null($child_products_subset)) { $child_products = $wpdb->get_results($wpdb->prepare(" SELECT post_id AS id, meta_value AS sku FROM {$wpdb->postmeta} WHERE meta_key = '_sku' AND meta_value LIKE %s", $base_sku . '-%' )); } else { $child_products = $child_products_subset; } if (empty($child_products)) { agpd_log("No child products found for base SKU: $base_sku", true); continue; } // Generate titles for child products $preview_titles = []; $config = get_option('agpd_config', []); $title_template = get_post_meta($base_id, '_agpd_title_template', true) ?: ($config['default_title_template'] ?? '{year_range} {model} {module_type} {part_number} {programmed_text} {extra}'); $sku_suffix = agpd_get_next_sku_suffix($base_sku); foreach ($grouped_restrictions as $fitment_model => $years) { $year_ranges = merge_contiguous_years($years); foreach ($year_ranges as $range) { $year_range = format_year_range($range[0], $range[1]); foreach ($part_numbers as $part_number) { $temp_sku = "$base_sku-$sku_suffix"; $existing_product_id = wc_get_product_id_by_sku($temp_sku); $existing_title = $existing_product_id ? get_the_title($existing_product_id) : $base_title; $title = custom_build_title( $title_template, $year_range, $fitment_model, $base_title, $part_number, $existing_title ); $preview_titles[$temp_sku] = $title; $sku_suffix++; } } } $child_ids = array_column($child_products, 'id'); $products = wc_get_products(['include' => $child_ids, 'limit' => -1]); $product_map = array_column($products, null, 'id'); $chunks = array_chunk($child_products, $batch_size); $batch_number = 0; foreach ($chunks as $chunk) { $batch_start_time = microtime(true); $batch_number++; agpd_log("Starting batch $batch_number of " . count($chunk) . " child products for base SKU: $base_sku", true); $wpdb->query('START TRANSACTION'); try { foreach ($chunk as $child) { $child_id = $child->id; $child_sku = $child->sku; $new_title = $preview_titles[$child_sku] ?? build_merged_title( get_post_meta($child_id, '_agpd_year_range', true), get_post_meta($child_id, '_agpd_model', true), get_post_meta($child_id, '_agpd_part', true), $base_title, $child_sku ); $new_title = str_replace(' (Variation Updated)', '', $new_title); $child_product = $product_map[$child_id]; if ($child_product) { $child_product->set_name($new_title); $result = $child_product->save(); if ($result) { agpd_log("Updated title for child ID $child_id (SKU: $child_sku) to: $new_title", true); } else { agpd_log("Failed to update title for child ID $child_id (SKU: $child_sku)", true, 'error'); } } else { agpd_log("Could not load child product ID $child_id (SKU: $child_sku)", true, 'error'); } } $wpdb->query('COMMIT'); $batch_duration = microtime(true) - $batch_start_time; agpd_log("Committed batch update for " . count($chunk) . " child products. Duration: $batch_duration seconds", true); } catch (Exception $e) { $wpdb->query('ROLLBACK'); agpd_log("Error updating batch for base SKU: $base_sku - " . $e->getMessage(), true, 'error'); } } $total_duration = microtime(true) - $start_time; agpd_log("Completed title update for base SKU: $base_sku. Total duration: $total_duration seconds", true); } }