Woocommerce Duplicate product then increment highest SKU - php

Using woocommerce hook as follow :
I am expecting with the query $queryLast to get latest product SKU,
BUT
get_the_ID() always returns the duplicated items even with :
wp_reset_postdata();
wp_reset_query();
clean_post_cache(get_the_ID());
I need to get item ID requested in queryLast.
To illustrate, let's say my highest SKU is 1600, i am duplicating SKU 300.
Expected behavior is to assign new SKU 1601 to the new product ( SKU 300 duplication )
Now it does assign new SKU to 301...etc
add_action( 'woocommerce_product_duplicate', 'duplicate_sku_func', 10, 2 );
function duplicate_sku_func( $duplicate ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
$product_id = $duplicate->save();
wp_reset_postdata();
wp_reset_query();
clean_post_cache(get_the_ID());
$args = array(
'order' => 'DESC',
'orderby' => 'id' ,
'post_type'=> 'product',
'posts_per_page' => 1 ,
);
$queryLast = new WP_Query($args);
while ( $queryLast->have_posts() ) : $queryLast->the_post();
$sku2 = get_post_meta( get_the_ID(), '_sku', true );
//$your_sku = get_the_ID();
$your_sku = (int) $sku2+1;
endwhile;
update_post_meta($product_id, '_sku', $your_sku );
update_post_meta($product_id, '_manage_stock', 'yes');
update_post_meta($product_id, '_stock', '1');
}

First of all the hook woocommerce_product_duplicate is called after duplicate product saved. So, definitely you are getting new duplicate product sku value which is from parent sku 300 not the last product sku 1600. Because the last inserted product sku is now 301 and you are getting that.
So, Replace your codes with follows snippet -
add_action( 'woocommerce_product_duplicate_before_save', 'duplicate_sku_func', 10, 2 );
function duplicate_sku_func( $duplicate, $product ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
$args = array(
'order' => 'DESC',
'orderby' => 'id' ,
'post_type'=> 'product',
'posts_per_page' => 1 ,
'fields' => 'ids'
);
$queryLast = new WP_Query($args);
$your_sku = '';
if( $queryLast->get_posts() ) {
foreach ( $queryLast->get_posts() as $product_id) {
$sku2 = get_post_meta( get_the_ID(), '_sku', true );
$your_sku = (int) $sku2+1;
}
}
$duplicate->set_sku( $your_sku );
$duplicate->set_manage_stock( 'yes' );
$duplicate->set_stock_quantity( 1 );
}

Related

WP All Import don't importing values from custom fields

I have custom tab for Frequently Bought Together products in my woocommerce site, that shows up on single product page. When i update products via WP All Import, only one product show up in custom tab and should be a two. Here is the settings of custom fields import and actually view of the single product page.
custom-fields-settings
single-product-accessory-tab
I'll provide Single Product Accessories template, just to make it clear
accessorie template function
global $product;
$loop_columns = apply_filters( 'mc_accessories_loop_columns', 4 );
$posts_per_page = 4;
if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '3.3', '<' ) ) {
global $woocommerce_loop;
$woocommerce_loop['columns'] = $loop_columns;
} else {
wc_set_loop_prop( 'columns', $loop_columns );
}
$product_id = mc_wc_get_product_id( $product );
$accessories = MediaCenter_WC_Helper::get_accessories( $product );
array_unshift( $accessories, $product_id );
if ( sizeof( $accessories ) === 0 && !array_filter( $accessories ) ) {
return;
}
$meta_query = WC()->query->get_meta_query();
$args = apply_filters( 'mc_accessories_query_args', array(
'post_type' => 'product',
'ignore_sticky_posts' => 1,
'no_found_rows' => 1,
'posts_per_page' => $posts_per_page,
'orderby' => 'post__in',
'post__in' => $accessories,
'meta_query' => $meta_query
) );
unset( $args['meta_query'] );
$products = new WP_Query( $args );
$add_to_cart_checkbox = '';
$total_price = 0;
$count = 0;
Any help will be appreciated
Solution is so easy, just need to import post Id's, i lost two weeks on that problem.

