I am programmatically adding a product to the cart. Besides this, somehow, I want to store some extra info (an array) to the order. When the client finishes the order, I want to access that info through some WordPress actions. I'll have to do this immediately after adding the product to the cart, because the info may change after that, if the user doesn't finish the order right away. Is there any way I can do it, without putting the database to work?
You should probably use the WooCommerce Cart Item Meta API and the WooCommerce Order Item Meta API.
You use them like this:
// Add to cart item
// This is triggered on add to cart
add_filter('woocommerce_add_cart_item_data', 'my_add_cart_item_data', 10, 2);
function my_add_cart_item_data( $cart_item_meta, $product_id ) {
//Here we can easily filter what values should be added to what products using the $product_id
$cart_item_meta['my_meta_key'] = 'meta value';
return $cart_item_meta;
}
// Add to order item when the cart is converted to an order
// This is triggered when the order is created
add_action('woocommerce_add_order_item_meta', 'my_order_item_meta'), 10, 2);
function my_order_item_meta( $item_id, $values, $cart_item_key ) {
// The value stored in cart above is accessable in $values here
woocommerce_add_order_item_meta( $item_id, 'meta_key', $values['my_meta_key'] );
//Or add what ever you want
$meta_value = 'value';
woocommerce_add_order_item_meta( $item_id, 'meta_key', $meta_value );
}
I hope that helps.
Related
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' );
}
}
}
With the below code, I can successfully add a custom order note to a subscription renewal order when the order is completed.
However, I would like to modify this to add the note to the Subscription Notes instead of the Order Notes. I think Subscription Notes use the same add_order_note function as $subscription->add_order_note instead of $order->add_order_note. But I have been unsuccessful in my attempts to get the $subscription variable to work in the below code.
// Add box contents (product excerpt) as order note for subscriptions
add_action( 'woocommerce_email_before_order_table', 'custom_action_on_completed_customer_email_notification', 10, 4 );
function custom_action_on_completed_customer_email_notification( $order, $sent_to_admin, $plain_text, $email ) {
if( 'customer_completed_renewal_order' == $email->id ){ // for processing order status customer notification…
$product_id = '';
foreach ($order->get_items() as $item_id => $item_values) {
$product_id = $item_values['product_id'];
break; // (optional) stop loop to first item
}
// The text for the note
$note = get_the_excerpt($product_id);
// Add the note
$order->add_order_note( $note, $is_customer_note = 1 );
// Save the data
$order->save();
}
}
Do you know what I need to add/change to make this add to a Subscription note instead of order note?
I wonder if there's a hook for changing Place Order Button behaviour upon click. I am trying to replace/change a product upon placing order as the product selection (all available products) are also in the Checkout Page.
So far I have been trying to manipulate woocommerce_checkout_order_review hook & failed.
add_action('woocommerce_checkout_order_review', 'remove_woocommerce_product');
function remove_woocommerce_product(){
if (isset($_POST['woocommerce_checkout_place_order'])){
global $woocommerce;
$woocommerce->cart->empty_cart(); // Empty the cart
$selectedproduct = $_POST['selectedproductid']; // Get the selected product
WC()->cart->add_to_cart( $selectedproduct ); // Insert the selected product in the the cart
return esc_url( wc_get_checkout_url() ); // Redirect to Payment Gateway Page
}
}
The hook above is not triggered upon Place Order. Maybe there's something wrong with my code or maybe what I suspected is wrong hook applied. Any ideas?
Nevermind... found the answer...
add_action('woocommerce_checkout_process', 'change_product_upon_submission');
function change_product_upon_submission() {
if ( !empty( $_POST['_wpnonce'] ) && !empty($_POST['selectedproductid']) ) {
$selectedproduct = $_POST['selectedproductid']; // Get the selected product
WC()->cart->empty_cart(); //Empty the cart
WC()->cart->add_to_cart( $selectedproduct ); // Insert the selected product in the cart
}
}
For more explanation, see Woocommerce Replace Product in Cart Upon Place Order in Checkout Page
I have a really weird behavior on Woocommerce with the stock management. On a product with stock management enabled, a stock of 100 items and stock status "available", every time I do an order the product stock go to negative and get out of stock.
For example, if I do an order of 2 items of the product, the stock go to -2 right after the order, even if the stock was at 100 right before.
The product is a simple one, without any attribute. I use the following hooks to alter some label and stuffs, but none seems related to this issue:
add_filter('woocommerce_product_single_add_to_cart_text', array(&$this->wc, 'add_to_cart_text'), 11);
add_filter('woocommerce_add_to_cart', array(&$this->wc, 'add_to_cart'), 10, 1);
add_action('woocommerce_cart_item_removed', array(&$this->wc, 'cart_item_removed'), 10, 1);
add_action('woocommerce_order_status_completed', array(&$this->wc, 'order_status_completed'), 10, 1);
add_action('woocommerce_after_shop_loop_item', array(&$this->wc, 'replace_add_to_cart'));
In short, woocommerce_product_single_add_to_cart_text change the add to cart button label, woocommerce_add_to_cart place some vars in session, woocommerce_cart_item_removed remove those session var on item removal from cart, woocommerce_order_status_completed do some stuffs with the session vars (update a CPT from those session vars - I don't touch the order or the product at all) and woocommerce_after_shop_loop_item display a button on product listing. I tried to disable the woocommerce_order_status_completed hook, it didn't change anything.
I will paste any code of those function if any of you think some could be related to this stock issue.
I'm using latest version of Woocommerce and Wordpress.
I found out the culprit, as helgatheviking suggested I disabled all the plugins one by one and found out that the plugin Progression One Click Import provided by the theme and marked as "recommended for theme use" was doing this.
My guess is that it is related to this filter in the plugin code:
add_filter( 'add_post_metadata', array( $this, 'check_previous_meta' ), 10, 5 );
Which is doing this:
public function check_previous_meta( $continue, $post_id, $meta_key, $meta_value, $unique ) {
$old_value = get_metadata( 'post', $post_id, $meta_key );
if ( count( $old_value ) == 1 ) {
if ( $old_value[0] === $meta_value ) {
return false;
} elseif ( $old_value[0] !== $meta_value ) {
update_post_meta( $post_id, $meta_key, $meta_value );
return false;
}
}
}
The flaw in this is that it is inserting the stock meta value raw (-2) instead of decrementing the existing meta value, which Woocommerce seems to do with some filter on his end - a behavior that is overwrited by this filter.
I guess this could be fixed by changing the filter priority but just disabling the plugin was good for me as I don't need to import preview data.
Im adding a custom item meta to every item with woocommerce_add_order_item_meta action.
I dont need to show this custom meta in the Order Detail, because it's an arry stringy that im using to print a pdf.
How can i remove this meta custom item? Is there some action to do it?
Thanks
I understand its a bit old question but I am answering for some other users who will have same issue in future.
If you want your order item meta to not display in admin order details page than you should append underscore (_) at the start of your meta name.
Example:
_custom_order_meta
The underscore trick no longer works. In Woo 3.x there is a hidden meta array:
add_filter('woocommerce_hidden_order_itemmeta',
array($this, 'hidden_order_itemmeta'), 50);
function hidden_order_itemmeta($args) {
$args[] = 'my_hidden_meta';
return $args;
}
It sounds like you need to keep it in order to print the PDF. If you override the order-details.php template you can possibly change:
$item_meta = new WC_Order_Item_Meta( $item['item_meta'], $_product );
to
$array = $item['item_meta'];
if( isset( $array['your_pdf_array_key'] ) ){ unset( $array['your_pdf_array_key'] ); }
$item_meta = new WC_Order_Item_Meta( $array, $_product );
EDIT
The wc_add_order_item_meta() function has 4 parameters as seen in the code:
function wc_add_order_item_meta( $item_id, $meta_key, $meta_value, $unique = false ) {
return add_metadata( 'order_item', $item_id, $meta_key, $meta_value, $unique );
}
If you choose a $meta_key with a preceding underscore, the meta will be automatically hidden from view on the checkout/order-received page, the My Order's list of the My account area, as well as in the admin's order overview page.
Therefore, I would suggest making your woocommerce_add_order_item_meta callback function look something like the following:
add_action( 'woocommerce_add_order_item_meta', '25979024_add_order_item_meta', 10, 3 );
function 25979024_add_order_item_meta( $order_item_id, $cart_item, $cart_item_key ) {
wc_add_order_item_meta( $order_item_id, '_pdf_something', 'hide this stuff' );
}