No decrement on order wordpress - wordpress

everybody !
I'm looking for a way to no decrement when an order is completed.
Exemple: I got 1 T-shirt with 20 quantity. When i order, i want the number to be still 20, and not 19.)
here my hook:
add_action( 'woocommerce_order_status_completed', 'action_on_order_completed' , 10, 1 );
function action_on_order_completed( $order_id )
{
// Get an instance of the order object
$order = wc_get_order( $order_id );
// Iterating though each order items
foreach ( $order->get_items() as $item_id => $item_values ) {
// Item quantity
$item_qty = $item_values['qty'];
// getting the product ID (Simple and variable products)
$product_id = $item_values['variation_id'];
if( $product_id == 0 || empty($product_id) ) $product_id = $item_values['product_id'];
// Get an instance of the product object
$product = wc_get_product( $product_id );
// Get the stock quantity of the product
$product_stock = $product->get_stock_quantity();
// Increase back the stock quantity
wc_update_product_stock( $product, $item_qty, 'increase' );
}
}
But when the order is completed, the quantity still decrease. Any idea ?

That is because your hooked function is triggered after stock quantity is decreased.
You are trying to get previous stock quantity with
$product_stock = $product->get_stock_quantity();
But in that case this method returns already decreased value.
So, try this:
wc_update_product_stock( $product, $product_stock + $item_qty, 'increase' );

Related

Get related products SKUs in WooCommerce

We want to show a section called "complete the look" in WooCommerce. We are using PureClarity to do that.
PureClarity asked us to extend the WooCommerce feed by adding a code snippet in functions.php to add related peoducts SKUs under RelatedProducts.
We used the following code:
function product_callbackk($data, $product) {
$data['RelatedProducts'] = $product->get_sku() ?? null;
return $data;
}
add_filter( 'pureclarity_feed_get_product_data', 'product_callbackk', 10, 2 );
But it showing only the current product SKU and not the related products SKUs. Any advice?
I don't use PureClarity so I added an example based on a default hook in WooCommerce.
In this I use wc_get_related_products() which allow to obtain related products based on the current product ID.
The product SKU per product can then be obtained via a foreach loop.
So you get:
function action_woocommerce_single_product_summary() {
// Get the global product object
global $product;
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Initialize
$skus = array();
// Get product ID
$product_id = $product->get_id();
// Get related products based on product category and tags || second argument = limit of results, default = 5
$related_products = wc_get_related_products( $product_id, 10 );
// Loop through
foreach ( $related_products as $related_product ) {
// Get product
$product = wc_get_product( $related_product );
// Get product SKU
$product_sku = $product->get_sku();
// NOT empty
if ( ! empty( $product_sku ) ) {
// Push to array
$skus[] = $product_sku;
}
}
// Output
echo '<pre>', print_r( $skus, 1 ), '</pre>';
}
}
add_action( 'woocommerce_single_product_summary', 'action_woocommerce_single_product_summary', 10 );
Or in your specific case:
/**
* #param mixed[] $data - the array of data that will be sent to PureClarity
* #param WC_Product $product - the WooCommerce product object
* #return mixed
*/
function filter_pureclarity_feed_get_product_data( $data, $product ) {
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Initialize
$skus = array();
// Get product ID
$product_id = $product->get_id();
// Get related products based on product category and tags || second argument = limit of results, default = 5
$related_products = wc_get_related_products( $product_id, 10 );
// Loop through
foreach ( $related_products as $related_product ) {
// Get product
$product = wc_get_product( $related_product );
// Get product SKU
$product_sku = $product->get_sku();
// NOT empty
if ( ! empty( $product_sku ) ) {
// Push to array
$skus[] = $product_sku;
}
}
$data['RelatedProducts'] = $skus;
}
return $data;
}
add_filter( 'pureclarity_feed_get_product_data', 'filter_pureclarity_feed_get_product_data', 10, 2 );

Woocommerce : programmatically set a discount for the first item ordered, but inventory based

