Woocommerce: how do I add metadata to a cart item? - woocommerce

I have a digital product which is described by a quantity and a price, but which also needs 3 more numbers to completely specify it (Unix dates, etc). Problem: how do I get these numbers into the cart?
As far as I can see, there are 2 possible ways to handle this:
A product variation
A product custom field
It looks like variations can only handle discrete values with a limited range (ie. red/yellow/green, S/M/L, etc), and can't handle general integers, like dates. That leaves custom fields. I think I'm right in saying that custom fields are ordinary meta data on the product post page, so I can handle them with get_post_meta and update_post_meta.
So, if I go for custom fields, then I would update the product page field during ordering, and then I would read back the field during checkout, when the WC_Order is created, and add the field to the new order. However, this won't work. I can't change metadata on the product page, because the product is global to all customers, and this operation would interfere with other customers. In other words, you can't store order-specific information in a product, so neither of these options would work.
So, how do I store temporary product metadata and pass it between the ordering and checkout phases (ie. between WC_Cart and WC_Order)?
One option would be to store it as user metadata (or as session data?), but there's got to be a better way - any ideas?

It turns out to be easy to do this with session data. When you're adding an item to the cart (see the source for add_to_cart_action) you create a session variable, containing all your additional meta data:
WC()->session->set(
'my_session_var_name',
array(
'members' => $members,
'start' => $start,
'expiry' => $expiry,
'etc' => $etc));
When the user checks out, the cart data disappears, and a new order is created. You can hook into woocommerce_add_order_item_meta to add the session meta data to the order meta data:
add_action(
'woocommerce_add_order_item_meta', 'hook_new_order_item_meta', 10, 3);
function hook_new_order_item_meta($item_id, $values, $cart_item_key) {
$session_var = 'my_session_var_name';
$session_data = WC()->session->get($session_var);
if(!empty($session_data))
wc_add_order_item_meta($item_id, $session_var, $session_data);
else
error_log("no session data", 0);
}
That's it. You do have to figure out how to get the order metadata out and do something useful with it, though. You may also want to clear the session data, from hooks into woocommerce_before_cart_item_quantity_zero, and woocommerce_cart_emptied. There's gist here which has some example code for this.

Related

Differences between WooCommerce price filters

First of all, thank you for your support all those years.
I am building a role-based pricing plugin for a client and I am having an existential crisis over filters WooCommerce uses for prices. I made this post in hope someone can explain this so someone in the future can find this post.
I managed to understand how filters for simple products work but I don't have an idea how equivalent filters for variable products work
Simple products
As from what I understood, you can override price, regular price, and sale price for simple products returning some value inside filters woocommerce_product_get_price, woocommerce_product_get_regular_price, and woocommerce_product_get_sale_price. Those filters will save provided data into $product object and you can easily access them later in woocommerce_get_price_html filter by using $product->get_regular_price
Variable products
Looks like variable products work differently. For example, they dont save overriden price to $product or $variation object and you cannot fetch overriden prices by calling $variation->get_regular_price.
As I understood, following filters change price of the product on add-to-cart variation select, and in the cart and do not save them in $variation object.
woocommerce_product_variation_get_price
woocommerce_product_variation_get_regular_price
woocommerce_product_variation_get_sale_price
I didnt manage to fully understand what following filters do. But when I turn them on loop price changes and product price changes but prices are removed from add-to-cart select and cart prices are not changed.
woocommerce_variation_prices_price
woocommerce_variation_prices_regular_price
woocommerce_variation_prices_sale_price

Creating WooCommerce placeholder for Emails sent

My client, a courier company, is using delivery software that is able to track with both WooCommerce order no. and ID, which means it requires both order no. and ID ("wc_order_abcdefg") to work, I believe this falls in the phpmyadmin database of post_password column.
Full tracking ID goes like: wc_order_abcdefg.66
So in the WooCommerce email settings, it only has {order_number}. How do I create one for {order_id}?
It looks like, your shipment tracking number is {order_key}.{order_number}.
Once you get hold of the order object, you can get its key simply with: $order->get_order_key().
{order_key} is not available as an email placeholder. So in order to include it in the email sent to the customer, you have different options depending on where you want it to be displayed. For example:
You could include the tracking number in the body of the email. In this case, you can override one of the WooCommerce email templates (e.g. email-order-details.php). See the WooCommerce docs for more info on how to override templates.
You could include the tracking number in the subject of the email. In this case, you can use the woocommerce_email_subject_customer_completed_order filter. E.g. (this snippet should be added to your functions.php):
add_filter( 'woocommerce_email_subject_customer_completed_order', 'add_tracking_number_to_email_subject', 1, 2 );
function add_tracking_number_to_email_subject( $subject, $order ) {
return sprintf( 'Thank you for your order! Your shipment tracking number is: %s.%s', $order->get_order_key(), $order->get_id() );
}

