[Special Summer Sale] 40% OFF All Magento 2 Themes

Cart

Create programmatically a variable product and two new attributes in WooCommerce

  • This topic is empty.
Viewing 4 posts - 1 through 4 (of 4 total)
  • Author
    Posts
  • #10011
    cedric
    Participant

    I would like to programmatically create a variable product ("parent" product) with two new variante attributes – all that from a WordPress plugin (so no HTTP Request to an API).

    These two variante attributes should also be created on the fly.

    How can this be done ?

    (with WooCommerce version 3)


    Update : I have written more lines of code on this that I wished, and tried many things to solve it, using wooCommerce objects, and added missing data about terms, termmeta, the relationship from term with post, in the database using the WordPress database object – but nothing has sufficed to make it work. And I couldn’t pin-point where I went wrong – that is why I couldn’t provide a narrower problem – things for which stackoverflow is more made for.

    #10014
    loictheaztec
    Participant

    After: Create programmatically a WooCommerce product variation with new attribute values

    Here you get the way to create a new variable product with new product attributes + values:

    /**
     * Save a new product attribute from his name (slug).
     *
     * @since 3.0.0
     * @param string $name  | The product attribute name (slug).
     * @param string $label | The product attribute label (name).
     */
    function save_product_attribute_from_name( $name, $label='', $set=true ){
        if( ! function_exists ('get_attribute_id_from_name') ) return;
    
        global $wpdb;
    
        $label = $label == '' ? ucfirst($name) : $label;
        $attribute_id = get_attribute_id_from_name( $name );
    
        if( empty($attribute_id) ){
            $attribute_id = NULL;
        } else {
            $set = false;
        }
        $args = array(
            'attribute_id'      => $attribute_id,
            'attribute_name'    => $name,
            'attribute_label'   => $label,
            'attribute_type'    => 'select',
            'attribute_orderby' => 'menu_order',
            'attribute_public'  => 0,
        );
    
    
        if( empty($attribute_id) ) {
            $wpdb->insert(  "{$wpdb->prefix}woocommerce_attribute_taxonomies", $args );
            set_transient( 'wc_attribute_taxonomies', false );
        }
    
        if( $set ){
            $attributes = wc_get_attribute_taxonomies();
            $args['attribute_id'] = get_attribute_id_from_name( $name );
            $attributes[] = (object) $args;
            //print_r($attributes);
            set_transient( 'wc_attribute_taxonomies', $attributes );
        } else {
            return;
        }
    }
    
    /**
     * Get the product attribute ID from the name.
     *
     * @since 3.0.0
     * @param string $name | The name (slug).
     */
    function get_attribute_id_from_name( $name ){
        global $wpdb;
        $attribute_id = $wpdb->get_col("SELECT attribute_id
        FROM {$wpdb->prefix}woocommerce_attribute_taxonomies
        WHERE attribute_name LIKE '$name'");
        return reset($attribute_id);
    }
    
    /**
     * Create a new variable product (with new attributes if they are).
     * (Needed functions:
     *
     * @since 3.0.0
     * @param array $data | The data to insert in the product.
     */
    
    function create_product_variation( $data ){
        if( ! function_exists ('save_product_attribute_from_name') ) return;
    
        $postname = sanitize_title( $data['title'] );
        $author = empty( $data['author'] ) ? '1' : $data['author'];
    
        $post_data = array(
            'post_author'   => $author,
            'post_name'     => $postname,
            'post_title'    => $data['title'],
            'post_content'  => $data['content'],
            'post_excerpt'  => $data['excerpt'],
            'post_status'   => 'publish',
            'ping_status'   => 'closed',
            'post_type'     => 'product',
            'guid'          => home_url( '/product/'.$postname.'/' ),
        );
    
        // Creating the product (post data)
        $product_id = wp_insert_post( $post_data );
    
        // Get an instance of the WC_Product_Variable object and save it
        $product = new WC_Product_Variable( $product_id );
        $product->save();
    
        ## ---------------------- Other optional data  ---------------------- ##
        ##     (see WC_Product and WC_Product_Variable setters methods)
    
        // THE PRICES (No prices yet as we need to create product variations)
    
        // IMAGES GALLERY
        if( ! empty( $data['gallery_ids'] ) && count( $data['gallery_ids'] ) > 0 )
            $product->set_gallery_image_ids( $data['gallery_ids'] );
    
        // SKU
        if( ! empty( $data['sku'] ) )
            $product->set_sku( $data['sku'] );
    
        // STOCK (stock will be managed in variations)
        $product->set_stock_quantity( $data['stock'] ); // Set a minimal stock quantity
        $product->set_manage_stock(true);
        $product->set_stock_status('');
    
        // Tax class
        if( empty( $data['tax_class'] ) )
            $product->set_tax_class( $data['tax_class'] );
    
        // WEIGHT
        if( ! empty($data['weight']) )
            $product->set_weight(''); // weight (reseting)
        else
            $product->set_weight($data['weight']);
    
        $product->validate_props(); // Check validation
    
        ## ---------------------- VARIATION ATTRIBUTES ---------------------- ##
    
        $product_attributes = array();
    
        foreach( $data['attributes'] as $key => $terms ){
            $taxonomy = wc_attribute_taxonomy_name($key); // The taxonomy slug
            $attr_label = ucfirst($key); // attribute label name
            $attr_name = ( wc_sanitize_taxonomy_name($key)); // attribute slug
    
            // NEW Attributes: Register and save them
            if( ! taxonomy_exists( $taxonomy ) )
                save_product_attribute_from_name( $attr_name, $attr_label );
    
            $product_attributes[$taxonomy] = array (
                'name'         => $taxonomy,
                'value'        => '',
                'position'     => '',
                'is_visible'   => 0,
                'is_variation' => 1,
                'is_taxonomy'  => 1
            );
    
            foreach( $terms as $value ){
                $term_name = ucfirst($value);
                $term_slug = sanitize_title($value);
    
                // Check if the Term name exist and if not we create it.
                if( ! term_exists( $value, $taxonomy ) )
                    wp_insert_term( $term_name, $taxonomy, array('slug' => $term_slug ) ); // Create the term
    
                // Set attribute values
                wp_set_post_terms( $product_id, $term_name, $taxonomy, true );
            }
        }
        update_post_meta( $product_id, '_product_attributes', $product_attributes );
        $product->save(); // Save the data
    }
    

    Code goes in function.php file of your active child theme (or active theme). Tested and works.


    USAGE (example with 2 new attributes + values):

    create_product_variation( array(
        'author'        => '', // optional
        'title'         => 'Woo special one',
        'content'       => '<p>This is the product content <br>A very nice product, soft and clear…<p>',
        'excerpt'       => 'The product short description…',
        'regular_price' => '16', // product regular price
        'sale_price'    => '', // product sale price (optional)
        'stock'         => '10', // Set a minimal stock quantity
        'image_id'      => '', // optional
        'gallery_ids'   => array(), // optional
        'sku'           => '', // optional
        'tax_class'     => '', // optional
        'weight'        => '', // optional
        // For NEW attributes/values use NAMES (not slugs)
        'attributes'    => array(
            'Attribute 1'   =>  array( 'Value 1', 'Value 2' ),
            'Attribute 2'   =>  array( 'Value 1', 'Value 2', 'Value 3' ),
        ),
    ) );
    

    Tested and works.


    Related:

    #10013
    sarakinos
    Participant

    You can also achieve this using the new native functions for setting/getting data from postmeta.

    Here is an example that works ( based on the default dummy products of Woocommerce 3)

    //Create main product
    $product = new WC_Product_Variable();
    
    //Create the attribute object
    $attribute = new WC_Product_Attribute();
    //pa_size tax id
    $attribute->set_id( 1 );
    //pa_size slug
    $attribute->set_name( 'pa_size' );
    
    //Set terms slugs
    $attribute->set_options( array(
            'blue',
            'grey'
    ) );
    $attribute->set_position( 0 );
    
    //If enabled
    $attribute->set_visible( 1 );
    
    //If we are going to use attribute in order to generate variations
    $attribute->set_variation( 1 );
    
    $product->set_attributes(array($attribute));
    
    //Save main product to get its id
    $id = $product->save();
    
    
    $variation = new WC_Product_Variation();
    $variation->set_regular_price(5);
    $variation->set_parent_id($id);
    
    //Set attributes requires a key/value containing
    // tax and term slug
    $variation->set_attributes(array(
            'pa_size' => 'blue'
    ));
    
    //Save variation, returns variation id
    $variation->save();
    

    You can add things like weight, tax, sku etc using the native functions available from Woocommerce 3 and on like set_price, set_sku ect.

    Wrap it within a function and you are good to go.

    #10012
    dee_ell
    Participant

    Sarakinos answer only worked with two small but important modifications.

    1. The $attribute->set_id() needs to be set to 0.
    2. The $attribute->set_name(); and $variation->set_attributes() do not need the pa_ prefix. The methods already handle the prefixes.

    So a working code would be:

    //Create main product
    $product = new WC_Product_Variable();
    
    //Create the attribute object
    $attribute = new WC_Product_Attribute();
    
    //pa_size tax id
    $attribute->set_id( 0 ); // -> SET to 0
    
    //pa_size slug
    $attribute->set_name( 'size' ); // -> removed 'pa_' prefix
    
    //Set terms slugs
    $attribute->set_options( array(
        'blue',
        'grey'
    ) );
    
    $attribute->set_position( 0 );
    
    //If enabled
    $attribute->set_visible( 1 );
    
    //If we are going to use attribute in order to generate variations
    $attribute->set_variation( 1 );
    
    $product->set_attributes(array($attribute));
    
    //Save main product to get its id
    $id = $product->save();
    
    $variation = new WC_Product_Variation();
    $variation->set_regular_price(10);
    $variation->set_parent_id($id);
    
    //Set attributes requires a key/value containing
    // tax and term slug
    $variation->set_attributes(array(
        'size' => 'blue' // -> removed 'pa_' prefix
    ));
    
    //Save variation, returns variation id
    echo get_permalink ( $variation->save() );
    
    
    // echo get_permalink( $id ); // -> returns a link to check the newly created product
    

    Keep in mind, the product will be bare bones, and will be named ‘product’. You need to set those values in the $product before you save it with $id = $product->save();.

Viewing 4 posts - 1 through 4 (of 4 total)
  • You must be logged in to reply to this topic.