Create Programmatically a Product Using Crud Methods in Woocommerce 3

Create programmatically a product using CRUD methods in Woocommerce 3

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:

  • Create new product attribute programmatically in Woocommerce
  • Create programmatically a WooCommerce product variation with new attribute values
  • Create programmatically a variable product and two new attributes in WooCommerce

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.

Create programmatically a WooCommerce product variation with new attribute values

Update January 2020: Changed to WC_Product method get_name() instead of get_title()
Update September 2018: Handling taxonomy creation (Thanks to Carl F. Corneil)

From a defined variable product ID You will find below, a custom function that will add (create) a Product variation. The variable parent product needs to have set for it the needed attributes.

You will need to provide some information as:

  • the array of attributes/values
  • the Sku, prices and stock….

This data has to be stored in a formatted multi dimensional array (see an example at the end).

This function will check if the attributes values (term name) already exist and if not:

  • it create it for the product attribute
  • set it in the parent variable product.

The custom function code:

/**
* Create a product variation for a defined variable product ID.
*
* @since 3.0.0
* @param int $product_id | Post ID of the product parent variable product.
* @param array $variation_data | The data to insert in the product.
*/

function create_product_variation( $product_id, $variation_data ){
// Get the Variable product object (parent)
$product = wc_get_product($product_id);

$variation_post = array(
'post_title' => $product->get_name(),
'post_name' => 'product-'.$product_id.'-variation',
'post_status' => 'publish',
'post_parent' => $product_id,
'post_type' => 'product_variation',
'guid' => $product->get_permalink()
);

// Creating the product variation
$variation_id = wp_insert_post( $variation_post );

// Get an instance of the WC_Product_Variation object
$variation = new WC_Product_Variation( $variation_id );

// Iterating through the variations attributes
foreach ($variation_data['attributes'] as $attribute => $term_name )
{
$taxonomy = 'pa_'.$attribute; // The attribute taxonomy

// If taxonomy doesn't exists we create it (Thanks to Carl F. Corneil)
if( ! taxonomy_exists( $taxonomy ) ){
register_taxonomy(
$taxonomy,
'product_variation',
array(
'hierarchical' => false,
'label' => ucfirst( $attribute ),
'query_var' => true,
'rewrite' => array( 'slug' => sanitize_title($attribute) ), // The base slug
),
);
}

// Check if the Term name exist and if not we create it.
if( ! term_exists( $term_name, $taxonomy ) )
wp_insert_term( $term_name, $taxonomy ); // Create the term

$term_slug = get_term_by('name', $term_name, $taxonomy )->slug; // Get the term slug

// Get the post Terms names from the parent variable product.
$post_term_names = wp_get_post_terms( $product_id, $taxonomy, array('fields' => 'names') );

// Check if the post term exist and if not we set it in the parent variable product.
if( ! in_array( $term_name, $post_term_names ) )
wp_set_post_terms( $product_id, $term_name, $taxonomy, true );

// Set/save the attribute data in the product variation
update_post_meta( $variation_id, 'attribute_'.$taxonomy, $term_slug );
}

## Set/save all other data

// SKU
if( ! empty( $variation_data['sku'] ) )
$variation->set_sku( $variation_data['sku'] );

// Prices
if( empty( $variation_data['sale_price'] ) ){
$variation->set_price( $variation_data['regular_price'] );
} else {
$variation->set_price( $variation_data['sale_price'] );
$variation->set_sale_price( $variation_data['sale_price'] );
}
$variation->set_regular_price( $variation_data['regular_price'] );

// Stock
if( ! empty($variation_data['stock_qty']) ){
$variation->set_stock_quantity( $variation_data['stock_qty'] );
$variation->set_manage_stock(true);
$variation->set_stock_status('');
} else {
$variation->set_manage_stock(false);
}

$variation->set_weight(''); // weight (reseting)

$variation->save(); // Save the data
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Usage (example with 2 attributes):

$parent_id = 746; // Or get the variable product id dynamically

// The variation data
$variation_data = array(
'attributes' => array(
'size' => 'M',
'color' => 'Green',
),
'sku' => '',
'regular_price' => '22.00',
'sale_price' => '',
'stock_qty' => 10,
);

// The function to be run
create_product_variation( $parent_id, $variation_data );

Tested and works.

Part 2: Create programmatically a variable product and two new attributes in WooCommerce

You will get this in backend:

Sample Image

And it will work perfectly in front end.

Related: Create programmatically a product using CRUD methods in Woocommerce 3

Add a new product from a custom product type programmatically in WooCommerce 4

1). Instead of using the WordPress old way, since WooCommerce 3, Use WC_Order methods instead.

Important notes:

  • Product Image: Normally the image is set from an attachment id, but not from an URL. Also save_featured_image() is not a WordPress function.
  • Product name (or title): Is mandatory.
  • There are a lot of mistakes and errors in your provided code.

Product types and custom product types

  • In the code below you will have to define the product type.
  • Custom product type: It will be necessary to define also the Class name as defined for the custom product type source code Class.

For example for a "grouped" product type:

$auction_title    = isset($_POST['auction_title']) ? sanitize_text_field($_POST['auction_title']) : '';
$auction_category = isset($_POST['auction_category']) ? esc_attr($_POST['auction_category']) : 'auction';

