WooCommerce: hook for admin edited orders - php

Good morning. I have a single custom function which should be triggered when:
an order is created or modified from frontend
an order is created or modified from backend (admin mode), in any way: refunds, products added or removed, coupon applied, order notes inserted, order action changed, etc.
In the 1st case I'm using add_action('woocommerce_checkout_order_processed', 'calcolo_corrispettivi', 10, 1). Works fine.
In the 2nd case I've tried using add_action('save_post', 'calcolo_corrispettivi', 10, 1). It crashes when triggered by non "order" type posts.
Full code:
add_action('woocommerce_checkout_order_processed', 'calcolo_corrispettivi', 10, 1);
add_action('save_post', 'calcolo_corrispettivi', 10, 1);
// Not enough for all possible 'edit' actions:
// add_action('woocommerce_order_refunded', 'calcolo_corrispettivi', 10, 1);
function calcolo_corrispettivi ( $order_id ) {
$order = wc_get_order( $order_id );
$order_refunds = $order->get_refunds();
$totale_EP = 0;
$totale_altri = 0;
foreach ( $order->get_items() as $item_id => $item) {
$prodotto = $item->get_product();
$editrice = $prodotto->get_attribute('pa_casa-editrice');
if ($editrice == "EP") {
$totale_EP = $totale_EP + $item->get_subtotal() - $order->get_total_refunded_for_item( $item_id );
}
else {
$totale_altri = $totale_altri + $item->get_subtotal() - $order->get_total_refunded_for_item( $item_id );
}
}
update_post_meta($order_id, 'totale_EP', $totale_EP);
update_post_meta($order_id, 'totale_altri', $totale_altri);
}
Is there any specific woocommerce hook for admin updated orders?
Thank you.
Update. I've also tried using woocommerce_process_shop_order_meta, as suggested below, following this question. The solution works only if I press "Update" button under "Order action":
Admin order edit page - Update button
But, for instance, if I change the quantity of a product, the order gets updated without pressing the "Update" button, and so without running my custom function:
Admin order edit page - Update single product quantity
Solution. These hooks worked for me:
Order modified by admin on backend page: woocommerce_saved_order_items (as shown here)
Note added: woocommerce_order_note_added
Refund: woocommerce_order_refunded

Related

Show extra sections on a product page ONLY to users who already purchased that product (Elementor, Crocoblock, JetEngine)

I have a website with few WooCommerce products, and the product page is created with Elementor Pro. I want users to be able to click Add to Cart and buy the product normally.
But then when the user goes back to the product page (after buying the product), they would not see the the Add to Cart button (if will be hidden for those that purchased the product) and they will see another extra section.
How can I do this?
I also have Crocoblock and JetEngine that have a Dynamic Visibility functionality built in Elementor.
The easiest way to achieve this would be by creating a child theme. The child theme should contain 2 added functionalities.
For this to fully work you will need all users to be registered and NOT have checkout as a guest enabled. Also, this will only work for new orders. If you want to add compatibility for old orders you'd have to create a script that sets the meta value for all users that have purchased this product before the code was implemented.
First of we create a function that adds metadata to the purchasing user account if the product was in the cart. Add the following code to your child theme functions.php
add_action( 'woocommerce_thankyou', 'custom_add_user_meta');
function custom_add_user_meta( $order_id ){
$user_id = get_current_user_id();
$order = wc_get_order( $order_id );
$items = $order->get_items();
foreach ( $items as $item_id => $item ) {
$product_id = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();
if ( $product_id == 12345 ) {
add_user_meta( $user_id, '_product_xyz_purchased', "true");
}
}
}
Now we add the following code to the same functions.php file to render additional content on the single product page of WooCommerce. NOTE: This step is for a more complete overview that can be implemented outside of Crocoblocks/Jetegine. The following step can be skipped because Jetengine allows setting conditions based on user_meta
add_action("woocommerce_after_single_product", 'render_additional_content', 50);
function render_additional_content() {
$user_id = get_current_user_id();
$product_purchased = get_user_meta( $user_id, '_product_xyz_purchased', true);
if($product_purchased == "true"){
echo "here you can put the HTML you want to display";
}
}

Hook woocommerce_checkout_order_processed order items issue

I am working on a WooCommerce project. I need to add some entry based on ordered item in my custom table. If user ordered 3 items then those 3 entry will be place along with some data in my custom table.
For that I used woocommerce_checkout_order_processed hook. But I faced some issue, that if user adds 4 items in cart and on checkout page if user removed all items except one and finally ordered just 1 item then also in this hook I am getting all 4 items. I am not getting final ordered item in this hook.
So I changed the hook to woocommerce_thankyou . But in some case due to some reason user did not come on thank you page or on some credit card payment this hook did not work.
So can anyone tell me the best hook which can run after order place no matter if payment done or not and also I should get only ordered items. My WooCommerce version is 3+
Code :
function wc_function($order_id) {
global $wpdb;
$order = new WC_Order($order_id);
$items = $order->get_items();
foreach ($items as $item_line_id => $item) {
// Insert data in my custom table
}
}
//add_action('woocommerce_checkout_order_processed','wc_function', 10, 3);
//add_action('woocommerce_thankyou', 'wc_function', 10, 1);
Thank you !
do_action on woocommerce_checkout_order_processed passes exactly three args, third of which is the $order itself. So try using that instead:
function wc_function($order_id, $posted_data, $order) {
$items = $order->get_items();
foreach ($items as $item_line_id => $item) {
// Insert data in my custom table
}
}
add_action( 'woocommerce_checkout_order_processed', 'getswift_delivery_thankyou', 10, 1 );
add_action( 'woocommerce_thankyou', 'getswift_delivery_thankyou', 10, 1 );
You may use this hook it's working on my side... if you have any problems then discuss me we will solve them

