Add a custom field to an order in WooCommerce 3+ - php

In WooCommerce, I would like to add a new custom field to order details. I now that I can use use the code below to create a new custom field 'referenceNumber' and adds in it "ordercreated" value:
update_post_meta($order_id, 'referenceNumber', 'ordercreated']);
What I would like is to make that through checkout once an order is placed.
But it doesn't work it doesn't add a new custom field to order details page and don't add the value 'ordercreated', as you can see in this screenshot:
So the question is how to add a custom field when an order is placed in WooCommerce?

To add a custom field to an order you can use:
WordPress update_post_meta() function (from an order id):
$order_id = $order->get_id(); // If needed
update_post_meta($order_id, 'referenceNumber', 'ordercreated'); // add and save the custom field
WooCommerce WC_Data update_meta_data() method (from the order object or the order id):
$order = wc_get_order( $order_id ); // If needed: Get the WC_Order object from the order Id
update_meta_data('referenceNumber', 'ordercreated'); // Add the custom field
$order->save(); // Save the data
Where referenceNumber is the meta key and ordercreated is the meta value. Both works.
Now to add a custom field to an order when customer place an order, you can use:
woocommerce_checkout_create_order action hook (before order data is saved - used to adjust order data before it's saved):
add_action( 'woocommerce_checkout_create_order', 'add_custom_field_on_placed_order', 10, 2 );
function add_custom_field_on_placed_order( $order, $data ){
$order->update_meta_data( 'referenceNumber', 'ordercreated' );
}
woocommerce_checkout_update_order_meta action hook (order already exist - used to add custom meta data):
add_action( 'woocommerce_checkout_create_order', 'add_custom_field_on_placed_order', 10, 2 );
function add_custom_field_on_placed_order( $order_id, $data ){
$order->update_meta_data( 'referenceNumber', 'ordercreated' );
}
woocommerce_checkout_order_created action hook (order already exist - to trigger an action or also to add custom meta data):
add_action( 'woocommerce_checkout_order_created', 'add_custom_field_on_placed_order', 10, 2 );
function add_custom_field_on_placed_order( $order_id, $data ){
$order->update_meta_data( 'referenceNumber', 'ordercreated' ); // Add the custom field
$order->save(); // Save data (as order exist yet)
}
Or:
add_action( 'woocommerce_checkout_order_created', 'add_custom_field_on_placed_order' );
function add_custom_field_on_placed_order( $order ){
update_post_meta($order->get_id(), 'referenceNumber', 'ordercreated');
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Hi i had a similar requirement few days ago, as i needed to add new field at checkout. Following article helped me. You can check it too. Here is the link. Basically you will have a write a function which will use woo commerce hook "woocommerce_default_address_fields"
https://wisdmlabs.com/blog/add-custom-fields-woocommerce-checkout-page/

Related

My cart_item_data isn't showing up in the order

I'm working on a site that lets a user enter data from a form and have it attached to a product. I was originally using:
$cart_item_data ['Entry Link'] = $formUrl;
$woocommerce->cart->add_to_cart($productID,$quantity,0,$cart_item_data);
With $formUrl being a link to the form data. Whenever a user made an order, under the product would be 'Entry Link' with the url.
We later had to add variations to the product so the line looked like:
$woocommerce->cart->add_to_cart($productID,$quantity,$typeID,$cart_item_data);
With $typeID being the variation ID. Once I added the $typeID, only the variation showed up on the order in the backend and not the 'Entry Link'.
If I reset $typeID to '0', the entry link shows up when an order is made. I also tried using the variation id in place of the product id but was still getting the same issue. I looked at the documentation and it should be working.
I need both the variation and the 'Entry Link' to be entered and visible from the backend.
This was the part requested by Vincenzo Di Gaetano in the comments
$formUrl = $_SERVER['SERVER_NAME'].'/wp-admin/admin.php?page=gf_entries&view=entry&id='.$formID.'&lid='.$entryID;
$cart_item_data['Entry Link'] = $formUrl;
$variationAttributes['Per'] = 1000;
$woocommerce->cart->add_to_cart($productID,$quantity,$typeID,$variationAttributes,$cart_item_data);
I added variationAttributes to it with 'Per' lining up with the attribute name, '1000' represents the value of that attribute. I hardcoded it in for testing. When I echo just the $formUrl, it does return the correct url
You are setting only 4 arguments instead of 5 for the add_to_cart method of the WC_Cart class.
Try replacing this:
$woocommerce->cart->add_to_cart( $productID, $quantity, $typeID, $cart_item_data );
with:
$woocommerce->cart->add_to_cart( $productID, $quantity, $typeID, $variation, $cart_item_data );
Here is an example of how to add a variation to the cart:
WordPress WooCommerce - Add a variable product to cart using the WC_Cart class
This will not be enough to display the cart item data as the meta of the order item.
Based on this question Save and display product custom meta on WooCommerce orders and emails you will need to save the value as a order item meta data:
// save the cart item data as custom order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'save_cart_item_data_as_order_item_meta_data', 20, 4 );
function save_cart_item_data_as_order_item_meta_data( $item, $cart_item_key, $values, $order ) {
if ( isset( $values['Entry Link'] ) ) {
$item->update_meta_data( __( 'Entry Link'), $values['Entry Link'] );
}
}
The code has been tested and works. Add it to your active theme's functions.php.
Here is the result:

Is there a possibility to make custom prices?

I'm selling Gift Cards via WooCommerce on Wordpress. My customer should be able to set a value for the gift card amount by himself. I just was able to do this via a plugin. Is there a possibilty to do this by changing some code or via functions.php?
Installed Pimwick Gift Card Pro
Yes, but it's a fairly complex process if doing so from a completely fresh WooCommerce installation with no additional plugins. You will need to do the following things to achieve it:
Add a custom input field to the product to add the custom price
Save the data from the custom input field to the session (cart) when that product is added to the cart
Add the cart meta (created above in #2) to the order when the order is created
Adjust the cost of the product based on the custom price meta (added above in #3).
Step 1: Add a custom input field:
You can add the input field using the woocommerce_before_add_to_cart_button filter as shown below.
Alternatively you can use the woocommerce_wp_text_input - here's an example.
add_action( 'woocommerce_before_add_to_cart_button', 'add_custom_price_input', 100 );
function add_custom_price_input() {
if(get_the_ID() != 123) { //use the product ID of your gift card here, otherwise all products will get this additional field
return;
}
echo '<input type="number" min="50" placeholder="50" name="so_57140247_price">';
}
Step 2: Save custom price to Cart/Session
Next, we need to make sure that your custom input field data is carried over to the cart/session data. We can make use of the woocommerce_add_cart_item_data ( docs | example ) filter to that:
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_meta_to_cart', 10, 3 );
function add_custom_meta_to_cart( $cart_item_data, $product_id, $variation_id ) {
$custom_price = intval(filter_input( INPUT_POST, 'so_57140247_price' ));
if ( !empty( $custom_price ) && $product_id == 123 ) { //check that the custom_price variable is set, and that the product is your gift card
$cart_item_data['so_57140247_price'] = $custom_price; //this will add your custom price data to the cart item data
}
return $cart_item_data;
}
Step 3: Add cart meta to the order
Next we have to add the meta from the cart/session to the order itself so that it can be used in the order-total calculations. We use the woocommerce_checkout_create_order_line_item ( docs | example ) to do this:
add_action( 'woocommerce_checkout_create_order_line_item', 'add_custom_meta_to_order', 10, 4 );
function add_custom_meta_to_order( $item, $cart_item_key, $values, $order ) {
//check if our custom meta was set on the line item of inside the cart/session
if ( !empty( $values['so_57140247_price'] ) ) {
$item->add_meta_data( '_custom_price', $values['so_57140247_price'] ); //add the value to order line item
}
return;
}
Step 4: Adjust total of gift card line item
Finally, we simply adjust the cost of the line item of the gift card based on the value entered into the input field. We can hook into woocommerce_before_calculate_totals ( docs | example ) to do this.
add_action( 'woocommerce_before_calculate_totals', 'calculate_cost_custom', 10, 1);
function calculate_cost_custom( $cart_obj ) {
foreach ( $cart_obj->get_cart() as $key => $value ) {
$price = intval($value['_custom_price']);
$value['data']->set_price( $price );
}
}

Read and update a custom field in woocommerce_product_on_backorder hook

I have a custom field in Woocommerce variation products and I try to update that field wherever there is a backorder. This is the code
add_action( 'woocommerce_product_on_backorder', 'reduce_second_stock' );
function reduce_second_stock( $array ){
$temp = get_post_meta($array['product']->ID, 'second_stock', true);
update_post_meta( $array['product']->ID, 'second_stock', $temp - $array['quantity'] );
}
The custom field is called second_stock which is just a number. What I try to do is to reduce that number based on the backorder quantity of that order.
However, even if the regular stock of the product is updated, my custom field stays the same.
With this hook, $array['product'] is the WC_Product Object, so to get the product Id you need to use the related method get_id()… Since WooCommerce 3 and CRUD Objects, you can use directly the WC_Data methods get_meta(), update_meta_data() and save() on the WC_Product Object like:
add_action( 'woocommerce_product_on_backorder', 'reduce_second_stock' );
function reduce_second_stock( $array ){
if( $original_stock = $array['product']->get_meta('second_stock') ) {
$array['product']->update_meta_data( 'second_stock', ( $original_stock - $array['quantity'] ) );
$array['product']->save();
}
}
Code goes in function.php file of your active child theme (or active theme). It should work.

Display custom data on Woocommerce admin order preview

I would like to add some custom data to the end of the preview order in Woocommerce order listing page.
For that I have tried the hook 'woocommerce_admin_order_preview_end'. But no way to pass any arguments to that action.
add_action( 'woocommerce_admin_order_preview_end', 'custom_display_order_data_in_admin' );
function custom_display_order_data_in_admin( $order ){
//$order is empty here
}
Does anybody have an idea on this? I'm stuck on this.
You can't get the order object as it's a template that loads specific data via Ajax and there is no arguments for woocommerce_admin_order_preview_end action hook.
Instead the filter hook woocommerce_admin_order_preview_get_order_details will allow you first to add some custom data that you will be able to call and display it after in woocommerce_admin_order_preview_end action hook.
The code:
// Add custom order meta data to make it accessible in Order preview template
add_filter( 'woocommerce_admin_order_preview_get_order_details', 'admin_order_preview_add_custom_meta_data', 10, 2 );
function admin_order_preview_add_custom_meta_data( $data, $order ) {
// Replace '_custom_meta_key' by the correct postmeta key
if( $custom_value = $order->get_meta('_custom_meta_key') )
$data['custom_key'] = $custom_value; // <= Store the value in the data array.
return $data;
}
// Display custom values in Order preview
add_action( 'woocommerce_admin_order_preview_end', 'custom_display_order_data_in_admin' );
function custom_display_order_data_in_admin(){
// Call the stored value and display it
echo '<div>Value: {{data.custom_key}}</div><br>';
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Note: You can also use woocommerce_admin_order_preview_start hook if needed…

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.

Categories