WooCommerce: updating order - woocommerce

I am trying to run some code everytime after the order is updated using 'woocommerce_update_order' action hook as you can see below:
add_action( 'woocommerce_update_order', 'update_order' );
After some time spent on developing 'update_order' function I realized that it is not called only once as I supposed but it is called multiple times.
So for testing I rewrite 'update order' function as you can see below:
function update_order( $order_id ) {
$order = wc_get_order( $order_id );
$current_count = get_post_meta( $order_id, '_edit_sale_count', true );
$new_count = 1;
if( $current_count ) $new_count = $current_count + 1;
$order->update_meta_data( '_edit_sale_count', $new_count );
$order->save();
}
After updating a single order and checking database, I realized that function 'update_order' is called 1500 times...
So my question is why is this the case? And how I can prevent multiple times execution on single update and force it to run once only?
Thanks

Related

WooCommerce function that disables an admin user to reduce the product stock quantity

I would like to add a function that is triggered every time that the stock quantity of a product will be changed in the admin product page, such that this function will not allow any reduce of the stock value - but only increase.
This is to prevent an admin user to reduce the stock quantity of the products.
Of course, this function should not be triggered if a product will be in an order, since then of course I would like the stock quantity to be reduced.
I tried the following function in the functions.php but unfortunately did not work.
Since I'm new to woocommerce and php, any ideas that could provide a solid solution to the problem?
// get old and new product stock quantity
function get_old_and_new_product_quantity_stock( $sql, $product_id_with_stock, $new_stock, $operation ) {
$product = wc_get_product( $product_id_with_stock );
$old_stock_quantity = $product->get_stock_quantity();
$new_stock_quantity = $new_stock;
echo $old_stock_quantity, $new_stock_quantity;
if ($new_stock_quantity < $old_stock_quantity) {
$new_stock = $old_stock_quantity;
$new_stock_quantity = $old_stock_quantity;
}
return $sql;
}
add_filter( 'woocommerce_update_product_stock_query', 'get_old_and_new_product_quantity_stock', 10, 4 );
You can use the update_post_meta action hook to check if the new value is less than the previous value and display error message.
This will work for quick edit and for product edit page. But the wp_die on product page will look bad so use the javascript to prevent submitting on product edit page (there was another question about it yesterday)
Be sure to test this snippet and create some orders that will reduce the stock automatically. I added is_admin() check but please do a good test.
add_action( 'update_post_meta', 'prevent_reducing_stock_metadata', 10, 4 );
function prevent_reducing_stock_metadata( $meta_id, $post_id, $meta_key, $meta_value ) {
// Check if the meta key is _stock and the new value is less than the previous value
if ( '_stock' == $meta_key && $meta_value < get_post_meta( $post_id, '_stock', true ) ) {
// Check if this is an update from the WordPress admin area
if ( is_admin() ) {
wp_die( __( 'Error: You cannot reduce the stock level for this product.' ), 'error' );
}
}
}

Custom field value set to permalink only on new post, But they change it every time it's updated