$product_type = 'grouped'; // <== Here define your product type slug
$class_name = WC_Product_Factory::get_classname_from_product_type($product_type); // Get the product Class name

// If the product class exist for the defined product type
if( ! empty($class_name) && class_exists( $class_name ) ) {
$product = new $class_name(); // Get an empty instance of a grouped product Object
}
// For a custom product class
else {
$class_name = 'WC_Product_custom'; // <== Here define the Class name of your custom product type

if( class_exists( $class_name ) ) {
$product = new $class_name(); // Get an empty instance of a custom class product Object
} else {
wp_send_json_error( array( 'message' =>__('Wrong product class') ), 409 );
return; // or exit;
}
}

$product->set_name($auction_title);
$product->set_description('Description');
$product->set_short_description('Short_description');
$product->set_status('publish');

// $product-> set_image_id( $image_id ); // ???

$category_term = get_term_by( 'slug', $auction_category, 'product_cat' ); // Get the term from its slug
if( is_a($category_term, 'WP_Term') ) {
$product->set_category_ids( array($category_term->term_id) );
}

$product_id = $product->save(); // Save product to database

if ( $product_id ) {
// Set the post author
if( isset($_POST['author_id']) ) {
wp_update_post('ID' => $product_id, 'post_author' => esc_attr($_POST['author_id']) );
}

wp_send_json_success(array('auction_id' => $product_id,'message' => __('Auction Added Successfully!!') ), 200);
} else {
wp_send_json_error( array( 'auction_id' => $product_id, 'message' =>__('Auction failed :(') ), 400 );
}

This code should better works.


2). Or you can still use the Wordpress Old Way combined:

$auction_data = array(
'post_author' => isset($_POST['author_id']) ? esc_attr($_POST['author_id']) : '',
'post_content' => 'Description',
'post_status' => "publish",
'post_title' => isset($_POST['auction_title']) ? sanitize_text_field($_POST['auction_title']) : __('Empty title'),
'post_parent' => '',
'post_type' => "product",
);

$auction_id = wp_insert_post($auction_data, $wp_error);

if ( $auction_id ) {
$auction_category = isset($_POST['auction_category']) ? esc_attr($_POST['auction_category']) : 'auction';
wp_set_object_terms( $auction_id, $auction_category, 'product_cat' );

if( isset($_POST['auction_image_url']) && function_exists('save_featured_image') ) {
save_featured_image($auction_image, ecs_attr($_POST['auction_image_url']));
}

update_post_meta( $auction_id, '_author_id', $author_id );

$product_type = 'grouped'; // <== Here define your product type slug
$class_name = WC_Product_Factory::get_product_classname( $product_id, $new_product_type );

// If the product class exist for the defined product type
if( ! empty($class_name) && class_exists( $class_name ) ) {
$product = new $class_name($auction_id); // Get an empty instance of a grouped product Object
}
// For a custom product class (you may have to define the custom class name)
else {
$class_name = 'WC_Product_custom'; // <== Here define the Class name of your custom product type

if( class_exists( $class_name ) ) {
$product = new $class_name($auction_id); // Get an empty instance of a custom class product Object
} else {
wp_send_json_error( array( 'message' =>__('Wrong product class') ), 409 );
return; // or exit;
}
}

$auction_id = $product->save(); // Save to database

wp_send_json_success( array('auction_id' => $auction_id, 'message' => __('Auction Added Successfully!!') ), 200 );
} else {
wp_send_json_error( array('message' => __('Auction Failed') 400 );
}

This should also work.


Related:

  • Create programmatically a product using CRUD methods in Woocommerce 3
  • Change the product type of an existing product in WooCommerce 3+
  • Source code for WC_Product Class (methods) and WC_Product_Grouped Class (methods)

Create programmatically a variable product and two new attributes in WooCommerce

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:

  • Create new product attribute programmatically in Woocommerce
  • Create programmatically a WooCommerce product variation with new attribute values
  • Create programmatically a product using CRUD methods in Woocommerce 3

Set order creation date using CRUD methods and save it in Woocommerce 3

You need also to save the data… try the following instead:

// Get an instance of the WC_Order object
$order = wc_get_order( $post->ID );

// Get an instance of the current WC_DateTime object
$date_time = new WC_DateTime();

// Set it in the order
$order->set_date_created( $date_time );

// Save the data (in database)
$order->save();

This time it should works, and you will not get an empty value.

Updating product stock programmatically in Woocommerce 3

Update 2

Since woocommerce 3 "outofstock" product status is saved in 2 locations:

  1. As post meta data for _stock_status meta key (just as before).
  2. As a post term name outofstock remaining to product_visibility custom taxonomy

That means that you missed just a step (the step 3):

$out_of_stock_staus = 'outofstock';

// 1. Updating the stock quantity
update_post_meta($product_id, '_stock', 0);

// 2. Updating the stock quantity
update_post_meta( $product_id, '_stock_status', wc_clean( $out_of_stock_staus ) );

// 3. Updating post term relationship
wp_set_post_terms( $product_id, 'outofstock', 'product_visibility', true );

// And finally (optionally if needed)
wc_delete_product_transients( $product_id ); // Clear/refresh the variation cache

It hope that it will work with your cron job.


Original answer

Your code is a bit outdated since woocommerce 3 and there is no specifically a stock status setting for product variations...



Related Topics



Leave a reply



Submit