How to show order details (my-account) for a specific product (id) on a separate page in Woocommerce?

I want to display the order table found in woocommerce my-account recent orders for a specific product id on a separate page. To be more precise, display all recent orders for current user if the order has a product with the product_id of X.
I am trying to use these references:
Woocommerce - How to show Order details (my-account) on a separate page
Get all Orders IDs from a product ID in Woocommerce
Woocommerce: Get all orders for a product
But I am not able to relate $product_id to $user_id = get_current_user_id(); so that all the orders of the current user for a particular product id can be displayed on a separate page.
Edit: added code. I tried this code but its not working.
function orders_from_product_id( $product_id ) {
$order_statuses = array('wc-on-hold', 'wc-processing', 'wc-completed');
$customer_user_id = get_current_user_id(); // current user ID here for example
$customer_orders = wc_get_orders( array(
'meta_key' => '_customer_user',
'meta_value' => $customer_user_id,
'post_status' => $order_statuses,
'numberposts' => -1
) );
foreach($customer_orders as $order ){
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
foreach($order->get_items() as $item_id => $item){
$product_id = method_exists( $item, 'get_product_id' ) ? $item->get_product_id() : $item['product_id'];
if ( $product_id == 326 ) {
ob_start();
wc_get_template( 'myaccount/my-orders.php', array(
'current_user' => get_user_by( 'id', $user_id),
'order_count' => $order_count
) );
return ob_get_clean();
} else {
echo '<p> You donot have any orders.</p>';
}
}
}
}
add_shortcode('woocommerce_orders', 'orders_from_product_id');
From this code you to get the Current user-product id which product purchased by the user.
// GET CURR USER
$current_user = wp_get_current_user();
if ( 0 == $current_user->ID ) return;
// GET USER ORDERS (COMPLETED + PROCESSING)
$customer_orders = get_posts( array(
'numberposts' => -1,
'meta_key' => '_customer_user',
'meta_value' => $current_user->ID,
'post_type' => wc_get_order_types(),
'post_status' => array_keys( wc_get_is_paid_statuses() ),
) );
// LOOP THROUGH ORDERS AND GET PRODUCT IDS
if ( ! $customer_orders ) return;
$product_ids = array();
foreach ( $customer_orders as $customer_order ) {
$order = wc_get_order( $customer_order->ID );
$items = $order->get_items();
foreach ( $items as $item ) {
$product_id = $item->get_product_id();
$product_ids[] = $product_id;
}
}
$product_ids = array_unique( $product_ids );

How to programmatically set a term to a Woocommerce product variation?

