Create programmatically a product using CRUD methods in Woocommerce 3
Asked Answered
R

2

11

I'd like to create a new Woocommerce product programmatically with PHP code and I have tried it with the Woocommerce 3 CRUD methods:

//Woocommerce CRUD
$objProduct = new WC_Product_Simple();

$objProduct->set_name('My Product 1'); //Set product name.
$objProduct->set_status('publish'); //Set product status.
//$objProduct->set_featured(FALSE); //Set if the product is featured.                          | bool
$objProduct->set_catalog_visibility('visible'); //Set catalog visibility.                   | string $visibility Options: 'hidden', 'visible', 'search' and 'catalog'.
$objProduct->set_description('My custom long description'); //Set product description.
//$objProduct->set_short_description('My short description'); //Set product short description.
//$objProduct->set_sku('U-123'); //Set SKU

$objProduct->set_price(5.00); //Set the product's active price.
//$objProduct->set_regular_price(5.00); //Set the product's regular price.
//$objProduct->set_sale_price(); //Set the product's sale price.
//$objProduct->set_date_on_sale_from(); //Set date on sale from.                              | string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.
//$objProduct->set_date_on_sale_to();//Set date on sale to.                                   | string|integer|null $date UTC timestamp, or ISO 8601 DateTime. If the DateTime string has no timezone or offset, WordPress site timezone will be assumed. Null if their is no date.

//$objProduct->set_manage_stock(TRUE); //Set if product manage stock.                         | bool
//$objProduct->set_stock_quantity(10); //Set number of items available for sale.
//$objProduct->set_stock_status('instock'); //Set stock status.                               | string $status 'instock', 'outofstock' and 'onbackorder'
//$objProduct->set_backorders('no'); //Set backorders.                                        | string $backorders Options: 'yes', 'no' or 'notify'.
//$objProduct->set_sold_individually(FALSE); //Set if should be sold individually.            | bool

//$objProduct->set_weight(); //Set the product's weight.
//$objProduct->set_length(); //Set the product length.
//$objProduct->set_width(); //Set the product width.
//$objProduct->set_height(); //Set the product height.

//$objProduct->set_upsell_ids($upsell_ids); //Set upsell IDs.                               | array $upsell_ids IDs from the up-sell products.
//$objProduct->set_cross_sell_ids($cross_sell_ids); //Set crosssell IDs.                    | array $cross_sell_ids IDs from the cross-sell products.

$objProduct->set_reviews_allowed(TRUE); //Set if reviews is allowed.                        | bool

//$objProduct->set_purchase_note($purchase_note); //Set purchase note.                      | string $purchase_note Purchase note.


$attribute = new WC_Product_Attribute();
$attribute->set_id(wc_attribute_taxonomy_id_by_name('pa_color')); //if passing the attribute name to get the ID
$attribute->set_name('pa_color'); //attribute name
$attribute->set_options('red'); // attribute value
$attribute->set_position(1); //attribute display order
$attribute->set_visible(1); //attribute visiblity
$attribute->set_variation(0);//to use this attribute as varint or not

$raw_attributes[] = $attribute; //<--- storing the attribute in an array

$attribute = new WC_Product_Attribute();
$attribute->set_id(25);
$attribute->set_name('pa_size');
$attribute->set_options('XL');
$attribute->set_position(2);
$attribute->set_visible(1);
$attribute->set_variation(0);

$raw_attributes[] = $attribute; //<--- storing the attribute in an array

$objProduct->set_attributes($raw_attributes); //Set product attributes.                   | array $raw_attributes Array of WC_Product_Attribute objects.

//$objProduct->set_category_ids($term_ids); //Set the product categories.                   | array $term_ids List of terms IDs.
//$objProduct->set_tag_ids($term_ids); //Set the product tags.                              | array $term_ids List of terms IDs.

//$objProduct->set_image_id(); //Set main image ID.                                         | int|string $image_id Product image id.
//$objProduct->set_gallery_image_ids(); //Set gallery attachment ids.                       | array $image_ids List of image ids.

$new_product_id = $objProduct->save(); //Saving the data to create new product, it will return product ID.

return;
}

But I get this error:

22-Oct-2018 20:25:19 UTC] PHP Fatal error: Uncaught Error: Class 'WC_Product_Simple' not found in /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-content/plugins/ff-dropship-data-scraper/ff-dropship-data-scraper.php:165 Stack trace:
- #0 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-content/plugins/ff-dropship-data-scraper/ff-dropship-data-scraper.php(233): curl_download('https://www.ban...')
- #1 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-settings.php(305): include_once('/home/u1771p590...')
- #2 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-config.php(112): require_once('/home/u1771p590...')
- #3 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-load.php(37): require_once('/home/u1771p590...')
- #4 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-admin/admin.php(31): require_once('/home/u1771p590...')
- #5 /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-admin/index.php(10): require_once('/home/u1771p590...')
- #6 {main}
thrown in /home/u1771p590/domains/famyfuerza.com/public_html/store/wp-content/plugins/ff-dropship-data-scraper/ff-dropship-data-scraper.php on line 165

I have tried to include the simple product class, but that produced another error which said that another class was missing.

Does somebody know how to fix this? Or has another method to create a woocommerce product via code?

Rigatoni answered 22/10, 2018 at 20:36 Comment(0)
G
25

You are not accessing the WC_Product_simple instance object from your custom Dropship Data Scraper plugin.

The guilty can be mostly 2 things:

  1. You have not installed Woocommerce.
  2. The plugin Dropship Data Scraper is outdated and needs changes, to handle woocommerce.

Try to include the global Woocommerce object and to enable Woocommerce support in your plugin.


To create a product programmatically using CRUD methods introduced in Woocommerce 3 here is the correct way to make it work.

If you need to handle product attributes creation or product variations creation, refer to:

All product attributes and their term values need to be created before. Same thing for product categories and product tags.