I'm building a website where i'll sell some fine art prints and i would like to set an automated discount when a customer buy the first print of a serie. Each of my prints are limited to 15 pieces and i would like to set a 30% discount for the first sell (#1/15) of each series. Then, for the next prints (#2 to #15), price goes back to normal.
Edit :
I did progress on my problem ! I did some research and tried a lot of different things and i found how to set the custom price i wanted on my product page (regular price + discount price) with the rule to only apply it if the related item available stock is 15.
regular price + discount price
And here's the code is used :
// Generating the product "regular price"
add_filter( 'woocommerce_product_get_regular_price', 'dynamic_regular_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_regular_price', 'dynamic_regular_price', 10, 2 );
function dynamic_regular_price( $regular_price, $product ) {
$stock_qte = $product->get_stock_quantity();
if( empty($regular_price) || $regular_price == 0 )
return $product->get_price();
else
return $regular_price;
}
// Generating the product "sale price"
add_filter( 'woocommerce_product_get_sale_price', 'dynamic_sale_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_sale_price', 'dynamic_sale_price', 10, 2 );
function dynamic_sale_price( $sale_price, $product ) {
$stock_qte = $product->get_stock_quantity();
if( $stock_qte == '15')
return $product-> get_regular_price() * 0.7;
else
//return $product->get_regular_price();
return $regular_price;
};
// Displayed formatted regular price + sale price
add_filter( 'woocommerce_get_price_html', 'dynamic_sale_price_html', 20, 2 );
function dynamic_sale_price_html( $price_html, $product ) {
$stock_qte = $product->get_stock_quantity();
if( $stock_qte == '15')
$price_html = wc_format_sale_price( wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ), wc_get_price_to_display( $product, array( 'price' => $product->get_sale_price() ) ) ) . $product->get_price_suffix();
else
$price_html = wc_price(wc_get_price_to_display( $product, array( 'price' => $product->get_regular_price() ) ). $product->get_price_suffix());
return $price_html;
}
It's almost working but the code related to the cart values updates is not fully working. The cart sub-total is good and take count of the discount but the individual price of each product is not updated and shown as without discount. It's the same on the cart page.
cart (from mini cart)
cart (cart page)
add_action( 'woocommerce_before_calculate_totals', 'alter_price_cart', 9999 );
function alter_price_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// IF CUSTOMER NOT LOGGED IN, DONT APPLY DISCOUNT
//if ( ! wc_current_user_has_role( 'customer' ) ) return;
// LOOP THROUGH CART ITEMS & APPLY 30% DISCOUNT
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$price = $product->get_price();
$cart_item['data']->set_price( $price * 0.7 );
}
}
I'll also have to add the stock availability logic for the mini-cart / cart / checkout page but i'll do that in a second time.
I must have made some mistakes in the loop throught the cart but i cannot catch the issue :( Any idea about how to hook the price of each product and change the displayed value ?
Have a nice day,
Quentin

Get relating order id on product stock change when order placed

I am developing stock status log feature to collect data of all products stock changes. I am using "woocommerce_product_set_stock" hook to write changes to custom database table. One big issue is that I cannot find out how to get related order to stock change when someone has placed a new order. When stock change is based on order cancel/refund I can get the order id from $_SERVER info but when placed a new order via checkout, there's nothing related to order id.
Customer requires order id information on stock change log so any hints, please?
When order cancelled or pending WooCommerce called this wc_reduce_stock_levels and wc_increase_stock_levels function to handle stock quantity.
You can use woocommerce_reduce_order_stock and woocommerce_restore_order_stock to write changes to your custom database table
function update_in_custom_table( $order ){
$order_id = $order->get_id();
$order = wc_get_order( $order_id );
// We need an order, and a store with stock management to continue.
if ( ! $order || 'yes' !== get_option( 'woocommerce_manage_stock' ) ) {
return;
}
// Loop over all items.
foreach ( $order->get_items() as $item ) {
if ( ! $item->is_type( 'line_item' ) ) {
continue;
}
$product = $item->get_product();
if ( ! $product || ! $product->managing_stock() ) {
continue;
}
$stock_quantity = $product->get_stock_quantity();
}
}
add_action( 'woocommerce_reduce_order_stock', 'update_in_custom_table', 10, 1 );
add_action( 'woocommerce_restore_order_stock', 'update_in_custom_table', 10, 1 );

Auto update product custom field based on WooCommerce product stock

I have an ACF field "DeliverySpeed" attached to Products with the values 'Fast' and 'Slow'
I would like to update this field to change to value 'Slow' every time the product stock is zero or less (product on backorder)
I am still learning PHP so far this is what I got to but I am sure different things are missing, I just don't know in which direction to go:
based on acf update field documentation
function automatically_change_delivery( ) {
global $product;
$fieldkey = "DeliverySpeed";
$valueslow = "Slow";
if($product->get_stock_quantity()<0) { update_field( $field_key, $valueslow, $post_id );
} }
Thank you in advance for the attention and advice.
The following code will update automatically your product custom field once order has reduced product stock levels. So when product has stock the custom field value will be 'Fast' otherwise 'Slow'.
The code:
add_action( 'woocommerce_payment_complete', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_completed', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_processing', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
add_action( 'woocommerce_order_status_on-hold', 'update_product_custom_field_after_reduced_stock_levels', 20, 2 );
function update_product_custom_field_( $order_id, $order = '' ) {
// Continue only when order has reduced product stock levels
if ( wc_string_to_bool( get_post_meta( $order_id, '_order_stock_reduced', true ) ) )
return $order_id; // Exit
if( ! $order || ! is_a( $order, 'WC_Order') ) {
$order = wc_get_order( $order_id ); // Get the WC_Order object if it's empty
}
$field_key = 'DeliverySpeed';
// Loop through order items
foreach ( $order->get_items() as $item ) {
$product = $cart_item['data'];
$product_id = $product->get_id();
$stock_qty = $product->get_stock_quantity();
$field_value = get_field( $field_key, $product_id ); // Get ACF field value
if ( $stock_qty <= 0 && $field_value === 'Fast' ) {
update_field( $field_key, 'Slow', $product_id );
}
elseif ( $stock_qty > 0 && $field_value === 'Slow' ) {
update_field( $field_key, 'Fast', $product_id );
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should works.

WooCommerce change price when adding product to order in admin

We have customers who have different discount percentages. This is all programmed and working on the front end when adding products to the cart, but if using the back end order admin to add a new product I can't seem to find a way to calculate the new product price based on the user's discount. Is there a way to change the price in the woocommerce_new_order_item hook when adding a product to an existing order in the order admin?
Here's what I have so far:
function action_woocommerce_new_order_item( $item_id, $item, $order_id ) {
// only run this from the WP admin section
if ( !is_admin() )
return;
$item_type = $item->get_type();
// return if this is not a product (i.e. fee, tax, etc.)
if ( $item_type != 'line_item' )
return;
$product = wc_get_product( $item->get_product_id() );
if ( !$product )
return;
$current_price = $product->get_price();
$quantity = $item->get_quantity();
// here I get the order's user's discount percentage and calculate the new discounted price
// custom function
$discounted_price = get_discounted_price( $current_price, $users_discount );
$new_price = ( !empty($discounted_price) ) ? $discounted_price : $current_price;
// this doesn't work
$item->set_price( $new_price );
// and this doesn't work
$product->set_price( $new_price );
// this appears to work but I'm not sure if this the best way to accomplish this
$item->set_total( $price * $quantity );
}
add_action( 'woocommerce_new_order_item', 'action_woocommerce_new_order_item', 10, 3 );
Any help would be greatly appreciated!
Thanks
This works for adding item meta and changing the item price in the order admin screen:
function action_woocommerce_new_order_item( $item_id, $item, $order_id ) {
// only run this from the WP admin section
if ( !is_admin() )
return;
$item_type = $item->get_type();
// return if this is not a product (i.e. fee, tax, etc.)
if ( $item_type != 'line_item' )
return;
$product = wc_get_product( $item->get_product_id() );
if ( !$product )
return;
$current_price = $product->get_price();
$size = $product->get_attribute('size');
// add custom item meta to order
if ( $size ) {
wc_add_order_item_meta( $item_id, 'Size', $size , false );
}
$order = wc_get_order( $order_id );
$order_user = $order->get_user();
$order_user_id = $order->get_user_id();
// get this order's user's discount %
$users_discount = get_user_meta( $order_user_id, 'discount', true );
$users_discount = ( $users_discount > 0 ) ? $users_discount : 0;
// calculate the discounted price based on the user's discount (custom function)
$discounted_price = get_discounted_price( $current_price, $users_discount );
$quantity = $item->get_quantity();
$new_price = ( !empty($discounted_price) ) ? $discounted_price : $current_price;
$item->set_total( $new_price * $quantity );
};
add_action( 'woocommerce_new_order_item', 'action_woocommerce_new_order_item', 10, 3 );

Resources