Update Product Stock When Variation Stock Changes in WooCommerce - woocommerce

I am trying the update total stock of the product when stock for any variation changes. I want to keep the total stock of all the variations updated.
Here is the code I am using but it's not working. What could be the reason.
add_action( 'woocommerce_product_set_stock', 'wc_get_variable_product_stock_quantity' );
function wc_get_variable_product_stock_quantity( $output = 'raw', $product_id = 0 ){
global $wpdb, $product;
// Get the product ID (can be defined)
$product_id = $product_id > 0 ? $product_id : get_the_id();
// Check and get the instance of the WC_Product Object
$product = is_a( $product, 'WC_Product' ) ? $product : wc_get_product($product_id);
// Only for variable product type
if( $product->is_type('variable') ){
// Get the stock quantity sum of all product variations (children)
$stock_quantity = $wpdb->get_var("
SELECT SUM(pm.meta_value)
FROM {$wpdb->prefix}posts as p
JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type = 'product_variation'
AND p.post_status = 'publish'
AND p.post_parent = '$product_id'
AND pm.meta_key = '_stock'
AND pm.meta_value IS NOT NULL
");
// Preparing formatted output
if ( $stock_quantity > 0 ) {
$html = '<p class="stock in-stock">'. sprintf( __("%s in stock", "woocommerce"), $stock_quantity ).'</p>';
} else {
if ( is_numeric($stock_quantity) )
$html = '<p class="stock out-of-stock">' . __("Out of stock", "woocommerce") . '</p>';
else
$html = '';
}
// Different output options
if( $output == 'echo_html' )
echo $html;
elseif( $output == 'return_html' )
return $html;
else
return $stock_quantity;
set_stock_quantity( $stock_quantity );
}
}

Related

Update Parent Product Quantity When Variation Quantity Changes

I am actually trying to update the stock quantity of parent products whenever the quantity of any of its variation increases or decreases.
What could be the error in following code.
function wc_get_variable_product_stock_quantity( $output = 'raw', $product_id = 0 ){
global $wpdb, $product;
// Get the product ID (can be defined)
$product_id = $product_id > 0 ? $product_id : get_the_id();
// Check and get the instance of the WC_Product Object
$product = is_a( $product, 'WC_Product' ) ? $product : wc_get_product($product_id);
// Only for variable product type
if( $product->is_type('variable') ){
// Get the stock quantity sum of all product variations (children)
$stock_quantity = $wpdb->get_var("
SELECT SUM(pm.meta_value)
FROM {$wpdb->prefix}posts as p
JOIN {$wpdb->prefix}postmeta as pm ON p.ID = pm.post_id
WHERE p.post_type = 'product_variation'
AND p.post_status = 'publish'
AND p.post_parent = '$product_id'
AND pm.meta_key = '_stock'
AND pm.meta_value IS NOT NULL
");
// Preparing formatted output
if ( $stock_quantity > 0 ) {
$html = '<p class="stock in-stock">'. sprintf( __("%s in stock", "woocommerce"), $stock_quantity ).'</p>';
} else {
if ( is_numeric($stock_quantity) )
$html = '<p class="stock out-of-stock">' . __("Out of stock", "woocommerce") . '</p>';
else
$html = '';
}
// Different output options
if( $output == 'echo_html' )
echo $html;
elseif( $output == 'return_html' )
return $html;
else
return $stock_quantity;
}
}

See last order on specific product

Hi how to see last order of specific product in woocommerce?
EXEMPLE:
PRODUCT NAME
PRICE 10 $ [ADD CART]
LAST ORDER
DATE QUT. PRICE
10.10.2021 2 9$
10.12.2021 6 3$
10.01.2022 39 5$
EDIT: I would like to place it on the product page and as a second viewer user sees his latest product orders.
Place the following function in your functions.php file
function latest_order_by_product_id() {
global $wpdb;
// Select Product ID
$product_id = 14;
$orders_statuses = "'wc-completed', 'wc-processing', 'wc-on-hold'";
//Change get_row to get_col if you want all orders
//Change DESC to ASC if we need reverse order
$orders = $wpdb->get_row("
SELECT DISTINCT woi.order_id FROM {$wpdb->prefix}woocommerce_order_itemmeta as woim,
{$wpdb->prefix}woocommerce_order_items as woi,
{$wpdb->prefix}posts as p WHERE woi.order_item_id = woim.order_item_id AND woi.order_id = p.ID
AND p.post_status IN ( $orders_statuses ) AND woim.meta_key IN ( '_product_id', '_variation_id' ) AND woim.meta_value LIKE '$product_id' ORDER BY woi.order_item_id DESC");
if($orders):
$data = array();
foreach($orders as $key => $order_id):
$order = wc_get_order( $order_id );
if ( $order ):
$data[$key]['order_date'] = $order_date = $order->get_date_completed(); // Change depending on type of date you are looking for - get_date_created(), get_date_completed(), get_date_paid()
//Loop order items
foreach ( $order->get_items() as $item_id => $item ):
if($product_id == $item->get_product_id()):
$data[$key]['qty'] = $product_qty = $item->get_quantity();
//Choose which price you want to get
$data[$key]['price'] = $product_price = $item->get_total() + $item->get_total_tax(); // Discounted total with tax
//OR
//$product_price = $item->get_subtotal() + $item->get_subtotal_tax(); // NON discounted total with tax
endif;
endforeach;
endif;
endforeach;
endif;
if($data):
$output = array();
$output[] .='<table><thead><tr><th>LAST ORDER DATE</th><th>QTY</th><th>PRICE</th></tr></theead><tbody>';
foreach($data as $order_data):
//Change date format if needed
$date = $order_data['order_date']->date("d.m.Y");
$output[] .= '<tr><td>'.$date.'</td><td>'.$order_data['qty'].'</td><td>'.$order_data['price'].'</td></tr>';
endforeach;
$output[] .= '</tbody></table>';
endif;
echo sprintf('%s',implode($output));
}
Call latest_order_by_product_id() where you need it. Result - https://prnt.sc/6AhgTPXFerBg
Example with shortcode. How to use [lobpid product_id="35"]
add_shortcode('lobpid','latest_order_by_product_id' );
function latest_order_by_product_id($attr) {
global $wpdb;
$args = shortcode_atts( array(
'product_id' => '',
), $attr );
// Select Product ID
$product_id = $args['product_id'];
//Skip the rest if we dont have product id defined
if(empty($product_id)): echo 'there is no product id defined'; return; endif;
$orders_statuses = "'wc-completed', 'wc-processing', 'wc-on-hold'";
//Change get_row to get_col if you want all orders
//Change DESC to ASC if we need reverse order
$orders = $wpdb->get_row("
SELECT DISTINCT woi.order_id FROM {$wpdb->prefix}woocommerce_order_itemmeta as woim,
{$wpdb->prefix}woocommerce_order_items as woi,
{$wpdb->prefix}posts as p WHERE woi.order_item_id = woim.order_item_id AND woi.order_id = p.ID
AND p.post_status IN ( $orders_statuses ) AND woim.meta_key IN ( '_product_id', '_variation_id' ) AND woim.meta_value LIKE '$product_id' ORDER BY woi.order_item_id DESC");
//Skip the rest if we dont have orders
if(empty($orders)): echo 'no orders found'; return; endif;
if($orders):
$data = array();
foreach($orders as $key => $order_id):
$order = wc_get_order( $order_id );
if ( $order ):
$data[$key]['order_date'] = $order_date = $order->get_date_completed(); // Change depending on type of date you are looking for - get_date_created(), get_date_completed(), get_date_paid()
//Loop order items
foreach ( $order->get_items() as $item_id => $item ):
if($product_id == $item->get_product_id()):
$data[$key]['qty'] = $product_qty = $item->get_quantity();
//Choose which price you want to get
$data[$key]['price'] = $product_price = $item->get_total() + $item->get_total_tax(); // Discounted total with tax
//OR
//$product_price = $item->get_subtotal() + $item->get_subtotal_tax(); // NON discounted total with tax
endif;
endforeach;
endif;
endforeach;
endif;
if($data):
$output = array();
$output[] .='<table><thead><tr><th>LAST ORDER DATE</th><th>QTY</th><th>PRICE</th></tr></theead><tbody>';
foreach($data as $order_data):
//Change date format if needed
$date = $order_data['order_date']->date("d.m.Y");
$output[] .= '<tr><td>'.$date.'</td><td>'.$order_data['qty'].'</td><td>'.$order_data['price'].'</td></tr>';
endforeach;
$output[] .= '</tbody></table>';
endif;
echo sprintf('%s',implode($output));
}

Reflect default price and strikethrough in mini cart item price in WooCommerce

Hello this code creates two discount classes, and then with a filter on the cart page it shows the regular price and the discounted price, how can I do to have the same visual result also on the mini cart??
this is what i am trying to achieve in the minicart
add_action( 'woocommerce_before_calculate_totals', 'bbloomer_quantity_based_pricing', 9999 );
function bbloomer_quantity_based_pricing( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
// Define discount rules and thresholds
$threshold1 = 2; // Change price if items > 100
$discount1 = 0.05; // Reduce unit price by 5%
$threshold2 = 3; // Change price if items > 1000
$discount2 = 0.1; // Reduce unit price by 10%
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item_key => $cart_item )
{
if( has_term( array('cartucce-inkjet'), 'product_cat', $cart_item['product_id'] ) ){
if ( $cart_item['quantity'] >= $threshold1 && $cart_item['quantity'] < $threshold2 )
{
$price = round( $cart_item['data']->get_price() * ( 1 - $discount1 ), 2 );
$cart_item['data']->set_price( $price );
}
elseif ( $cart_item['quantity'] >= $threshold2 )
{
$price = round( $cart_item['data']->get_price() * ( 1 - $discount2 ), 2 );
$cart_item['data']->set_price( $price );
}
}
}
}
function filter_woocommerce_cart_item_price( $price_html, $cart_item, $cart_item_key ) {
// Get the product object
$product = $cart_item['data'];
// Is a WC product
if ( is_a( $product, 'WC_Product' ) ) {
// Get reqular price
$regular_price = $product->get_regular_price();
// New price
$new_price = $cart_item['data']->get_price();
// NOT empty and NOT equal
if ( ! empty ( $regular_price ) && $regular_price != $new_price ) {
// Output
$price_html = '<del>' . wc_price( $regular_price ) . '</del> <ins>' . wc_price( $new_price ) . '</ins>';
}
}
return $price_html;
}
add_filter( 'woocommerce_cart_item_price', 'filter_woocommerce_cart_item_price', 10, 3 );

Exclude user role from sale price in Woocommerce programmatically

the following code: Set product sale price programmatically in WooCommerce 3 works perfectly.
Also its continuation: Set programmatically product sale price and cart item prices in Woocommerce 3.
However I'd like to exclude an user role from this function altogether, how can I do that?
I added the following to the code above to no avail:
if ( ! wc_current_user_has_role( 'trader' ) ) return $product->get_regular_price();
Thanks
After asking around and trying it out, the following code manages to achieve what I need. For future reference if someone else needs it:
// Generating dynamically the product "regular price"
add_filter( 'woocommerce_product_get_regular_price', 'custom_dynamic_regular_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_regular_price', 'custom_dynamic_regular_price', 10, 2 );
function custom_dynamic_regular_price( $regular_price, $product ) {
if( empty($regular_price) || $regular_price == 0 )
return $product->get_price();
else
return $regular_price;
}
// Generating dynamically the product "sale price"
add_filter( 'woocommerce_product_get_sale_price', 'custom_dynamic_sale_price', 10, 2 );
add_filter( 'woocommerce_product_variation_get_sale_price', 'custom_dynamic_sale_price', 10, 2 );
function custom_dynamic_sale_price( $sale_price, $product ) {
$user = wp_get_current_user();
$rate = 0.9;
if( in_array( 'trader', (array) $user->roles ) ) {
return $product->get_regular_price() * $rate;
}
else
{
if( empty($sale_price) || $sale_price == 0 )
return $product->get_regular_price() * $rate;
else
return $sale_price;
}
};
// Displayed formatted regular price + sale price
add_filter( 'woocommerce_get_price_html', 'custom_dynamic_sale_price_html', 20, 2 );
function custom_dynamic_sale_price_html( $price_html, $product ) {
if( $product->is_type('variable') ) return $price_html;
$user = wp_get_current_user();
if( in_array( 'trader', (array) $user->roles ) ) {
$price_html = wc_price($product->get_regular_price() );
return $price_html;
}
else
{
$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();
return $price_html;
}
}
add_action( 'woocommerce_before_calculate_totals', 'set_cart_item_sale_price', 20, 1 );
function set_cart_item_sale_price( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Iterate through each cart item
foreach( $cart->get_cart() as $cart_item ) {
$price = $cart_item['data']->get_sale_price(); // get sale price
$cart_item['data']->set_price( $price ); // Set the sale price
}
}

woocommerce variable product price on dropdown

Hello I m trying to make available the prices for the variations on the dropdown, at some point I were able to achieve it when were only one variable, but now I have two variables for the product but the price on the dropdown is not updating.
Based on Variable product attribute: Customizing each displayed radio buttons text value answer code, here is the code I use to get on the first step, but I need help to update the price of variations up to the second variable selected.
add_filter( 'woocommerce_variation_option_name', 'display_price_in_variation_option_name' );
function display_price_in_variation_option_name( $term ) {
global $wpdb, $product;
if ( empty( $term ) ) return $term;
if ( empty( $product->id ) ) return $term;
$id = $product->get_id();
$result = $wpdb->get_col( "SELECT slug FROM {$wpdb->prefix}terms WHERE name = '$term'" );
$term_slug = ( !empty( $result ) ) ? $result[0] : $term;
$query = "SELECT postmeta.post_id AS product_id
FROM {$wpdb->prefix}postmeta AS postmeta
LEFT JOIN {$wpdb->prefix}posts AS products ON ( products.ID = postmeta.post_id )
WHERE postmeta.meta_key LIKE 'attribute_%'
AND postmeta.meta_key != 'attribute_pa_alto'
AND postmeta.meta_value = '$term_slug'
AND products.post_parent = $id";
$variation_id = $wpdb->get_col( $query );
$parent = wp_get_post_parent_id( $variation_id[0] );
if ( $parent > 0 ) {
$_product = new WC_Product_Variation( $variation_id[0] );
//EDITADO PARA MOSTRAR CUANDO NO HAY STOCK MUESTRA AGOTADO
if($_product->managing_stock() && $_product->get_stock_quantity() < 1){
return $term . ' - AGOTADO';
}else{
return $term . ' - (' . wp_kses( woocommerce_price( $_product->get_price() ), array() ) . ')';
}
}
return $term;
}

Resources