Change payment gateway option based on cart total in Woocommerce checkout

For my woocommerce shop, i have this filter in functions.php. It force 3DS with "woocommerce Stripe Gateway" plugin.
add_filter('wc_stripe_require_3ds','__return_true');
It work great.
I would like this filter to be active only for order over 50€.
I tried with this but it doesn't work, the order is validated without 3DS.
$minsecure = 50;
$order = new WC_Order( $order_id );
$total = $order->get_total();
if($total>$minsecure) {
add_filter('wc_stripe_require_3ds','__return_true');
}
I also try to get the cart amount instead of the order amount, but I don't know which one to get for the filter to be active between the time of the "order" click and the confirmation page.
Any help is appreciated.
I would go for this to check if the price of the order is over 50
if( WC()->cart->subtotal > 50 )
So the snippet would look like
add_action('woocommerce_cart_updated', 'wc_stripe_require_3ds', 90);
function wc_stripe_require_3ds ( $cart ){
if( WC()->cart->subtotal > 50 ) {
add_filter('wc_stripe_require_3ds','__return_true');
}
}
Have a try.

Woocommerce custom add to cart button with custom checkout page

I have a Woocommerce store, I was looking to add another add to cart button named "Try now" to a particular category(not to all the categories). When the user clicks on "try now", it gets redirected to the custom checkout page.
On custom checkout page, try-now products can be added up-to 5 products max, total is fixed as 500 for all the try now products and payment only by card.
I have found the following codes.
Code to replace add to cart button
function remove_loop_button(){
if (in_array( 10, $product->category_ids))
remove_action(‘woocommerce_after_shop_loop_item’,‘woocommerce_template_loop_add_to_cart’, 10);
}
add_action(‘init’,’remove_loop_button’);
add_action(‘woocommerce_after_shop_loop_item’,’replace_add_to_cart’);
function replace_add_to_cart() {
global $product;
$link = $product->get_permalink();
echo ‘<a href=”‘.esc_attr($link).'”>Try Now</a>’;
}
And also this code to customize checkout page from Make 2 different WooCommerce checkout pages?
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
function custom_override_checkout_fields( $fields ) {
global $woocommerce;
//assuming only one product in cart
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
}
switch ($_product->id) {
case '666': //product id for product 1
//do stuff with the checkout fields
break;
case '999': //product id for product 2
//do stuff with the checkout fields
break;
}
return $fields;
}
I know it's quite complicated, Can any one please suggest me where to start? Or any hint will be appreciated. Thanks.

Woocommerce after product update get stock

I have a problem with adding action to 'save_post_product' hook.
I want to send stock data to my external API when product is changed(updated) in woocommerce admin.
The problem is that the stock values i get from simple product after the action is called are one 'iteration' old. By that i mean that the stock data i get seem to be the data before update. so if i call the update product 2 times, first time i get old data, second time i get the new ones.
add_action('save_post_product', array($this, 'product_changed'), 99, 3);
function product_changed($post_id, $post, $update)
{
if ('product' != $post->post_type || $update != true) {
return;
}
$_pf = new WC_Product_Factory();
$product = $_pf->get_product($post_id);
$items = array();
if ($product->product_type == 'simple') {
$product->get_total_stock();
$inStock = $product->is_in_stock();
$qty = $product->get_stock_quantity();
$managing = $product->managing_stock();
$items[$product->id] = [
...
];
} elseif ($product->product_type == 'variable') {
$variations = $product->get_available_variations();
/*For variations it works properly*/
}
}
$itemsJson = json_encode($items);
$this->sendData($itemsJson, '/products-changed/');
}
TLDR (example):
Lets say that product is set to manage stock, stock quantity 500 and is in stock.
Now i change the product not to manage stock, and set that it is out of stock.
I hit update.
Everything runs and wordpress gets to my code. When i get the values i still get
$product->is_in_stock(); //true
$product->get_stock_quantity(); //500
$product->managing_stock(); //yes
Now, when i hit the update again, everything runs the second time, but now i get the correct values.
$product->is_in_stock(); //false
$product->get_stock_quantity(); //0
$product->managing_stock(); //no
I assume that the product stock update runs after 'save_post_product' hook however, i was not able to find any other hook that might solve my problem.
NOTE: It works well with variations in the first 'iteration'. I think it has to do something with the $product->get_available_variations() code.
Seems like hooking the action to wp_insert_post hook did the trick :
add_action('wp_insert_post', array($this, 'product_changed'), 99, 3);
save_post is triggered BEFORE the update. So you would have to use the $_POST, $_GET or the global $post_data, as specified in https://codex.wordpress.org/Plugin_API/Action_Reference/save_post
You already resolved this by using wp_insert_post, so that's okay. Just a clarification for any one seeing this

Categories