skip to Main Content

I have over 400 products in my WooComerce store, and they all were done as a simple product. The problem is that now I have to add variations to all the products (to satify a shipping plugin) and it will take me forever if I have to do this manually for each product.

I have setup one of my product with all the variations and values needed to be duplicated to the other products of the same category.

I tried piecing together a simple plugin to do this based on TSCAmerica.com answer.

Below is the complete plugin code for anyone to try out and see if it is working for them or where it needs to be fixed:

<?php

/*
Plugin Name:  WC Copy Variations
Plugin URI:   https://www.example.com
Description:  Copy a Woocommerce Product's Variations From One Product to Another
Version:      1.0
Author:       Wayne Schulz
Author URI:   https://www.example.com
License:      GPL2
License URI:  https://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  wc-copy-variations
Domain Path:  /languages
*/

// plugin settings menu
add_action('admin_menu', 'wcvc_create_menu');

function wcvc_create_menu() {

    //create new top-level menu
    add_menu_page('WC Copy Variations Settings', 'Copy Variations', 'administrator', __FILE__, 'wcvc_settings_page' , plugins_url('/images/icon.png', __FILE__) );

    //call register settings function
    add_action( 'admin_init', 'register_wcvc_settings' );
}


function register_wcvc_settings() {
    //register our settings
    register_setting( 'wcvc-settings-group', 'source_product_id' );
    register_setting( 'wcvc-settings-group', 'target_product_id' );
        register_setting( 'wcvc-settings-group', 'wcvc_status' );
    
}

function wcvc_settings_page() {

// Trigger wcv copy
$wcvc_status = get_option('wcvc_status');
    if(str_contains($wcvc_status, 'yes')) {
        perform_wcv_copy();
    }

?>
<div class="wrap">
<h1>WC Copy Variations</h1>

<form method="post" action="options.php">
    <?php settings_fields( 'wcvc-settings-group' ); ?>
    <?php do_settings_sections( 'wcvc-settings-group' ); ?>
    <table class="form-table">
        <tr valign="top">
        <th scope="row">Source Product ID</th>
        <td><input type="text" name="source_product_id" value="<?php echo esc_attr( get_option('source_product_id') ); ?>" /></td>
        </tr>
         
        <tr valign="top">
        <th scope="row">Target Product ID</th>
        <td><input type="text" name="target_product_id" value="<?php echo esc_attr( get_option('target_product_id') ); ?>" /></td>
        </tr>
        
        <tr valign="top">
        <th scope="row">Type 'yes' to copy</th>
        <td><input type="text" name="wcvc_status" value="<?php echo esc_attr( get_option('wcvc_status') ); ?>" /></td>
        </tr>
    </table>
    <?php submit_button(); ?>
</form>

</div>
<table><tr><td style="vertical-align: top;"><?php show_wcv_source(); ?></td><td style="vertical-align: top;"><?php show_wcv_target(); ?></td></tr></table>

<?php }

function perform_wcv_copy() {
    global $options;
    $source_product_id = get_option('source_product_id');
    $target_product_id = get_option('target_product_id');

    $source_product = wc_get_product($source_product_id);

    // Check if the source product has variations
    if ($source_product->is_type('variable')) {
        // Get the variations of the source product
        $variations = $source_product->get_children();

        foreach ($variations as $variation_id) {
            $variation = wc_get_product($variation_id);

            // Create a new variation for the target product
            $new_variation = new WC_Product_Variation();
            $new_variation->set_parent_id($target_product_id);
            
            // Set attributes and other settings from the source variation
            $new_variation->set_attributes($variation->get_attributes());
            $new_variation->set_regular_price($variation->get_regular_price());
            $new_variation->set_sale_price($variation->get_sale_price());
            $new_variation->set_weight($variation->get_weight());
            $new_variation->set_length($variation->get_length());
            $new_variation->set_height($variation->get_height());
            $new_variation->set_width($variation->get_width());
            
            // Save the new variation
            $new_variation->save();
        }
    }
    update_option( 'wcvc_status', 'done' );
}

function show_wcv_source() {

    global $options;
    $source_product_id = get_option('source_product_id');
    $target_product_id = get_option('target_product_id');
    echo '<p><strong>Source Product ID: '.$source_product_id.'</strong><br />';
    echo 'Product Categories: '.wc_get_product_category_list($source_product_id).'</p>';
    $source_product = wc_get_product($source_product_id);

    // Check if the source product has variations
    if ($source_product->is_type('variable')) {
        // Get the variations of the source product
        $s_variations = $source_product->get_children();
        
        foreach ($s_variations as $s_variation_id) {
            $s_variation = wc_get_product($s_variation_id);
            
            echo '<div class="wrap"><p>';
            
            //$raw_variation = var_export($variation, true);
            //echo 'Variation ID: '.$raw_variation.'<br />';

            echo 'Attributes: ';
            var_dump($s_variation->get_attributes());
            echo '<br />';
            
            $s_regular_price = $s_variation->get_regular_price();
            echo 'Regular Price: '.$s_regular_price.'<br />';

            $s_sale_price = $s_variation->get_sale_price();
            echo 'Sale Price: '.$s_sale_price.'<br />';
            
            $s_weight = $s_variation->get_weight();
            echo 'Weight: '.$s_weight.'<br />';
            
            $s_length = $s_variation->get_length();
            echo 'Length: '.$s_length.'<br />';
            
            $s_height = $s_variation->get_height();
            echo 'Height: '.$s_height.'<br />';
            
            $s_width = $s_variation->get_width();
            echo 'Width: '.$s_width.'<br />';
            
            echo '</p></div>';
        }
    }
}

