Replace woocommerce_add_order_item_meta hook in Woocommerce 3.4 - php

I have custom code use woocommerce_add_order_item_meta hook. But woocommerce 3.4.0 show error log: "woocommerce_add_order_item_meta is deprecated since version 3.0.0! Use woocommerce_new_order_item instead."
How to fix it? Thank you very much. My code:
// add data design to order
function tshirt_order_meta_handler( $item_id, $values, $cart_item_key ) {
if( WC()->session->__isset( $cart_item_key.'_designer' ) ) {
wc_add_order_item_meta( $item_id, "custom_designer", WC()->session->get( $cart_item_key.'_designer') );
}
}
add_action( 'woocommerce_add_order_item_meta', 'tshirt_order_meta_handler', 1, 3 );

Updated
Since Woocommerce version 3, woocommerce_checkout_create_order_line_item action hook now replace outdated woocommerce_add_order_item_meta hook in a much better way using the new introduced CRUD getters and setters methods:
// Save custom data to order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'tshirt_order_meta_handler', 20, 4 );
function tshirt_order_meta_handler( $item, $cart_item_key, $values, $order ) {
$custom_designer = WC()->session->get( $cart_item_key.'_designer' );
if( ! empty($custom_designer) ) {
$item->update_meta_data( 'custom_designer', $custom_designer );
}
}
Code goes in function.php file of your active child theme (or active theme). It should works.
See this related thread:
Woocommerce: Which hook to replace deprecated "woocommerce_add_order_item_meta"

Related

Disallow backorders product option globally (in admin too) on WooCommerce