1) The code functions:

    // Custom function for product creation (For Woocommerce 3+ only)
    function create_product( $args ){

        if( ! function_exists('wc_get_product_object_type') && ! function_exists('wc_prepare_product_attributes') )
            return false;

        // Get an empty instance of the product object (defining it's type)
        $product = wc_get_product_object_type( $args['type'] );
        if( ! $product )
            return false;

        // Product name (Title) and slug
        $product->set_name( $args['name'] ); // Name (title).
        if( isset( $args['slug'] ) )
            $product->set_name( $args['slug'] );

        // Description and short description:
        $product->set_description( $args['description'] );
        $product->set_short_description( $args['short_description'] );

        // Status ('publish', 'pending', 'draft' or 'trash')
        $product->set_status( isset($args['status']) ? $args['status'] : 'publish' );

        // Visibility ('hidden', 'visible', 'search' or 'catalog')
        $product->set_catalog_visibility( isset($args['visibility']) ? $args['visibility'] : 'visible' );

        // Featured (boolean)
        $product->set_featured(  isset($args['featured']) ? $args['featured'] : false );

        // Virtual (boolean)
        $product->set_virtual( isset($args['virtual']) ? $args['virtual'] : false );

        // Prices
        $product->set_regular_price( $args['regular_price'] );
        $product->set_sale_price( isset( $args['sale_price'] ) ? $args['sale_price'] : '' );
        $product->set_price( isset( $args['sale_price'] ) ? $args['sale_price'] :  $args['regular_price'] );
        if( isset( $args['sale_price'] ) ){
            $product->set_date_on_sale_from( isset( $args['sale_from'] ) ? $args['sale_from'] : '' );
            $product->set_date_on_sale_to( isset( $args['sale_to'] ) ? $args['sale_to'] : '' );
        }

        // Downloadable (boolean)
        $product->set_downloadable(  isset($args['downloadable']) ? $args['downloadable'] : false );
        if( isset($args['downloadable']) && $args['downloadable'] ) {
            $product->set_downloads(  isset($args['downloads']) ? $args['downloads'] : array() );
            $product->set_download_limit(  isset($args['download_limit']) ? $args['download_limit'] : '-1' );
            $product->set_download_expiry(  isset($args['download_expiry']) ? $args['download_expiry'] : '-1' );
        }

        // Taxes
        if ( get_option( 'woocommerce_calc_taxes' ) === 'yes' ) {
            $product->set_tax_status(  isset($args['tax_status']) ? $args['tax_status'] : 'taxable' );
            $product->set_tax_class(  isset($args['tax_class']) ? $args['tax_class'] : '' );
        }

        // SKU and Stock (Not a virtual product)
        if( isset($args['virtual']) && ! $args['virtual'] ) {
            $product->set_sku( isset( $args['sku'] ) ? $args['sku'] : '' );
            $product->set_manage_stock( isset( $args['manage_stock'] ) ? $args['manage_stock'] : false );
            $product->set_stock_status( isset( $args['stock_status'] ) ? $args['stock_status'] : 'instock' );
            if( isset( $args['manage_stock'] ) && $args['manage_stock'] ) {
                $product->set_stock_status( $args['stock_qty'] );
                $product->set_backorders( isset( $args['backorders'] ) ? $args['backorders'] : 'no' ); // 'yes', 'no' or 'notify'
            }
        }

        // Sold Individually
        $product->set_sold_individually( isset( $args['sold_individually'] ) ? $args['sold_individually'] : false );

        // Weight, dimensions and shipping class
        $product->set_weight( isset( $args['weight'] ) ? $args['weight'] : '' );
        $product->set_length( isset( $args['length'] ) ? $args['length'] : '' );
        $product->set_width( isset(  $args['width'] ) ?  $args['width']  : '' );
        $product->set_height( isset( $args['height'] ) ? $args['height'] : '' );
        if( isset( $args['shipping_class_id'] ) )
            $product->set_shipping_class_id( $args['shipping_class_id'] );

        // Upsell and Cross sell (IDs)
        $product->set_upsell_ids( isset( $args['upsells'] ) ? $args['upsells'] : '' );
        $product->set_cross_sell_ids( isset( $args['cross_sells'] ) ? $args['upsells'] : '' );

        // Attributes et default attributes
        if( isset( $args['attributes'] ) )
            $product->set_attributes( wc_prepare_product_attributes($args['attributes']) );
        if( isset( $args['default_attributes'] ) )
            $product->set_default_attributes( $args['default_attributes'] ); // Needs a special formatting

        // Reviews, purchase note and menu order
        $product->set_reviews_allowed( isset( $args['reviews'] ) ? $args['reviews'] : false );
        $product->set_purchase_note( isset( $args['note'] ) ? $args['note'] : '' );
        if( isset( $args['menu_order'] ) )
            $product->set_menu_order( $args['menu_order'] );

        // Product categories and Tags
        if( isset( $args['category_ids'] ) )
            $product->set_category_ids( $args['category_ids'] );
        if( isset( $args['tag_ids'] ) )
            $product->set_tag_ids( $args['tag_ids'] );


        // Images and Gallery
        $product->set_image_id( isset( $args['image_id'] ) ? $args['image_id'] : "" );
        $product->set_gallery_image_ids( isset( $args['gallery_ids'] ) ? $args['gallery_ids'] : array() );

        ## --- SAVE PRODUCT --- ##
        $product_id = $product->save();

        return $product_id;
    }

    // Utility function that returns the correct product object instance
    function wc_get_product_object_type( $type = 'simple' ) {
        // Get an instance of the WC_Product object (depending on his type)
        if( $type === 'variable' ){
            $product = new WC_Product_Variable();
        } elseif( $type === 'grouped' ){
            $product = new WC_Product_Grouped();
        } elseif( $type === 'external' ){
            $product = new WC_Product_External();
        } else {
            $product = new WC_Product_Simple(); // "simple" By default
        } 
        
        if( ! is_a( $product, 'WC_Product' ) )
            return false;
        else
            return $product;
    }

    // Utility function that prepare product attributes before saving
    function wc_prepare_product_attributes( $attributes ){
        global $woocommerce;

        $data = array();
        $position = 0;

        foreach( $attributes as $taxonomy => $values ){
            if( ! taxonomy_exists( $taxonomy ) )
                continue;

            // Get an instance of the WC_Product_Attribute Object
            $attribute = new WC_Product_Attribute();

            $term_ids = array();

            // Loop through the term names
            foreach( $values['term_names'] as $term_name ){
                if( term_exists( $term_name, $taxonomy ) )
                    // Get and set the term ID in the array from the term name
                    $term_ids[] = get_term_by( 'name', $term_name, $taxonomy )->term_id;
                else
                    continue;
            }

            $taxonomy_id = wc_attribute_taxonomy_id_by_name( $taxonomy ); // Get taxonomy ID

            $attribute->set_id( $taxonomy_id );
            $attribute->set_name( $taxonomy );
            $attribute->set_options( $term_ids );
            $attribute->set_position( $position );
            $attribute->set_visible( $values['is_visible'] );
            $attribute->set_variation( $values['for_variation'] );

            $data[$taxonomy] = $attribute; // Set in an array

            $position++; // Increase position
        }
        return $data;
    }

