In WooCommerce, I have 100 variable products with a variation using custom attribute for variation "Volume" with "50ml" as value. I want to change/update the value from "50ml" to "60ml".
Here is the code that I have so far:
add_action('woocommerce_before_variations_form', 'p4wp_default_variation_value');
function p4wp_default_variation_value() {
global $product;
// Check if the product is a variable product
if ($product->is_type('variable')) {
$product_attributes = $product->get_attributes();
$attribute_value_to_find = '60ml';
// Get the variations with the specified attribute value
$variations = wc_get_products(array(
'type' => 'variation',
'status' => 'publish',
'limit' => -1,
'parent' => $product->get_id(),
'meta_query' => array(
array(
'key' => 'attribute_volume',
'value' => $attribute_value_to_find,
'compare' => '=',
),
),
));
// Loop through the variations and get their IDs
$variation_ids = array();
foreach ($variations as $variation) {
$variation_ids[] = $variation->get_id();
}
echo '<pre>';
print_r($variation_ids);
echo '</pre>';
// Check if there are attributes
if (count($product_attributes)) {
$product_attributes = get_post_meta($product->get_id(), '_product_attributes', true);
// Check if the 'volume' attribute exists
if (isset($product_attributes['volume'])) {
// Update the 'value' for '50ml' to '60ml'
$product_attributes['volume']['value'] = str_replace('60ml', '50ml', $product_attributes['volume']['value']);
// Update the '_product_attributes' meta field
update_post_meta($product->get_id(), '_product_attributes', $product_attributes);
//update_post_meta($variation_ids[0], 'attribute_volume', '60ml');
}
}
}
//Update post meta for post ID 3631
update_post_meta($variation_ids[0], 'attribute_volume', '50ml');
}
But the code is not working at all. What I am doing wrong? How to change/update the attribute value from "50ml" to "60ml" keeping all product variations functional?
Any help is appreciated.
First, always make a database backup (mandatory).
The following untested code should update, for all your product variations, "volume" variation attribute value from "50ml" to "60ml" keeping all product variations functional.
The code is lightweight as it makes one or two direct SQL update queries to the database on all matching products without involving PHP in heavy processes with multiple read/update database queries.
The code is only active for administrator user roles (see Usage at the end).
The code work for global product attributes and custom product attributes. Note that global product attributes taxonomy always start with "pa_" (+ the attribute slug).
add_action('init', 'update_variation_attribute_volume_value');
function update_variation_attribute_volume_value() {
global $wpdb, $current_user;
// Restricted to administrator user role
if ( ! in_array('administrator', $current_user->roles) ) return;
$attribute = 'volume'; // Here define the attribute taxonomy (start with "pa_") or the custom attribute (slug)
$name_from = '50ml'; // Here define the existing attribute term name or custom attribute name value
$slug_from = '50ml'; // Here define the existing attribute term slug or custom attribute name value
$name_to = '60ml'; // Here define the replacement attribute term name or custom attribute name value
$slug_to = '60ml'; // Here define the replacement attribute term slug or custom attribute name value
// Lightweight bulk update all product variations related variation attribute, and sync variable product title
$query = $wpdb->query( "
UPDATE {$wpdb->prefix}postmeta pm
INNER JOIN {$wpdb->prefix}posts p ON pm.post_id = p.ID
SET pm.meta_value = '{$slug_to}',
p.post_title = REPLACE(p.post_title, '{$name_from}', '{$name_to}'),
p.post_excerpt = REPLACE(p.post_excerpt, '{$name_from}', '{$name_to}')
WHERE pm.meta_key = 'attribute_{$attribute}'
AND pm.meta_value = '{$slug_from}'
AND p.post_type = 'product_variation'
" );
error_log( "Query (product variation)): \n" . print_r($query, true) ); // DEBUG
// For global attribute (taxonomy): Update the product attribute term
if ( taxonomy_exists($attribute) && term_exists($slug_from, $attribute) ) {
$term = get_term_by('slug',$slug_from, $attribute );
$update = wp_update_term( $term->term_id, $attribute, array('name' => $slug_to, 'slug' => $slug_to) ); // Update term
error_log( "Taxonomy term update: \n" . print_r($update, true) ); // DEBUG
}
// For custom attribute: Lightweight bulk update the variable product attribute
else {
$query2 = $wpdb->query( "
UPDATE {$wpdb->prefix}postmeta pm
INNER JOIN {$wpdb->prefix}posts p ON pm.post_id = p.ID
SET pm.meta_value = REPLACE(pm.meta_value, '{$slug_from}', '{$slug_to}')
WHERE pm.meta_key = '_product_attributes'
AND pm.meta_value LIKE '%{$slug_from}%'
AND p.post_type = 'product'
" );
error_log( "Query two (variable product)): \n" . print_r($query2, true) ); // DEBUG
}
}
Code goes in functions.php file of your child theme (or in a plugin). It should work.
USAGE: Browse any page on your website (front or backend), then remove the code.