I would like to set all variable products, when created, with the same six different variations using an already defined attribute ("bidragsstorlek"). The six variations should have different prices.
With my current code I succeded with all steps except the last one. I succefully added an attribute, six diffrent terms and six different variations. When I look in the back end panel the product variations have the prices I want, the only thing missing is to set the right term to each variation.
I know similar questions been asked before and been trying to implement those answers, but can't get it right.
$taxonomy = 'pa_bidragsstorlek';
$arrtermnames = array('50 kronor', '100 kronor', '250 kronor', '500 kronor', '1000 kronor', '5000 kronor');
$attr_data = Array(
$taxonomy=>Array(
'name' => $taxonomy,
'value' => '',
'is_visible' => '1',
'is_variation' => '1',
'is_taxonomy' => '1'
)
);
$newproduct = new WC_Product($product_id);
update_post_meta( $product_id, '_product_attributes', array_merge($newproduct->get_attributes(), $attr_data) );
foreach ($arrtermnames as &$value) {
$term_name = $value; // The term "NAME"
$term_slug = sanitize_title($term_name); // The term "slug"
// Check if the term exist and if not it create it (and get the term ID).
if( ! term_exists( $term_name, $taxonomy ) ){
$term_data = wp_insert_term( $term_name, $taxonomy );
$term_id = $term_data['term_id'];
} else {
$term_id = get_term_by( 'name', $term_name, $taxonomy )->term_id;
}
// get an instance of the WC_Product Object
$product = wc_get_product( $product_id );
$attributes = (array) $product->get_attributes();
// 1. If the product attribute is set for the product
if( array_key_exists( $taxonomy, $attributes ) ) {
foreach( $attributes as $key => $attribute ){
if( $key == $taxonomy ){
$options = (array) $attribute->get_options();
$options[] = $term_id;
$attribute->set_options($options);
$attributes[$key] = $attribute;
break;
}
}
$product->set_attributes( $attributes );
}
// 2. The product attribute is not set for the product
else {
$attribute = new WC_Product_Attribute();
$attribute->set_id( sizeof( $attributes) + 1 );
$attribute->set_name( $taxonomy );
$attribute->set_options( array( $term_id ) );
$attribute->set_position( sizeof( $attributes) + 1 );
$attribute->set_visible( true );
$attribute->set_variation( false );
$attributes[] = $attribute;
$product->set_attributes( $attributes );
}
$product->save();
// Append the new term in the product
if( ! has_term( $term_name, $taxonomy, $product_id ))
wp_set_object_terms($product_id, $term_slug, $taxonomy, true );
}
unset($value);
$parent_id = $product_id;
$arrprice = array(50, 100, 250, 500, 1000, 5000);
for ($x = 0; $x <= 5; $x++) {
$variation = array(
'post_title' => 'Product #' . $parent_id. $arrprice[$x],
'post_content' => '',
'post_status' => 'publish',
'post_parent' => $parent_id,
'post_type' => 'product_variation'
);
// The variation id
$variation_id = wp_insert_post( $variation );
update_post_meta( $variation_id, '_regular_price', $arrprice[$x] );
update_post_meta( $variation_id, '_price', $arrtermnames[$x] );
update_post_meta( $variation_id, '_virtual', '1' );
// Assign the size and color of this variation
update_post_meta( $variation_id, 'attribute_'.$taxonomy, $arrtermnames[$x] );
WC_Product_Variable::sync( $parent_id );
}
Right now with this code, when checking in the panel, I have a drop-down at each variation with all the terms - but none is choosen. Any idea what is missing to make each variation to be set to the right term?

wordpress add field for every custom type