2) USAGE: - Example for a simple product creation with 2 product attributes "Color" and "Size":


    $product_id = create_product( array(
        'type'               => '', // Simple product by default
        'name'               => __("The product title", "woocommerce"),
        'description'        => __("The product description…", "woocommerce"),
        'short_description'  => __("The product short description…", "woocommerce"),
        // 'sku'                => '',
        'regular_price'      => '5.00', // product price
        // 'sale_price'         => '',
        'reviews_allowed'    => true,
        'attributes'         => array(
            // Taxonomy and term name values
            'pa_color' => array(
                'term_names' => array('Red', 'Blue'),
                'is_visible' => true,
                'for_variation' => false,
            ),
            'pa_size' =>  array(
                'term_names' => array('X Large'),
                'is_visible' => true,
                'for_variation' => false,
            ),
        ),
    ) );  

// Displaying the created product ID
echo $product_id;

Tested and works using only Woocommerce 3 CRUD methods.

Glycerol answered 23/10, 2018 at 5:54 Comment(8)
Thanks for your reply! How do I get access to Woocommerce's classes? Because I get a similar error code when I tried your code: [23-Oct-2018 13:08:23 UTC] PHP Fatal error: Uncaught Error: Class WC_Product_Simple' not found in ... This is my first plugin, so I have no idea what to include to make this possible. Woocommerce is installed and active on my website.Rigatoni
@Rigatoni With the provided code, informations and details, actually it's not possible to see how is your plugin built, when and how you are triggering the product creation. My answer code works, but I can't guess why is not working in your plugin.Glycerol
Your code is the only code in my plugin that tries to create a new product. The rest just creates the plugin's settings page, a few custom fields in the inventory tab and I use cURL to scrape information. It seems that I miss some code to include all Woocommerce's classes. Does $product = new WC_Product_Simple(); normally do something when Woocommerce is activated on the website? Or do I need to set up a few things with Woocommerce first before the plugin can find the classes?Rigatoni
@Rigatoni If you can post somewhere your plugin file(s) and add the links it will be the only way to see how to solve the problem.Glycerol
I used the plugins_loaded hook (codex.wordpress.org/Plugin_API/Action_Reference/plugins_loaded) and now it works :).Rigatoni
@Glycerol simple product manage stock is not working using the above function.Kelikeligot
A { is missing after function wc_get_product_object_type( $type )Adiathermancy
@Glycerol Why does wc_prepare_product_attributes need to import $woocommerce via the global keyword? It isn't use in the code.Battleplane
G
6

Another way: https://wordpress.stackexchange.com/a/137578/74284 , Use wp_insert_post function.

https://lukasznowicki.info/insert-new-woocommerce-product-programmatically/

$item = array(
    'Name' => 'Product A',
    'Description' => 'This is a product A',
    'SKU' => '10020030A',
);
$user_id = get_current_user(); // this has NO SENSE AT ALL, because wp_insert_post uses current user as default value
// $user_id = $some_user_id_we_need_to_use; // So, user is selected..
$post_id = wp_insert_post( array(
    'post_author' => $user_id,
    'post_title' => $item['Name'],
    'post_content' => $item['Description'],
    'post_status' => 'publish',
    'post_type' => "product",
) );
wp_set_object_terms( $post_id, 'simple', 'product_type' );
update_post_meta( $post_id, '_visibility', 'visible' );
update_post_meta( $post_id, '_stock_status', 'instock');
update_post_meta( $post_id, 'total_sales', '0' );
update_post_meta( $post_id, '_downloadable', 'no' );
update_post_meta( $post_id, '_virtual', 'yes' );
update_post_meta( $post_id, '_regular_price', '' );
update_post_meta( $post_id, '_sale_price', '' );
update_post_meta( $post_id, '_purchase_note', '' );
update_post_meta( $post_id, '_featured', 'no' );
update_post_meta( $post_id, '_weight', '' );
update_post_meta( $post_id, '_length', '' );
update_post_meta( $post_id, '_width', '' );
update_post_meta( $post_id, '_height', '' );
update_post_meta( $post_id, '_sku', $item['SKU'] );
update_post_meta( $post_id, '_product_attributes', array() );
update_post_meta( $post_id, '_sale_price_dates_from', '' );
update_post_meta( $post_id, '_sale_price_dates_to', '' );
update_post_meta( $post_id, '_price', '' );
update_post_meta( $post_id, '_sold_individually', '' );
update_post_meta( $post_id, '_manage_stock', 'no' );
update_post_meta( $post_id, '_backorders', 'no' );
update_post_meta( $post_id, '_stock', '' );
Gilles answered 22/10, 2018 at 20:56 Comment(2)
Much easier to fit into existing workflows. Thanks!Woolfolk
This is what I was looking forAngleaangler

© 2022 - 2024 — McMap. All rights reserved.