I am trying to customize the "Order Complete" email. Specifically, I have some products (software) that require license keys. So far, I've finished my algorithm for generating and storing the license keys (as well as verification) in a database.
In my child theme, under /woocommerce/order/order-details.php, I've added the corresponding code to add the license keys to the database. I don't want to display them on the order-details page, because the user could close this webpage and then lose the keys. So, I want to send them in an email (or display the keys in both the email and the order-details page). I want to use the "Order-Completed" email, because I don't want to send multiple emails.
I figured out how to add on to the order-details.php template because there was the pre-existing WC_ORDER instance: $order = new WC_Order( $order_id ). After that, I just looked through the documentation to find the correct methods that I needed, and I came up with this:
foreach( $order->get_items() as $item ) {
$_product = apply_filters( 'woocommerce_order_item_product', $order->get_product_from_item( $item ), $item );
$item_meta = new WC_Order_Item_Meta( $item['item_meta'] );
?>
// some code that was already included
if ( $_product && $_product->exists() && $_product->is_downloadable() && $order->is_download_permitted() ) {
if ($_product->get_attribute('needs_license_key') == "True") { // custom attribute for my software
// generate and store license keys
I only had to add in the if ($_product->get_attribute('needs_license_key')... part, so it was not very complex.
However, this is not present in the Order-Completed template, so I'm not sure where this goes. I'd need to iterate through all the products, check if they are downloadable (I have the code for that already), and then locate the product keys (I know how to do that as well). My main question is: How do I find out what order number the email is being sent for, as well as other stats for that order (such as products listed and their attributes, so I can iterate over them as seen above)? I'm not sure how to do this exactly with WooCommerce.
Related
What I am trying to achieve here is to update all the weight values inside the products that already exist based on the criteria in the if statement.
So I am using the following code:
function update_product_weight_from_dimensions( $product ) {
//$product = wc_get_product();
$squared_dimensions = $product->get_length() * $product->get_width();
$synthetic_product = $product->get_attribute('pa_composition');
if($squared_dimensions <= 2.8 && $synthetic_product == 'steel') {
$product->set_weight(3);
}
}
add_action( 'woocommerce_admin_process_product_object', 'update_product_weight_from_dimensions', 10, 1 );
If i use a hook like do_action( 'update_product_weight_from_dimensions', 10, 1 ); , nothing will happen.
As per this post in StackOverflow , i am already using the $product->set_weight(); and the hook woocommerce_admin_process_product_object. The function already works as expected but only if I SAVE the product. I want to update the values without needing to run inside all products to hit the SAVE/UPDATE button. If this function could run only once then this would also be closer to what I try to achieve.
As far as I know, the weight of standard WooCommerce products is stored solely inside wp_postmeta table with the _weight meta key.
Therefore you should be able to use:
update_post_meta( $product->get_id(), '_weight', $your_value );
I would also recommend to clear WC transients after updating the weights (I am not sure if it is needed though).
Anyway, the $product->set_weight() and $product->save() approach is really the right thing to do. 4000 products really isn't that much and you can always split these into smaller chunks, if it is a one-time action.
Is it possible to automatically copy the value of a Customer's custom field to an Order's custom field when this customer places the order?
Should it be done using any plugin/extension or thru customized coding behind the scenes?
This custom field does not need to be displayed on customer order view. We just need it to distinguish whether the order was placed by Consumer or Wholesale when we get it thru API.
I'm totally new in this system, i did a lot of research but couldn't find any direction for this.
Any advice/suggestion would be very appreciated.
You can use woocommerce_thankyou hook to add this user data to the order meta data:
add_action( 'woocommerce_thankyou', 'orders_from_processing_to_pending', 10, 1 );
function orders_from_processing_to_pending( $order_id ) {
if ( ! $order_id )
return;
$order = wc_get_order( $order_id );
$user_id = get_current_user_id();
//Set HERE the meta key of your custom user field
$user_meta_key = 'some_meta_key';
// Get here the user custom field (meta data) value
$user_meta_value = get_user_meta($user_id, $user_meta_key, true);
if ( ! empty($user_meta_value) )
update_post_meta($order_id, $user_meta_key, $user_meta_value);
else
return;
}
Code goes in function.php file of your active child theme (active theme or in any plugin file).
This code is tested and works.
After, if you want to display that value on admin edit order backend or in frontend customer view order and emails notifications, you will have to use some more code and some other hooks…
Does anyone have (or know of) a PHP code snippet solution to add automation say a checkbox to increase stock by quote list or bring back the original increase stock button in the order page; before sending out a quote ?
I have searched many days and hours for a code solution or a Plugin => Nothing.
I believe WooCommerce once used to have this button in the orders page but it is now not there, I am on Woo5.6.0, WP5.8 and PHP7.4
Thanks in advance.
So.. After re-posting my question again and reducing it to simplify and add focus, after I think a robot response closed my original question.
I looked at the suggestions that came up and "would you believe it" the post below was in the suggestion list.. I had not seen this before.
Increase stock (not decrease) after completed WooCommerce orders?
I had to test and change the call adapt the code a little to fit my store model..
I now have a working safe way of targeting only the stock from a quote list and only elevating the stock by the quote list amount (quantity) when I send out a quote.
The only downside to this is if another client comes along and sees the commission in stock they could place it in their basket and then it would not match the original quote sent out.
"Code to develop another time to find a way to reserve that elevated and allocated stock".
I did this after thinking about how to only trigger an action for a sent quote.
So a deep dive into Yiths Request a quote code to find the class where it changed the WooCommerce order status and came up with this.
Thanks to #loictheaztec he was responsible for this inspiration.
// Increase stock on pending quote order status - An experiment "ywraq-pending"
add_action( 'woocommerce_order_status_ywraq-pending', 'action_on_quote_sent' , 10, 1 );
function action_on_quote_sent( $order_id )
{
// Get an instance of the order object
$order = wc_get_order( $order_id );
// Iterating though each order items
foreach ( $order->get_items() as $item_id => $item_values ) {
// Item quantity
$item_qty = $item_values['qty'];
// getting the product ID (Simple and variable products)
$product_id = $item_values['variation_id'];
if( $product_id == 0 || empty($product_id) ) $product_id = $item_values['product_id'];
// Get an instance of the product object
$product = wc_get_product( $product_id );
// Get the stock quantity of the product
$product_stock = $product->get_stock_quantity();
// Increase back the stock quantity
wc_update_product_stock( $product, $item_qty, 'increase' );
}
}
My issue: The client has 12 locations, each location is a different corporation hence a different PayPal account per business. By default woocommerce only supports one email to be entered to process the payment. The goal is to use one installation of wordpress / woocommerce then direct the user to the PayPal account associated with the location they have selected upon checkout.
My Theory / Attempt: originally I thought of implementing this feature by setting up a variation so the user can select a location which will then pass a parameter to the URL. The parameter would later be used within the PHP to overwrite the default email.
My Problem: I am having trouble with overwriting the default email that is entered within the admin settings, I cant seem to locate this email in the database. I am assuming the file pertaining this modification is located at: wp-content/plugins/woocommerce/includes/gateways/paypal but would prefer doing this the wordpress way vs editing core files, for obvious reasons. After doing some research I have found the following action shown below, but this is for the proceed to checkout button, I am looking to interact with the proceed to PayPal button. I am fluent in PHP but not the best with WordPress development. I would think this is a popular issue since majority of franchises would deal with such a scenario, but I am unpleasantly surprised on the amount of information regarding this topic. If someone could point me in the right direction of conquering this task it would be greatly appreciated!
remove_action('woocommerce_proceed_to_checkout','woocommerce_button_proceed_to_checkout', 20);
add_action('woocommerce_proceed_to_checkout', 'change_url_to_checkout', 20);
function change_url_to_checkout(){
$extra_url = 'put_your_extra_page_url_here';
?>
<?php _e( 'Proceed to Checkout', 'woocommerce' ); ?>
<?php
}
I can see two functions to be written here.
1. To alter the order data when an order is created. This is where we save the email needed.
add_action( 'woocommerce_checkout_update_order_meta', 'woocommerce_checkout_update_order_meta' );
function woocommerce_checkout_update_order_meta( $order_id ) {
$email = 'paypal#location1.com';
// do something here as to use the right email.
// you have $order_id.
// can be used as:
// $order = wc_get_order( $order_id );
// $order->get_billing_address_1() to get the address to check order address.
// or use $_POST['location'] if ever you posted some data.
update_post_meta( $order_id, '_alternative_paypal_email', $email );
}
2. Then use woocommerce_paypal_args to alter the args that is being passed to paypal.
add_filter( 'woocommerce_paypal_args', 'woocommerce_paypal_args', 10, 2 );
function woocommerce_paypal_args( $paypal_args, $order ) {
$email = get_post_meta( $order->get_id(), '_alternative_paypal_email', true );
if ( !empty( $email ) ) {
$paypal_args['business'] = $email;
}
return $paypal_args;
}
To summarize, this is just an example. But these two hooks is enough to get what you need.
I am a WP noob but very comfortable in PHP.
I am working with a client and we have built a product customization tool as an Angular.js single page application. When the product is finished being customized we are seeking to inject it into a WooCommerce cart so the client can check out. To do this we are $_POSTing the data to a PHP file in the root directory of the WP install. The code to catch it looks like:
require_once('./wp-load.php' );
global $woocommerce;
$woocommerce->session->set_customer_session_cookie(true);
$woocommerce->cart->empty_cart();
$id_arr = $_GET['productID'];
$pdfName = $_GET['pdfName'];
for($i=0; $i<count($id_arr); $i++){
$id = $id_arr[$i];
if ($id==0) continue;
if ($i==0){
$ret = $woocommerce->cart->add_to_cart($id, 1, '', '', array('pdfName'=>$pdfName));
}else{
$ret = $woocommerce->cart->add_to_cart($id);
}
}
wp_redirect(site_url().'/cart/');
The products are all correctly added to the cart but after checkout there is no sign of the metadata. After extensive research, I have found an article here: https://wpml.org/forums/topic/woocommerce-add-to-cart-does-not-work-with-wpml-activated/ that shows me that plugins can cause this behavior. So I have two specific questions?
Does my code make sense, am I creating the metadata array correctly?
Do I need to create something in WooCommerce called pdfName before I can do this?
Is there another way that metadata can be added to an order in
WooCommerce that may work around this problem?
It looks like you are adding the metadata correctly. However, as soon as you refresh, WooCommerce re-creates the cart data. Therefore you have to tell WooCommerce to maintain the metadata when it is pulling the cart from the stored session. Well, at least that is my understanding of it. So I think you need to filter thee $cart_item as it is run through the woocommerce_get_cart_item_from_session filter:
add_filter( 'woocommerce_get_cart_item_from_session', 'so_29660316_get_cart_item_from_session', 11, 2 );
function so_29660316_get_cart_item_from_session( $cart_item, $values ) {
if ( isset( $values['pdfName'] ) ) {
$cart_item['pdfName'] = $values['pdfName'];
}
return $cart_item;
}