Recently, I needed to update all of the products in a WooCommerce store. The dimensions were included in every product name but I needed them to be set as the product dimensions. If there were only a dozen or so products, manually editing them would be an option but this store has around 7 thousand. Manually doing this would be error prone and take a lot of time. So I wrote a quick script to automatically add the dimensions. Here’s how that works.
The first step is to get a list of the products. To limit potential complications, I decided to do this one category at a time. That way I could roll out the changes incrementally. WooCommerce gives us the wc_get_products()
method that we can use to load a list of products by category. Here’s what that looks like:
function update_dimensions( $cat ) {
$args = array(
'category' => array( $cat ),
'orderby' => 'id',
'limit' => 800,
);
$products = wc_get_products( $args );
The idea here is to pass the slug for the product category into the function (that’s the $cat
argument). The “limit” here sets the maximum number of products that can be returned. By default, 10 are returned so I set this much higher than the category with the most products to make sure none were missed.
Now with a foreach
loop, I can examine the name of each product and update the dimensions if they meet certain criteria. Here’s the code I’m using for that:
foreach ( $products as $product ) {
foreach ( $widths as $width ) {
if ( matches_pattern( $width['pattern'], $product->get_name() ) ) {
$product->set_width( $width['dimension'] );
$product->save();
error_log( 'updated product width ' . $width['dimension'] . ' ' . $product->get_name() );
}
}
foreach ( $heights as $height ) {
if ( matches_pattern( $height['pattern'], $product->get_name() ) ) {
$product->set_height( $height['dimension'] );
$product->save();
error_log( 'updated product height ' . $height['dimension'] . ' ' . $product->get_name() );
}
}
}
Each product is run through two more loops to check the width and height of the title. It has the pattern I’m trying to match as well as the value I want to set. There were lots of them so I’m leaving most of them out but here’s an example so you’ll have an idea.
$widths = array(
'60' => array(
'pattern' => '/ 60"W /i',
'dimension' => 60,
),
);
To determine if there is a match, I have a helper method called matches_pattern()
that I’m using. It takes the $pattern
and the text $string
and compares them through PHP’s preg_match
method. If they match, the number of matches is returned. Otherwise, false
is sent back.
function matches_pattern( $pattern, $string ) {
return preg_match( $pattern, $string );
}
The dimensions are updated in this block. It checks for the match and if it exists, it’ll update the dimension to the new value and save the product. I’ve also included a log statement here to give me a record of what happened in case there are problems.
if ( matches_pattern( $height['pattern'], $product->get_name() ) ) {
$product->set_height( $height['dimension'] );
$product->save();
error_log( 'updated product height ' . $height['dimension'] . ' ' . $product->get_name() );
}
And that’s about it. Nesting foreach loops can be a bit risky since they can consume so many resources. Since we have a limit on the number of products, this runs rather quickly. In my testing, I could update about 300 products in two to three seconds.
While I’m doing this with dimensions, you could update other product properties in the same way. It’s a good option to consider if you need to change a large number of products. Plus since we’re using WooCommerce’s native product methods, this will continue to work even if products are migrated to different database tables in the future.
Also, I ended up setting this up inside a class with the update_dimensions()
method being a public static function. That way I can easily access it from anywhere without having to create an instance of the class. But it’s perfectly fine to use these outside of a class too.
If you have any interesting use cases for this or any questions, let me know in the comments.
Leave a Reply