I want to create a stock level field in WooCommerce Products for every Store custom post type.
I've already created the Store custom post type and added 3 stores to it. I want to automatically add a "stock level at store" field every time someone adds a Store so that I could check the stocks at store level.
I'm trying to put the custom field at the Products->Inventory-> right under the Stock Quantity.
I've tried this:
$post_type = 'store';
$tax = 'show-topic';
$inv_arg_terms = get_terms(array('orderby' => 'id', 'order' => 'ASC'));
if ($inv_arg_terms) {
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'title',
'order' => 'ASC'
); // END $args
$my_query = null;
$my_query = new WP_Query($args);
if ($my_query->have_posts()) {
while ($my_query->have_posts()) : $my_query->the_post();
add_action( 'woocommerce_product_options_inventory_product_data', 'wc_inventory_stock_product_field' );
function wc_inventory_stock_product_field() {
woocommerce_wp_text_input( array( 'id' => 'stock_level_' . the_title(), 'class' => 'short wc_input_stock', 'label' => __( 'Stock Level at ' . the_title(), 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')' ) );
}
add_action( 'save_post', 'wc_cost_save_product' );
function wc_cost_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( isset( $_POST['stock_level_' . the_title()] ) ) {
if ( is_numeric( $_POST['stock_level_' . the_title()] ) )
update_post_meta( $product_id, 'stock_level_' . the_title(), $_POST['cost_price'] );
} else delete_post_meta( $product_id, 'stock_level_' . the_title() );
}
endwhile;
} // END if have_posts loop
wp_reset_query();
} // END if $inv_arg_terms
and I got this:
Fatal error: Call to undefined function get_userdata() in
.../wp-includes/query.php on line 4758
Is what I'm thinking possible? How do I go about it?
Thanks, appreciate every help I could get.
Finally got it to work. Here's the code:
add_action( 'woocommerce_product_options_inventory_product_data', 'wc_stock_product_field' );
add_action( 'woocommerce_process_product_meta', 'wc_stock_save_product' );
function wc_stock_product_field() {
global $woocommerce, $post;
$post_type = 'store';
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'id',
'order' => 'ASC',
'caller_get_posts' => 1
); // END $args
$store_query = null;
$store_query = new WP_Query($args);
if ($store_query->have_posts()) {
while ($store_query->have_posts()) : $store_query->the_post();
woocommerce_wp_text_input(
array(
'id' => get_the_id() ,
'class' => 'short wc_input_stock',
'label' => __( 'Stock Level # ' . get_the_title(), 'woocommerce' ) ) );
endwhile;
} // END if have_posts loop
wp_reset_query();
}
function wc_stock_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
$post_type = 'store';
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => - 1,
'orderby' => 'id',
'order' => 'ASC',
'caller_get_posts' => 1
); // END $args
$store_query = null;
$store_query = new WP_Query($args);
if ($store_query->have_posts()) {
while ($store_query->have_posts()) : $store_query->the_post();
if ( isset( $_POST[get_the_id()] ) ) {
if ( is_numeric( $_POST[get_the_id()] ) )
update_post_meta( $product_id, get_the_id(), $_POST[get_the_id()] );
} else delete_post_meta( $product_id, get_the_id() );
endwhile;
} // END if have_posts loop
wp_reset_query();
}

Unable to get WooCoommerce product variation id

I am trying to update a specific field for all variations in a product, but unfortunately, I am unable to get variation ids to go further.
Basically what I am doing is, I am trying to get each variation's stock value and if the stock value is less than zero, then I am updating a particular field with certain values (as mentioned in my code below).
I have tested this by manually inputting any custom post / variation id and is working fine, updates that particular variation id based on its stock value. All I am stuck here is I am unable to fetch the variation id by itself.
Below is the code that I am using:
global $post, $woocommerce;
$post_id = $variation->ID;
// Get specific data from the certain custom fields using get_post_meta( $post_id, $key, $single );
$stock = get_post_meta( $post_id, '_stock', true );
if ($stock < 1) {
update_post_meta( $post_id, 'cuzd-prod-general-v', '20,25' );
} else {
update_post_meta( $post_id, 'cuzd-prod-general-v', '1,5' );
}
I don't know where I am wrong to get the variation ids for this.
I was able to solve this by using below code changes:
// Values to be updated
$in_stock = '1,5';
$out_of_stock = '20,30';
// Get variations
$args = array(
'post_type' => 'product_variation',
'post_status' => array( 'private', 'publish' ),
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'asc',
'post_parent' => $post->ID
);
$variations = get_posts( $args );
foreach ( $variations as $variation ) {
$variation_id = absint( $variation->ID );$variable_id = $this['variation_id'];
$variation_post_status = esc_attr( $variation->post_status );
$variation_data = get_post_meta( $variation_id );
$variation_data['variation_post_id'] = $variation_id;
// Get specific data from the certain custom fields using get_post_meta( $post_id, $key, $single );
$stock = get_post_meta( $variation_data['variation_post_id'], '_stock', true );
if ($stock < 1) {
update_post_meta( $variation_data['variation_post_id'], 'cuzd-prod-general-v', $out_of_stock );
} else {
update_post_meta( $variation_data['variation_post_id'], 'cuzd-prod-general-v', $in_stock );
}
}

Categories