I am currently using the following code in the functions.php file.
add_action( 'woocommerce_after_shipping_rate', 'action_after_shipping_rate', 20, 2 );
function action_after_shipping_rate ( $method, $index ) {
// Targeting checkout page only:
if( is_cart() ) return; // Exit on cart page
if( 'flat_rate:3' ) {
echo __("<p>Delivery will take place tomorrow</br> morning between 8-12</p>");
}
}
Now I would like to get the customer postcode, to then add it to my pre-existing code.
Someone who can help me with this?
You could use WC()->customer->get_shipping_postcode() to add the postcode
So you get:
function action_woocommerce_after_shipping_rate( $method, $index ) {
// Targeting checkout page only
if ( is_cart() ) return;
// Get shipping postcode
$shipping_postcode = WC()->customer->get_shipping_postcode();
// Compare
if ( $method->get_id() === 'flat_rate:3' ) {
// Output
echo '<p>' . __( 'My text + zipcode = ', 'woocommerce') . $shipping_postcode . '</p>';
}
}
add_action( 'woocommerce_after_shipping_rate', 'action_woocommerce_after_shipping_rate', 10, 2 );
Related
In the Woocommerce admin screen, I'm attempting to use the order line meta data to display a button which will open up a new window with the URL of the dropship supplier. I have successfully pulled the supplier URL from the product on order and pushed it to the order line item.
I am able to change the meta data to a button but the consequence of that is the other custom fields which contain the custom options are wiped.
This is the full code which I have added to the functions.php file
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(), 'supplier_url', true );
// Update order item meta
if ( ! empty( $custom_field_value ) ){
$item->update_meta_data( '_supplier', $custom_field_value );
}
}
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 20, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
// Change display_key
if( $meta->key === '_supplier' && is_admin() )
$display_key = __("Supplier", "woocommerce" );
return $display_key;
}
add_filter( 'woocommerce_order_item_display_meta_value', 'change_order_item_meta_value', 20, 3 );
function change_order_item_meta_value( $value, $meta, $item ) {
// Display supplier meta value as a button
if( $meta->key === '_supplier' && is_admin() ) {
$display_value = __('<a class="button" target="_blank" href="'.$value.'">Order</a>', 'woocommerce' );
return $display_value;
}
}
These images show the before and after of using the last block of code.
Before:
After:
Where have I gone wrong with my code and is what i'm trying to achieve possible?
The main mistake is on last function where $display_value should be replaced with just $value and then return $value; should be located at the end before last closing bracket.
I have also revisited all your code:
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 ) {
$supplier_url = $values['data']->get_meta( 'supplier_url' ); // Get product custom field value
// add product custom field as custom order item meta data
if ( ! empty($supplier_url) ){
$item->update_meta_data( '_supplier', $supplier_url );
}
}
add_filter('woocommerce_order_item_display_meta_key', 'filter_wc_order_item_display_meta_key', 20, 3 );
function filter_wc_order_item_display_meta_key( $display_key, $meta, $item ) {
// Change displayed label for specific order item meta key
if( is_admin() && $item->get_type() === 'line_item' && $meta->key === '_supplier' ) {
$display_key = __("Supplier", "woocommerce" );
}
return $display_key;
}
add_filter( 'woocommerce_order_item_display_meta_value', 'change_order_item_meta_value', 20, 3 );
function change_order_item_meta_value( $value, $meta, $item ) {
// Change displayed value for specific order item meta key
if( is_admin() && $item->get_type() === 'line_item' && $meta->key === '_supplier' ) {
$value = __('<a class="button" target="_blank" href="'.$value.'">Order</a>', 'woocommerce' );
}
return $value;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
On the checkout page of my WooCommerce based site, users will have a list of shipping methods to choose from depending on what they are purchasing
This is the list I want to capture:
Things like
“Free Shipping” for orders over a certain price
“Freight Shipping” for certain items, and so on.
My goal, is to display ALL available methods for each specific order, and display it on the “Edit Order / Order Details” page in the Admin view.
A small feature that would help us be able to quickly identify what option people are choosing more often, depending on the choices that they have available.
This is what I have so far:
add_action( 'woocommerce_checkout_update_order_meta', 'save_available_shipping_methods' );
function save_available_shipping_methods( $order_id ) {
$shippingmethods = WC()->cart->get_shipping_methods();
update_post_meta( $order_id, '_shipping_methods', $shippingmethods );
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'get_available_shipping_methods', 10, 1 );
function get_available_shipping_methods($order){
$order = wc_get_order( $order_id );
if ( $order ) {
echo '<p><strong>'.__('Available Shipping Methods: ').'</strong> ' . get_post_meta($order->get_shipping_methods(), '_shipping_field_value', true ) . '</p>';
}
}
I'll attach a picture as well to maybe make things a little easier to follow.
This is where I would like to put it. The current hook places the field underneath the shipping address
In the woocommerce_checkout_update_order_meta hook, the available shipping packages are stored via update_post_meta
Comments with explanation added in the code
function action_woocommerce_checkout_update_order_meta( $order_id ) {
// Get shipping packages
$packages = WC()->shipping()->get_packages();
// Set array
$rate_labels = array();
// Loop trough packages
foreach ( $packages as $key => $package ) {
// Loop through package rates
foreach( $package['rates'] as $rate_id => $rate ) {
// Push to array
$rate_labels[] = $rate->get_label();
}
}
// NOT empty
if ( ! empty ( $rate_labels ) ) {
// Update post meta
update_post_meta( $order_id, '_available_shipping_methods', $rate_labels );
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'action_woocommerce_checkout_update_order_meta', 10, 1 );
// Display on the order edit page (backend)
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
// True
if ( $rate_labels ) {
// Loop trough rate labels
foreach( $rate_labels as $rate_label ) {
// Output
echo '<p>' . $rate_label . '</p>';
}
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
In case anyone is wondering, this is the final result. It will loop through each order to find the available shipping methods at the time, along with how much it was quoted for.
// Capture the available shipping methods, and costs:
function action_woocommerce_checkout_update_order_meta( $order_id ) {
// Get shipping packages
$packages = WC()->shipping()->get_packages();
// Set array
$rate_labels = array();
$rate_costs = array();
// Loop trough packages
foreach ( $packages as $key => $package ) {
// Loop through package rates
foreach( $package['rates'] as $rate_id => $rate ) {
// Push to array
$rate_labels[] = $rate->get_label();
$rate_costs[] = $rate->get_cost();
}
}
// NOT empty
if ( ! empty ( $rate_labels ) ) {
// Update post meta
update_post_meta( $order_id, '_available_shipping_methods', $rate_labels );
update_post_meta( $order_id, '_available_shipping_method_cost', $rate_costs );
}
}
add_action( 'woocommerce_checkout_update_order_meta', 'action_woocommerce_checkout_update_order_meta', 10, 1 );
// Make it display on the edit order page:
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
$rate_costs = $order->get_meta( '_available_shipping_method_cost' );
$methods = array ( $rate_labels, $rate_costs );
// True
if ( $rate_labels ) {
// Loop
echo '<p><strong>Shipping Methods: </strong>';
foreach(array_combine($rate_labels, $rate_costs) as $rate_label => $rate_cost) {
echo '<p>' . $rate_label . ' - $' . $rate_cost . '</p>';
}
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
Previous / Related Question: Display ALL available shipping methods for each specific order on admin edit order pages in Woocommerce
Currently in my WooCommerce based site, I am wanting to display the available shipping methods and prices on the order edit page.
It does not display the data as I want. For example, the output of my code so far results in:
Method 1
Method 2
Method 3
Price 1
Price 2
Price 3
When alternatively, I would like for it to display like this:
Method 1 - $Price 1
Method 2 - $Price 2
Method 3 - $Price 3
I understand why it is displaying this way, but I was curious how I could iterate the loops at the same time and format them, rather than one after the other.
This is my code so far:
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'action_woocommerce_admin_order_data_after_shipping_address', 10, 1 );
function action_woocommerce_admin_order_data_after_shipping_address( $order ){
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
$rate_costs = $order->get_meta( '_available_shipping_method_cost' );
$methods = array ( $rate_labels, $rate_costs );
// True
if ( $rate_labels ) {
// Loop
echo '<p><strong>Shipping Methods: </strong>';
foreach( $rate_labels as $rate_label ) {
// Output
echo '<p>' . $rate_label . '</p>';
}
foreach( $rate_costs as $rate_cost ) {
// Output
echo '<p> $' . $rate_cost . '</p>';
}
}
}
The following slight different code will display the label and the cost of all available shipping methods (in one array | one foreach loop):
add_action( 'woocommerce_checkout_create_order', 'action_wc_checkout_create_order' );
function action_wc_checkout_create_order( $order ) {
$shipping_data = array(); // Initializing
// Get shipping packages keys from cart
$packages_keys = (array) array_keys(WC()->cart->get_shipping_packages());
// Loop through shipping packages keys (when cart is split into many shipping packages)
foreach( $packages_keys as $key ){
// Get available shipping rates from WC_Session
$shipping_rates = WC()->session->get('shipping_for_package_'.$key)['rates'];
// Loop through shipping rates
foreach( $shipping_rates as $rate_key => $rate ){
// Set all related shipping rate data in the array
$shipping_data[] = array(
'id' => $rate_key,
'method_id' => $rate->method_id,
'instance_id' => (int) $rate->instance_id,
'label' => $rate->label,
'cost' => (float) $rate->cost,
'taxes' => (array) $rate->taxes,
'package_key' => (int) $key,
);
}
}
// Save shipping data as order custom field
if( ! empty($shipping_data) ) {
$order->update_meta_data( '_shipping_data', $shipping_data );
}
}
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'available_shipping_rates_after_shipping_address' );
function available_shipping_rates_after_shipping_address( $order ) {
// Get shipping rates custom meta data
$shipping_data = $order->get_meta( '_shipping_data' );
if ( ! empty($shipping_data) ) {
echo '<p><strong>Shipping Methods: </strong><br>';
// Loop through shipping rates data
foreach( $shipping_data as $rate ) {
// Calculate cost with taxes
$rate_cost = $rate['cost'] + array_sum($rate['taxes']);
// Output
echo $rate['label'] . ( $rate_cost > 0 ? ': '. wc_price($rate_cost) : '' ) . '<br>';
}
echo '</p>';
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
In case anyone happens to have the same question as I did, here is how I did it:
function action_woocommerce_admin_order_data_after_shipping_address( $order ) {
// Get meta
$rate_labels = $order->get_meta( '_available_shipping_methods' );
$rate_costs = $order->get_meta( '_available_shipping_method_cost' );
$methods = array ( $rate_labels, $rate_costs );
// True
if ( $rate_labels ) {
// Loop
echo '<p><strong>Shipping Methods: </strong>';
foreach(array_combine($rate_labels, $rate_costs) as $rate_label => $rate_cost) {
echo '<p>' . $rate_label . ' - $' . $rate_cost . '</p>';
}
}
}
With the code below, I am able to change the display of specific shipping methods full labels on WooCommerce cart and checkout pages:
add_filter( 'woocommerce_cart_shipping_method_full_label', 'custom_shipping_labels', 10000, 2 );
function custom_shipping_labels($label, $method){
$shpmethod = $label;
if(strpos($shpmethod, 'Express Shipping') !== false){
$shpmethod = str_replace('Express Shipping',' test express lbl',$shpmethod);
}
elseif(strpos($shpmethod, 'Free Standard Shipping') !== false){
$shpmethod = str_replace('Free Standard Shipping',' test free lbl',$shpmethod);
}
return $shpmethod;
}
Now I need to access the customer selected county inside that custom function hooked in woocommerce_cart_shipping_method_full_label filter hook.
Is it possible to get the customer selected country in that hooked function?
To get the selected shipping country you can use one of those:
from WC_Session data WC()->session->get('customer')['shipping_country'].
or WC()->checkout->get_value('shipping_country')
or from WC_Customer data: WC()->customer->get_shipping_country().
For testing purpose, here with the code below, selected (or customer) billing country code is displayed with each shipping method full label:
add_filter( 'woocommerce_cart_shipping_method_full_label', 'custom_shipping_labels', 10000, 2 );
function custom_shipping_labels($label, $method){
// Get selected shipping country value (country code)
$shipping_country = WC()->checkout->get_value('shipping_country');
// If shipping country is empty, we get it from customer data
if( empty( $shipping_country ) ) {
$shipping_country = WC()->customer->get_shipping_country();
}
return $label .' ('.$shipping_country. ')';
}
Now in your code you can use $method->label to target each defined shipping method label string, which is more efficient. So your code will be:
add_filter( 'woocommerce_cart_shipping_method_full_label', 'custom_shipping_labels', 10000, 2 );
function custom_shipping_labels($label, $method){
// Get selected checkout shipping country value (country code)
$shipping_country = WC()->checkout->get_value('shipping_country');
// If shipping country is empty, we get it from customer data
if( empty( $shipping_country ) ) {
$shipping_country = WC()->customer->get_shipping_country();
}
if ( $method->label == 'Express Shipping' ) {
$label = str_replace( $method->label, __('test express lbl'), $label );
}
elseif ( $method->label == 'Free Standard Shipping' ) {
$label = str_replace( $method->label, __('test free lbl'), $label );
}
return $label;
}
Code goes in functions.php file of your active child theme (active theme). Tested and works.
Now you can use the selected shipping country as you wish.
For that you can use WC_Customer::get_shipping_country()
https://docs.woocommerce.com/wc-apidocs/class-WC_Customer.html
function custom_shipping_labels( $label, $method ) {
// DEBUG
//echo '<pre>', print_r($label, 1), '</pre>';
//echo '<pre>', print_r($method, 1), '</pre>';
// Get shipping country
$shipping_country = WC()->customer->get_shipping_country();
// DEBUG
echo $shipping_country . '<br>';
if ( $shipping_country == 'BE' ) {
echo 'Yeey' . '<br>';
}
if( strpos( $label, 'Express Shipping') !== false) {
$label = str_replace( 'Express Shipping',' test express lbl', $label );
} elseif( strpos( $label, 'Free Standard Shipping') !== false) {
$label = str_replace( 'Free Standard Shipping',' test free lbl', $label );
}
return $label;
}
add_filter( 'woocommerce_cart_shipping_method_full_label', 'custom_shipping_labels', 10, 2 );
I use code that displays a custom field on the product edit page. This text box shows the cooking time on the single product page.
Here is the code:
// Backend: Display additional product fields
add_action( 'woocommerce_product_options_general_product_data', 'add_time_field_general_product_data' );
function add_time_field_general_product_data() {
// Custom Time Field
woocommerce_wp_text_input( array(
'id' => '_custom_time',
'label' => __( 'Time for cooking', 'woocommerce' ),
));
}
// Backend: Save the data value from the custom fields
add_action( 'woocommerce_admin_process_product_object', 'save_time_custom_fields_values' );
function save_time_custom_fields_values( $product ) {
// Save Custom Time Field
if( isset( $_POST['_custom_time'] ) ) {
$product->update_meta_data( '_custom_time', sanitize_text_field( $_POST['_custom_time'] ) );
}
}
// Display custom fields values under item name in checkout
add_filter( 'woocommerce_checkout_cart_item_quantity', 'custom_time_field_checkout_item_name', 10, 3 );
function custom_time_field_checkout_item_name( $item_qty, $cart_item, $cart_item_key ) {
if( $value4 = $cart_item['data']->get_meta('_custom_time') ) {
$item_qty .= '<br /><div class="my-custom-style"><strong>' . __("Time for cooking", "woocommerce") . ':</strong> ' . $value4 . ' min.</div>';
}
return $item_qty;
}
// Display custom fields values on orders and email notifications
add_filter( 'woocommerce_order_item_name', 'custom_time_field_order_item_name', 10, 2 );
function custom_time_field_order_item_name( $item_name, $item ) {
$product = $item->get_product();
if( $value4 = $product->get_meta('_custom_time') ) {
$item_name .= '<br /><span class="my-custom-style"><strong>' . __("Time for cooking", "woocommerce") . ':</strong> ' . $value4 . ' min.</span>';
}
return $item_name;
}
How can get the following functionality based on this code?
For example, a customer adds several dishes to a cart and checkout order. He sees how much time will be cooking this or that dish.
But when the customer chooses the delivery by courier (Flat Rate), in the same block, the delivery time is shown.
Flat Rate = $10
Delivery time = (the longest cooking time is selected from the order) min. + 45 min.
As I understand it, need to get the data of the custom field '_custom_time' when placing the order. Then, somehow need to get the highest value of this field and add 45 minutes.
I ask for your help! I hope that the answer to this question will be useful to many developers.
Try the following codethat will display a delivery time (calculated from the highest item cooking time value + 45 minutes) when a "flat rate" shipping method is selected on checkout page:
add_action( 'woocommerce_after_shipping_rate', 'action_after_shipping_rate_callback', 10, 2 );
function action_after_shipping_rate_callback( $method, $index ) {
$chosen_shipping_id = WC()->session->get( 'chosen_shipping_methods' )[$index];
if( is_checkout() && $method->method_id === 'flat_rate' && $method->id === $chosen_shipping_id ) {
$extra_time = 45; // Additional time to be added
$data_array = []; // Initializing
// Loop through car items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if( $cooking_time = $cart_item['data']->get_meta('_custom_time') ) {
$data_array[] = (int) $cooking_time;
}
}
if ( sizeof($data_array) ) {
$max_time = (int) max($data_array);
$delivery_time = $max_time + $extra_time;
echo '<br><small style="margin-left:2em;border:solid 1px #ccc;padding:2px 5px;"><strong>' . __("Delivery time", "woocommerce") . '</strong>: ' . $delivery_time . ' min.</small>';
}
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
To enable that in cart page too, remove is_checkout() && from the IF statement.