I want to set the permalink slug using the custom field value for the first save only, but it is not working.
The code below changes the slug not only for the first save, but also for every update.
function custom_slug_auto_setting( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
return $_POST['custom_field_title'];
}
add_filter( 'wp_unique_post_slug', 'custom_slug_auto_setting', 10, 6 );
For the second and subsequent saves, I want to keep the slug set for the first save.
I tried using the filter hook for wp_insert_post to specify post_name only for the first save, but that didn't work well either.
Is there any good solution?
Thank you.
save_post or save_post_{$post->post_type} Fires once a post has been saved. The dynamic portion of the hook name, {$post->post_type}, refers to the post type slug.
We need to discard any updates autosave or revision actions. The WordPress autosave system fire every 60 seconds.
#See https://wordpress.org/support/article/revisions/
The $update parameter is supposed to determined whether this is an existing post being updated. It applies more specifically to a post autosave revision. The $update parameter will always be true when firing through wp_publish_post. But that isn't true for its usage in wp_insert_post (See the following wordpress stackexchange answer and comments for more details...).
#See https://wordpress.stackexchange.com/a/185991/190376
In our case, the wp_publish_post function publish a post by transitioning the post status.
#See https://developer.wordpress.org/reference/functions/wp_publish_post/
By additionally crosschecking the post status we can effectively determine whether it is indeed a non-existing post.
If you are calling a function such as wp_update_post that includes the save_post hook, your hooked function will create an infinite loop. To avoid this, unhook your function before calling the function you need, then re-hook it afterward.
#See https://developer.wordpress.org/reference/hooks/save_post/#avoiding-infinite-loops
save_post will fire on post Update (eg: Autosave) or Publish which is why we're runing into an infinite loop.
#See https://wordpress.stackexchange.com/a/19539/190376
<?php
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
if ( ! function_exists( 'wpso74121743' ) ) {
function wpso74121743( $post_id, $post, $update ) {
if ( ! wp_is_post_autosave( $post_id ) && ! wp_is_post_revision( $post_id ) && ! $update && $post->post_status == 'auto-draft' ) {
$override_post_name = sanitize_title( get_post_custom_values( 'custom_field_title', $post_id ), get_the_title( $post_id ) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
wp_update_post( array(
'ID' => $post_id,
'post_name' => $self,
) );
add_action( 'save_post', 'wpso74121743', 10, 3 ); //can be replaced by save_post_{$post->post_type}
};
};
};

How to use calculation function after database update on Woocommerce?

I am making changes to some data after the order. Transactions are taking place in the database. There is no problem. But the problem is recalculating the order amount.
If I run the relevant function (calculate_totals) elsewhere, the calculation takes place. But it is not happening in example_function. There are no errors in the code. It works without problems.
My code is as follows:
//...
add_action( 'template_redirect', [ $this, 'example_function' ], 10 );
//...
function example_function() {
foreach ($order->get_items() as $item_id => $item) {
wc_update_order_item_meta( $item_id, '_line_tax', $new_value1));
wc_update_order_item_meta( $item_id, '_line_total',$value2));
//...
}
//Save and finish
$order->calculate_totals();
$order->save();
wc_add_notice( __( 'Successful', 'text-domain' ), 'success' );
wp_redirect( wc_get_account_endpoint_url( 'new-page' ) );
exit();
}
For example, then, calculation occurs later with a definition like the following.
add_action( 'woocommerce_view_order', 'example_view_order', 20 );
function example_view_order($order_id){
$order = wc_get_order($order_id);
//Save and finish
$order->calculate_totals();
}
Update:
A few hours later I found a thread like this: StackOverLink
I guess the order_item_meta functions are running asynchronously. Probably the problem is caused by that. However, a solution has not been found.

Issue adding date created to order number when creating order manually in WooCommerce

I use the following code to modify the order number in WooCommerce.
add_filter( 'woocommerce_order_number', 'change_woocommerce_order_number', 1, 2);
function change_woocommerce_order_number( $order_id, $order ) {
$prefix = '160-';
// you will need to get your city as a variable to pass in to priffix
$order = wc_get_order( $order_id );
$order_date = $order->get_date_created();
$date_created = $order_date->date( 'Ymd' );
// You can use either one of $order->id (or) $order_id
// Both will wor
return $prefix . $order->id . '-'.$date_created;
}
This code works during the checkout process but I get an error like this when i manually create an order in WooCommerce backend.
How can I prevent this?
Your code contains some mistakes
The use $order = wc_get_order( $order_id );is not necessary, as $order already passed to the function
$order->id has been replaced since WooCommerce 3 (2017) with $order->get_id()
However, using/replacing $order->get_id() is not needed in this answer, as this is also passed to the function
The error will not occur when you place an order, but will occur when you want to create a new order in the backend (which is the case for you). Simply because the order has yet to be created, and that value does not yet exist
So you get
function filter_woocommerce_order_number( $order_number, $order ) {
// Prefix
$prefix = '160-';
// Is null
if ( is_null( $order->get_date_created() ) ) {
$order->set_date_created( new WC_DateTime() );
}
// Get date created
$date_created = $order->get_date_created()->date( 'Ymd' );
return $prefix . $order_number . '-' . $date_created;
}
add_filter( 'woocommerce_order_number', 'filter_woocommerce_order_number', 10, 2 );
Try this code.
Replace this lines.
$order_date = $order->get_date_created();
$date_created = $order_date->date( 'Ymd' );
To
$date_created = $order->get_date_created()->date('Ymd');

Set every new order with woocommerce on hold

For a specific woocommerce project, I need to set every new order on hold.
It needs to go through that before processing payment.
Do you guys know a hook to do that? I tried many different things, that didn't work.
add_action( 'woocommerce_thankyou', 'custom_woocommerce_auto_complete_order' );
function custom_woocommerce_auto_complete_order( $order_id ) {
global $woocommerce;
if ( !$order_id )
return;
$order = new WC_Order( $order_id );
$order->update_status( 'on-hold' );
}
This is the standard way of doing it. Not sure if it still works with 2.2, but you didn't specify your WooCommerce version.

Resources