How to set a maximum limit in WooCommerce orders per item & per user & per date

I need to limit user's orders in WooCommerce in a way that each user would be able to order some specific products for a limited amount per day. this way the limitation is "per user"/"per product"/"per day" !
for example each user could buy only 10 items of a product each day, and the next day he would be able to buy 10 more.
I have checked almost all plugins related to limiting orders but none of them had all these conditions. I also read some sample codes here like this one. but since I'm new to php and wordpress coding I couldn't figure out how to change it to my preference.
I appreciate any help
I would start with adding a function to the woocommerce_add_to_cart hook.This is a basically a hook that get called when a new product is added to the cart. Then I will work with the users meta where I will check if the user has bought this product already when this has happened. If there is no such data I will then add it to the users meta.
Mind that you have two scenarios here - first, the product is just added to the cart and not purchased, the second one is when the product is purchased. This is important because you will have also the case when the user deletes product from the cart and you will need also a hook there so you can update the user meta. Here you can use woocommerce_remove_cart_item and woocommerce_after_cart_item_quantity_update (check for references here )
And finally you will need to hook on order completion -> check those hooks.
But still, one of the most important parts is how you are going to build the array for the user meta. I would suggest creating an associative array with key value -> the product id. As value of the array you can have another array with date of purchase and products quantity. Something like this:
$users_products = [
product_id1 => [
'date' => timestamp,
'quantity' => 3
],
product_id2 => [
'date' => timestamp,
'quantity' => 3
]
];
Where product_id1 and product_id2 are actual products ids. This way it will be easier for you to loop through the user meta and check if the current product is in the list. Also to avoid making this user meta data too big check if the date of each item is not outdated and if so - delete(unset) this element from the array and update it the user meta with the refreshed data.
There is much more that you will need to code but I think this will be a good start for you.

WooCommerce - Change customer order after it has been placed and paid

Using three plugins:
WooCommerce
Subscriptio
WooEvents
I have created a product which allows for a customer to pay for an event over five instalments.
A customer has placed an order and made their first of the five payments via PayPal and has then contacted me to advise they have booked the wrong event.
The correct event is exactly the same except the dates are a month sooner.
I have added the following snippet to be able to edit 'processing' orders:
add_filter( 'wc_order_is_editable', 'wc_make_processing_orders_editable', 10, 2 );
function wc_make_processing_orders_editable( $is_editable, $order ) {
if ( $order->get_status() == 'processing' ) {
$is_editable = true;
}
return $is_editable;
}
From the order screen within the back-end of WordPress I can see that the the order can be edit by way of removing the product from the order or editing the meta data and cost.
The correct product that should have been ordered has a different product/variation ID.
My question is simply:
Should I remove the incorrectly ordered product from the order and add the correct product (both have the same properties with the exception of the courses dates); or
Should I just change the meta data and increase the stock levels for the incorrectly product back to X and reduce the stock level for the correct product?
Your second option is much better. Change the meta from database if its accessible and then manage the stock accordingly.
I have not yet done this, but according to this exchange ...
How can I add a product to an existing and paid Woocommerce order?
... you can set the order status to "On Hold" and make changes to the order itself. I presume you would then return the status to "Processing".
I would expect that if the application permits those changes, then it would be doing the background meta changes to inventory levels, etc., and spare you the problem of doing so (and the potential errors that may occur when messing with the data tables outside of the application).
Like I said, I haven't done this. But it might be worthwhile doing a little test to make sure it works as it seems to be described in the answer to the other question.
J

Sort order of custom meta keys on woocommerce frontend

I have made a custom field on my Woocommerce products. It's a numeric value, and it shows perfectly on my product page on my front end via post meta. Then i used this tutorial to put my custom meta key into Woocommerces product sorting dropdown:
https://www.skyverge.com/blog/sort-woocommerce-products-custom-fields/
It works so far that the specific custom meta key can be selected in the drop down, and the right products are shown, but the order of the sorted products is not following the descending order that is given in the code.
case 'saetpris':
$sort_args['meta_key'] = 'saetpris_pr_maaned';
$sort_args['orderby'] = 'meta_value_num';
$sort_args['order'] = 'DESC';
break;
Rather the order of the products seems to go by product ID.
I have searched a lot on Google and also here on Stack Overflow, but i didn't find any answers. Clearly i am missing something, but what? :-)

Resources