function show_wcv_target() {

    global $options;
    $source_product_id = get_option('source_product_id');
    $target_product_id = get_option('target_product_id');
    echo '<p><strong>Target Product ID: '.$target_product_id.'</strong><br />';
    echo 'Product Categories: '.wc_get_product_category_list($target_product_id).'</p>';
    $target_product = wc_get_product($target_product_id);

    // Check if the target product has variations
    if ($target_product->is_type('variable')) {
        // Get the variations of the target product (if any)
        $t_variations = $target_product->get_children();
        
        foreach ($t_variations as $t_variation_id) {
            $t_variation = wc_get_product($t_variation_id);
            
            echo '<div class="wrap"><p>';
            
            // $raw_variation = var_export($variation, true);
            // echo 'Variation ID: '.$raw_variation.'<br />';

            echo 'Attributes: ';
            var_dump($t_variation->get_attributes());
            echo '<br />';
            
            $t_regular_price = $t_variation->get_regular_price();
            echo 'Regular Price: '.$t_regular_price.'<br />';

            $t_sale_price = $t_variation->get_sale_price();
            echo 'Sale Price: '.$t_sale_price.'<br />';
            
            $t_weight = $t_variation->get_weight();
            echo 'Weight: '.$t_weight.'<br />';
            
            $t_length = $t_variation->get_length();
            echo 'Length: '.$t_length.'<br />';
            
            $t_height = $t_variation->get_height();
            echo 'Height: '.$t_height.'<br />';
            
            $t_width = $t_variation->get_width();
            echo 'Width: '.$t_width.'<br />';
            
            echo '</p></div>';
        }
    }
}

?>

Enter the source ID and the target ID and hit save, then it will dispaly any variations in the source and target products. If you want to perform the copy, enter ‘yes’ in the last field and hit save again.

The issue I am having is that it is not saving the new variations to the target product. I VAR DUMPED every possible variable and the data is there in the right places. After the save command, the ID does increment for each new variation, however, either the save() is not working properly for some reason or WooComerce is deleting the saved variation immediately after the save.

What am I missing or doing wrong?

2

Answers


  1. Chosen as BEST ANSWER

    After Moshe Gross's answer, I added a cleanup routine to the perform_wvc_copy function, removing any existing product variations before the copy.

    The fixed function:

    function perform_wcv_copy() {
        global $options;
        $source_product_id = get_option('source_product_id');
        $target_product_id = get_option('target_product_id');
    
        $source_product = wc_get_product($source_product_id);
        $target_product = wc_get_product($target_product_id);
    
        // Check if source and target products have variations
        if ($source_product->is_type('variable') && $target_product->is_type('variable')) {
    
            // Get the variations of the target product
            $t_variations = $target_product->get_children();
    
            // Delete existing product variations
            foreach ($t_variations as $t_variation_id) {
                $t_variation = wc_get_product($t_variation_id);
                $t_variation->delete( true );
            }
        }        
    
        // Check if the source product has variations
        if ($source_product->is_type('variable')) {
            if (!$target_product->is_type('variable')) {
                /* Update target parent */
                $target_product = wc_get_product($target_product_id);
                $target_product->set_attributes($source_product->get_attributes());
                $target_product->save();
                wp_set_object_terms( $target_product_id, 'variable', 'product_type' );
            }
        
            // Get the variations of the source product
            $variations = $source_product->get_children();
    
            foreach ($variations as $variation_id) {
                $variation = wc_get_product($variation_id);
    
                // Create a new variation for the target product
                $new_variation = new WC_Product_Variation();
                $new_variation->set_parent_id($target_product_id);
                
                // Set attributes and other settings from the source variation
                $new_variation->set_attributes($variation->get_attributes());
                $new_variation->set_regular_price($variation->get_regular_price());
                $new_variation->set_sale_price($variation->get_sale_price());
                $new_variation->set_weight($variation->get_weight());
                $new_variation->set_length($variation->get_length());
                $new_variation->set_height($variation->get_height());
                $new_variation->set_width($variation->get_width());
                
                // Save the new variation
                $new_variation->save();
            }
        }
        update_option( 'wcvc_status', 'done' );
    }
    

    If there's anything else, please provide a comment or answer.


  2. There’s two things missing from the code above

    You’re not adding the attribute to the parent product, and the product is still set as a simple (not variable) product

    you can add a few lines to fix this

    function perform_wcv_copy() {
        global $options;
        $source_product_id = get_option('source_product_id');
        $target_product_id = get_option('target_product_id');
    
        $source_product = wc_get_product($source_product_id);
    
        // Check if the source product has variations
        if ($source_product->is_type('variable')) {
            /* Update target parent */
            $target_product = wc_get_product($target_product_id);
            $target_product->set_attributes($source_product->get_attributes());
            $target_product->save();
            wp_set_object_terms( $target_product_id, 'variable', 'product_type' );
            
            // Get the variations of the source product
            $variations = $source_product->get_children();
    
            foreach ($variations as $variation_id) {
                $variation = wc_get_product($variation_id);
    
                // Create a new variation for the target product
                $new_variation = new WC_Product_Variation();
                $new_variation->set_parent_id($target_product_id);
                
                // Set attributes and other settings from the source variation
                $new_variation->set_attributes($variation->get_attributes());
                $new_variation->set_regular_price($variation->get_regular_price());
                $new_variation->set_sale_price($variation->get_sale_price());
                $new_variation->set_weight($variation->get_weight());
                $new_variation->set_length($variation->get_length());
                $new_variation->set_height($variation->get_height());
                $new_variation->set_width($variation->get_width());
                
                // Save the new variation
                $new_variation->save();
            }
        }
        update_option( 'wcvc_status', 'done' );
    }
    

    P.s. if you run this for the same id multiple times (and you might have done already even if the variations didn’t show) you’ll have multiple of the same variations

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search