I have a question about how to disable backorders in WooCommerce globally. I found this here:
How to disable globally backorders in WooCommerce
https://wordpress.stackexchange.com/questions/334083/woocommerce-is-it-possible-to-overide-the-settings-for-allowing-to-purchase-out
I use now add_filter( 'woocommerce_product_backorders_allowed', '__return_false' );. But is is still possible to set that option to allowed. So my question is, if I set a product to "Backorder allowed" and this snipped is active. After save the product "Backorder allowed" is visible. But is that only a display thing and in the back Backorder are not possible even if "allowed" is selected?
It would be nice, if there is no way to change that setting. Maybe gray-out that option in the edit product overview?
Is something possible?
Cheers
You can use the following to disable backorder settings on admin product single pages (that handle product variations too):
add_action( 'admin_footer', 'disable_backorder_option_from_product_settings' );
function disable_backorder_option_from_product_settings() {
global $pagenow, $post_type;
if( in_array( $pagenow, array('post-new.php', 'post.php') ) && $post_type === 'product' ) :
?>
<script>
jQuery(function($){
// For product variations
$('#variable_product_options').on('change', function(){
$('select[name^=variable_backorders]').each( function(){
$(this).prop('disabled','disabled').val('no');
});
});
// For all other product types
$('select#_backorders').prop('disabled','disabled').val('no');
});
</script>
<?php
endif;
}
For frontend, you will use additionally (if there are still some older products with backorder option enabled):
add_filter( 'woocommerce_product_backorders_allowed', '__return_false', 1000 );
add_filter( 'woocommerce_product_backorders_require_notification', '__return_false', 1000 );
add_filter( 'woocommerce_product_get_backorders', 'get_backorders_return_no' );
add_filter( 'woocommerce_product_variation_get_backorders', 'get_backorders_return_no' );
function get_backorders_return_no( $backorders ){
return 'no';
}
add_filter( 'woocommerce_product_get_stock_status', 'filter_product_stock_status', 10, 2 );
add_filter( 'woocommerce_product_variation_get_stock_status', 'filter_product_stock_status', 10, 2 );
function filter_product_stock_status( $stock_status, $product ){
return $product->get_manage_stock() && $product->get_stock_quantity() <= 0 ? 'outofstock' : $stock_status;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.

Setting a tax class based on specific coupon in Woocommerce

This has been answered a while back but the filter is not working anymore. Not sure if it is deprecated or not. I am using both filters:
woocommerce_product_tax_class
woocommerce_product_get_tax_class
My function looks like:
function wc_diff_rate_for_user( $tax_class, $product ) {
$tax_class = "Zero rate";
return $tax_class;
}
add_filter( 'woocommerce_product_tax_class', 'wc_diff_rate_for_user', 1, 2 );
How can I set a tax class based on specific coupon in Woocommerce?
Since Woocommerce 3, the filter hook woocommerce_product_tax_class doesn't exist anymore, only new woocommerce_product_get_tax_class composite filter hook is available and works.
There is multiple ways to set a tax class based on an applied coupon code (In both examples below, we set "Zero rate" tax class when a defined coupon code is applied):
1) Using woocommerce_before_calculate_totals action hook, the best way:
add_action( 'woocommerce_before_calculate_totals', 'change_tax_class_based_on_specific_coupon', 25, 1 );
function change_tax_class_based_on_specific_coupon( $cart ) {
// Define your coupon code below
if ( ! $cart->has_discount('summer') )
return;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach( $cart->get_cart() as $cart_item ){
// We set "Zero rate" tax class
$cart_item['data']->set_tax_class("Zero rate");
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
2) Using woocommerce_product_get_tax_class filter hook:
add_filter( 'woocommerce_product_get_tax_class', 'change_tax_class_based_on_specific_coupon', 30, 2 );
function change_tax_class_based_on_specific_coupon( $tax_class, $product ) {
// Define your coupon code below
if( WC()->cart->has_discount('summer') )
$tax_class = "Zero rate";
return $tax_class;
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.

Only one currently added product into Woocommerce cart?

I would like Woocommerce to only allow 1 product in the cart. If a product is already in the cart and another one is added then it should remove the previous one.
I found this code on net:
/**
* When an item is added to the cart, remove other products
*/
function custom_maybe_empty_cart( $valid, $product_id, $quantity ) {
if( ! empty ( WC()->cart->get_cart() ) && $valid ){
WC()->cart->empty_cart();
wc_add_notice( 'Only allowed 1 item in cart, please remove previous
item.', 'error' ); // here instead popup notice need to remove prevous added product
}
return $valid;
}
add_filter( 'woocommerce_add_to_cart_validation', 'custom_maybe_empty_cart',
10, 3 );
But it seems that is not working as I wanted. It need to autoremove previously added product in cart, and add latest added product in cart. Can someone to give me tip what need to update on class to work in latest woo 3.3.X ?
This one is the more compact and actual code as global $woocommerce is not needed anymore:
add_filter( 'woocommerce_add_to_cart_validation', 'auto_empty_cart', 20, 3 );
function auto_empty_cart( $passed, $product_id, $quantity ) {
if( WC()->cart->is_empty() ) return $passed; // Exit
WC()->cart->empty_cart();
return $passed;
}
Code goes in function.php file of your active child theme (or active theme).
Tested and works in all Woocommerce versions since 2.6.x
This working perfecty on Woocommerce 3.3.X
add_filter( 'woocommerce_add_to_cart_validation',
'bbloomer_only_one_in_cart', 99, 2 );
function bbloomer_only_one_in_cart( $passed, $added_product_id ) {
global $woocommerce;
// empty cart: new item will replace previous
$woocommerce->cart->empty_cart();
// display a message if you like
wc_add_notice( 'Product added to cart!', 'notice' );
return $passed;
}

Woocommerce disable automatic order status change pending->processing

I want to dissable this option:
Whenever someone makes and order on my site and the payment is successfull the order status automaticaly changes from pending to processing.
However I don`t want this feature to have enabled. Rather I want to do it manually when i proces the orders.
I found this function in the woocommerce which is making this feature possible. I don`t want to directly change it there but rather with some kind of php snippet which overrides this function.
Here is the function which i need to change : http://woocommerce.wp-a2z.org/oik_api/wc_orderpayment_complete/
PS: I just having a hard time to do it correctly.
Update
May be this payment_complete() is not involved in the process you are looking for. Alternatively, what you could try is the woocommerce_thankyou action hook instead:
add_action( 'woocommerce_thankyou', 'thankyou_order_status', 10, 1 );
function thankyou_order_status( $order_id ){
if( ! $order_id ) return;
$order = new WC_Order( $order_id ); // Get an instance of the WC_Order object
if ( $order->has_status( 'processing' ) )
$order-> update_status( 'pending' )
}
You can use the same alternative hook: woocommerce_thankyou_{$order->get_payment_method()} (replacing $order->get_payment_method() by the payment method ID slug)
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works.
Using a custom function hooked in woocommerce_valid_order_statuses_for_payment_complete filter hook, where you will return the desired orders statuses that can be taken by the related function payment_complete() which is responsible of auto change the order status.
By default the array of order statuses in the filter is:
array( 'on-hold', 'pending', 'failed', 'cancelled' ).
And we can remove 'on-hold' order status this way:
add_filter( 'woocommerce_payment_complete_order_status', 'disable_auto_order_status', 10, 2 );
function disable_auto_order_status( $order_statuses, $order ) {
$return array( 'pending', 'failed', 'cancelled' );
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works.
Add the following code to your functions.php file.function
ja_order_status( $order_status, $order_id ) {
$order = new WC_Order( $order_id );
if ( 'processing' == $order_status ) {
return 'pending';
}
return $order_status;
}
add_filter( 'woocommerce_payment_complete_order_status', 'ja_order_status', 10, 2 );
Tested on WooCommerce with Storefront paid via Stripe test mode.

Woocommerce: Which hook to replace deprecated "woocommerce_add_order_item_meta"

Need to add custom meta to order items. Googled it and most articles says to use "woocommerce_add_order_item_meta" hook. This hook is deprecated in the newest version 2.3.7. Someone, please tell me which hook to use instead.
http://docs.woothemes.com/wc-apidocs/function-woocommerce_add_order_item_meta.html
2017/2018 THE RIGHT WAY (Using new CRUD setters and Getters methods)
Related: Replace woocommerce_add_order_item_meta hook in Woocommerce 3.4
Since woocommerce 3 that has improved many things making drastic changes, the action hook woocommerce_add_order_item_meta still work perfectly even in woocommerce version 3.3+.
This hook is enabled by WC_Checkout class methods and related functions in the checkout process and not in WC_Order Class where cart data is not anymore available.
Now as Woocommmerce 3 has introduced new CRUD setters and getters methods, the similar replacement hook to be used is woocommerce_checkout_create_order_line_item that has similar useful arguments as cart data.
The woocommerce_new_order_item is really NOT convenient as cart data is not accessible.
Let see how to work with woocommerce_checkout_create_order_line_item. It has 4 available arguments:
$item is an instance of WC_Order_Item_Product new introduced Class
$cart_item_key is the cart item unique hash key
$values is the cart item
$order an instance of the WC_Order object (This is a very useful additional argument in some specific cases)
In this hook we will replace the old working functions wc_add_order_item_meta() by the new WC_Data update_meta_data() method to be used with $item argument.
Example:
## --- New way --- ##
add_action( 'woocommerce_checkout_create_order_line_item', 'custom_checkout_create_order_line_item', 20, 4 );
function custom_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
// Get a product custom field value
$custom_field_value = get_post_meta( $item->get_product_id(), '_meta_key', true );
// Update order item meta
if ( ! empty( $custom_field_value ) ){
$item->update_meta_data( 'meta_key1', $custom_field_value );
}
// … … Or … …
// Get cart item custom data and update order item meta
if( isset( $values['custom_data'] ) ) {
$item->update_meta_data( 'meta_key2', $values['custom_data'] );
}
}
Finally we can do the same with old way using woocommerce_add_order_item_meta hook as it has nearly the same useful arguments:
## --- Old way --- ##
add_action( 'woocommerce_add_order_item_meta', 'custom_add_order_item_meta', 20, 3 );
function custom_add_order_item_meta( $item_id, $values, $cart_item_key ) {
// Get a product custom field value
$custom_field_value = get_post_meta( $values['data']->get_id(), '_meta_key', true );
// Update order item meta
if ( ! empty( $custom_field_value ) ){
wc_add_order_item_meta( $item_id, 'meta_key1', $custom_field_value );
}
// … … Or … …
// Get cart item custom data and update order item meta
if( isset( $values['custom_data'] ) ) {
wc_add_order_item_meta( $item_id, 'meta_key2', $values['custom_data'] );
}
}
Conclusion: woocommerce_checkout_create_order_line_item is the right replacement hook to be used with WooCommerce 3+ and that new CRUD setters and getters methods.
If you look at wc-deprecated-functions.php you will see
/**
* #deprecated
*/
function woocommerce_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
return wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique );
}
Basically, the function was renamed to wc_add_order_item_meta(), so if you need the function then use that. The action hook was not renamed and remains in class-wc-checkout.php as:
// Allow plugins to add order item meta
do_action( 'woocommerce_add_order_item_meta', $item_id, $values, $cart_item_key );
It seems that the hook is now also deprecated as of version 3.0.4.
I'm getting this notification:
The The "woocommerce_add_order_item_meta" hook uses out of date data structures and function is deprecated since version 3.0.4. Replace with woocommerce_new_order_item.
I have replaced the action name 'woocommerce_add_order_item_meta' with 'woocommerce_new_order_item' in an add_action statement in an offending plugin, and the deprecation notification disappears, The problem is that some parameters now appear inside a legacy_values array. I use the plugin YITH WooCommerce Product Add Ons, and the product meta data that should be attached to an order is not picked up by the plugin and therefore not stored with the order. So until this is fixed in the plugin you have to live with the deprecation notification.
I know this has been answered and there is an accepted reply already. I just wanted to give another way to handle this without actually getting a deprecated message (see reference);
add_action('woocommerce_new_order_item', 'saveMetaData', 10, 3); // or use just 2 instead of 3; if you don't need order id
/**
* Add meta to order item
*
* #param int $itemId
* #param WC_Order_Item_Product|WC_Order_Item_Shipping $item
* #param int #orderId
*/
function saveMetaData($itemId, $item, $orderId)
{
if (!isItemValid($item))
{
return;
}
wc_add_order_item_meta($itemId, 'my_custom_data', $item->legacy_values['my_custom_data']);
}
/**
* #param WC_Order_Item_Product|WC_Order_Item_Shipping $item
*
* #return bool
*/
function isItemValid($item)
{
return (
$item instanceof WC_Order_Item_Product &&
isset($item->legacy_values) &&
isset($item->legacy_values['my_custom_data']) &&
!empty($item->legacy_values['my_custom_data'])
);
}
Your specific use case isn't very clear (you didn't specify when or where you need to add this meta info), but you can use woocommerce_checkout_update_order_meta during checkout.
Read more in customizing checkout fields.
No it seems like the hook is also deprecated:
PHP Error:
The "woocommerce_add_order_item_meta" hook uses out of date data structures and function is deprecated since version 3.1.2. Replace with woocommerce_new_order_item.
I also cannot find it here:
https://docs.woocommerce.com/wc-apidocs/hook-docs.html
I wanted to add on to Ilgıt Yıldırım's answer: in my case, my custom values did not exist in the item->legacy_values array. To fix this, I used the woocommerce_checkout_create_order_line_item hook to add the custom values to the item prior to calling the woocommerce_new_order_item hook. Here is an example of that:
add_action( 'woocommerce_checkout_create_order_line_item', 'save_values_in_item', PHP_INT_MAX, 4 );
function save_values_in_item( $item, $cart_item_key, $values, $order ) {
$item->myCustomValues = $values;
}
//THEN call the new hook:
add_action( 'woocommerce_new_order_item', 'add_product_input_fields_to_order_item_meta_wc3', PHP_INT_MAX, 3 );
function add_product_input_fields_to_order_item_meta_wc3( $item_id, $item, $order_id ) {
if ( isset( $item->myCustomValues ) )
{
//iterate through array and place desired values into the meta data using the wc_add_order_item_meta function
}
}
Just to make things clear, this function was deprecated, but the hook is still ok

Categories