I'm looking to loop over all the products added to an order in the admin before the order is actually submitted. So far the only WooCommerce hooks I have found only allow you access the product items individually.
I was looking for a hook that would fire when a user clicks the recalculate button but actually it could trigger when a user adds a product, tax, shipping method, etc.. I just need to loop over all items added to the order so far.
At the moment I'm using woocommerce_admin_order_item_values hook but it's a self-contained loop so doesn't allow me to add all my '$item['product_id']' together.
function action_woocommerce_admin_order_item_values( $null, $item, $absint ) {
$item_ids = array($item['product_id']);
}
add_action( 'woocommerce_admin_order_item_values', 'action_woocommerce_admin_order_item_values', 10, 3 );
You can also use -
woocommerce_before_order_itemmeta Hook but this only accesses each item individually whereas I need to loop over each item in the summary.
There are number of hooks provided by WooCommerce, when you are clicking the Recalculate button. I'm listing here those hooks and it depends on you to choose among them according to your requirement.
$order = WC_Order object
add_action("woocommerce_order_before_calculate_taxes", "custom_order_before_calculate_taxes", 10, 2);
function custom_order_before_calculate_taxes($args, $order) {
// Do something
}
add_action("woocommerce_order_item_after_calculate_taxes", "custom_order_item_after_calculate_taxes", 10, 2);
function custom_order_item_after_calculate_taxes($order, $calculate_tax_for) {
// Do something
}
add_action("woocommerce_before_order_object_save", "custom_before_order_object_save", 10, 2);
function custom_before_order_object_save($order, $data_store) {
// Do something
}
add_action( 'woocommerce_order_before_calculate_totals', "custom_order_before_calculate_totals", 10, 2);
function custom_order_before_calculate_totals($and_taxes, $order ) {
// Do something
}
add_action( 'woocommerce_order_after_calculate_totals', "custom_order_after_calculate_totals", 10, 2);
function custom_order_after_calculate_totals($and_taxes, $order) {
//Do something
}
add_filter("woocommerce_order_is_vat_exempt", function(){
return $boolean;
});
add_filter("woocommerce_order_get_total", "custom_order_get_total", 10, 2);
function custom_order_get_total($value, $order) {
//do somethig
return $value;
}
Related
I've made a snippet to display the cart total in a shortcode. I use it at the checkout page (created a multistep checkout) before order validation.
add_shortcode( 'quote-total', 'get_quote_total' );
function get_quote_total(){
$total = WC()->cart->total;
return '<div>'.wc_price($total).'</div>';
}
// USAGE: [quote-total]
Now, I would like to use AJAX to make the amount change when there is new data, like shipping.
Do you know how can I achieve it ?
You should add some selector (e.g. class name) to your element:
return '<div class="step-cart-total">'.wc_price($total).'</div>';
Then you should be able to utilize woocommerce_add_to_cart_fragments filter like so:
function custom_woocommerce_add_to_cart_fragments( $fragments ) {
// Ajaxify checkout step cart total
ob_start();
$total = WC()->cart->total;
echo '<div class="step-cart-total">'.wc_price($total).'</div>';
$fragments['.step-cart-total'] = ob_get_clean();
return $fragments;
}
add_filter( 'woocommerce_add_to_cart_fragments', 'custom_woocommerce_add_to_cart_fragments');
I am working on a WooCommerce project. I need to add some entry based on ordered item in my custom table. If user ordered 3 items then those 3 entry will be place along with some data in my custom table.
For that I used woocommerce_checkout_order_processed hook. But I faced some issue, that if user adds 4 items in cart and on checkout page if user removed all items except one and finally ordered just 1 item then also in this hook I am getting all 4 items. I am not getting final ordered item in this hook.
So I changed the hook to woocommerce_thankyou . But in some case due to some reason user did not come on thank you page or on some credit card payment this hook did not work.
So can anyone tell me the best hook which can run after order place no matter if payment done or not and also I should get only ordered items. My WooCommerce version is 3+
Code :
function wc_function($order_id) {
global $wpdb;
$order = new WC_Order($order_id);
$items = $order->get_items();
foreach ($items as $item_line_id => $item) {
// Insert data in my custom table
}
}
//add_action('woocommerce_checkout_order_processed','wc_function', 10, 3);
//add_action('woocommerce_thankyou', 'wc_function', 10, 1);
Thank you !
do_action on woocommerce_checkout_order_processed passes exactly three args, third of which is the $order itself. So try using that instead:
function wc_function($order_id, $posted_data, $order) {
$items = $order->get_items();
foreach ($items as $item_line_id => $item) {
// Insert data in my custom table
}
}
add_action( 'woocommerce_checkout_order_processed', 'getswift_delivery_thankyou', 10, 1 );
add_action( 'woocommerce_thankyou', 'getswift_delivery_thankyou', 10, 1 );
You may use this hook it's working on my side... if you have any problems then discuss me we will solve them
I'm setting up a store that only sells to one city. I'm trying to figure out how I can restrict the city option to a pre-filled field.
I've already limited the country and using the following code in my functions.php:
add_filter( 'default_checkout_country', 'change_default_checkout_country' );
add_filter( 'default_checkout_state', 'change_default_checkout_state' );
function change_default_checkout_country() {
return 'PK'; // country code
}
function change_default_checkout_state() {
return 'SD'; // state code
}
And I've pre-selected the state using the following:
add_filter( 'woocommerce_states', 'bbloomer_custom_woocommerce_states' );
function bbloomer_custom_woocommerce_states( $states ) {
$states['PK'] = array(
'SD' => 'Sindh',
);
return $states;
}
But... Now comes the city and I am lost. I've tried using $fields['billing']['billing_city'] as well as $fields['billing']['billing_city']['value'] to no avail.
I want the customer to be limited to Karachi. I am not very familiar with WooCommerce filters, so I need help on achieving this.
Since woocommerce 3, default_checkout_country and default_checkout_state filter hooks are now deprecated and replaced.
Also in your last function, if you want to restrict just to one city, you should not include your city in the array of states. Instead you should return only one possible value.
So this will be your code:
// default checkout country
add_filter( 'default_checkout_billing_country', 'change_default_checkout_country' );
add_filter( 'default_checkout_shipping_country', 'change_default_checkout_country' );
function change_default_checkout_country() {
return 'PK'; // country code
}
// default checkout state
add_filter( 'default_checkout_billing_state', 'change_default_checkout_state' );
add_filter( 'default_checkout_shipping_state', 'change_default_checkout_state' );
function change_default_checkout_state() {
return 'SD'; // state code
}
// Setting one state only
add_filter( 'woocommerce_states', 'custom_woocommerce_state', 10, 1 );
function custom_woocommerce_state( $states ) {
// Returning a unique state
return array('PK' => array('SD' => 'Sindh'));
}
// Only one city at checkout
add_filter( 'woocommerce_checkout_fields', 'custom_checkout_fields', 10, 1 );
function custom_checkout_fields( $fields ) {
$fields['billing']['billing_city']['type'] = 'select';
$fields['billing']['billing_city']['options'] = array('Karachi' => 'Karachi');
$fields['shipping']['shipping_city']['type'] = 'select';
$fields['shipping']['shipping_city']['options'] = array('Karachi' => 'Karachi');
return $fields;
}
The Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works for wooCommerce versions 3+
Once added the code above and saved, you will need in WooCommerce > Settings > General to set locations this way:
Then you will get something like this on checkout:
Both dropdown have only one value… So you get what you are expecting.
I have been overriding the price of products dynamically based on specific criteria, but the ajax and mini-cart doesn't seem to see the price change when the product is getting added in the cart. It shows the original price total. I can override the prices in the cart itself no problem, but you have to be on the cart or checkout page to see it. Not sure what approach to take. I felt as though I've tried everything.
Seems as though $woocommerce->cart->get_cart_total() is called to display current cart total, but it doesn't seem to run add_action( 'woocommerce_before_calculate_totals', 'woo_add_discount'); hook when called.
If you go to the actual cart page, it is the proper pricing.
This code added will display the right individual price but not the subtotal. You have to refresh the cart page by clicking on the Cart URL for it to update the $woocommerce->cart->get_cart_total() object.
I've also tried add_action( 'woocommerce_before_mini_cart', 'woo_add_discount'); which does the same thing.. you have to refresh the page after loading. I'm sure I'm not the only one who had overriden prices and can't get all the peices to fall into place.
I've tried this and see that the second comment down on the answer, someone is having the same issue but no answers.
WooCommerce: Add product to cart with price override?
Try to use apply_filters instead of add_action
I ended up fixing this myself. I tried Paul de Koning's answer. Changing to apply_filters caused the prices to go to $0. I think this is because the order they need to go in.
Here was my solution. The root cause was that I was using the change price_html function to provide the change prices for the cart. Inside that function there were add_action calls etc. Somehow, there must have been an ordering issue. This is a multi step process to ensure all areas are done correctly.
If you want to change woocommerce prices without using sessions to store the changed price for the cart while changing the display price and hiding prices, perform something like the following:
functions.php
add_action('woocommerce_get_price_html','special_price');
function special_price($price) {
//put any if statements for hiding the cart button and discounting pricing below and return true or false
$displayprice = true;
$alterprice = true;
if($displayprice === true) {
add_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10, 2);
add_action( 'init', 'woocommerce_add_to_cart_action', 10);
add_action( 'init', 'woocommerce_checkout_action', 10 );
} else {
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10, 2);
remove_action( 'woocommerce_before_add_to_cart_form', 'woocommerce_template_single_product_add_to_cart', 10, 2); //
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
//return blank or something like 'Signup to view price'
return '';
}
//if you are displaying the price (altered)
if($displayprice === true && $alterprice === true){
$price = price_manipulator($theid);
return $price;
//display add to cart and price
}
//if you are displaying the price (unaltered)
return $price
}
function price_manipulator($theid = '') {
if(empty($theid)){
$theid = get_the_ID();
}
$product = wc_get_product($theid);
//30% off example
$newprice = floatval($product->price * (1-0.3));
return $newprice;
}
/*version of pricing if you are adding something to cart*/
function special_price_cart($theid){
$price = price_manipulator($theid);
return $price;
}
add_action( 'woocommerce_before_calculate_totals', 'woo_add_discount');
add_action( 'woocommerce_before_mini_cart', 'woo_add_discount'); //this is if you are using the mini-cart woocommerce widget
function woo_add_discount() {
global $woocommerce;
//create if statements same as if you were displaying the price
$displayprice = true;
if($displayprice === true){
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$price = special_price_cart($cart_item['data']->id);
$price = str_replace('$','',$price);
$price = str_replace(',','',$price);
if($price > 0){
$cart_item['data']->price = floatval($price);
}
}
}
}
I am making an ecommerce website using woocommerce, now I want to call a function after use fill the checkout form and submit it. Is there any filter or hooks that allow me to do that?
Or you can:
add_action( 'woocommerce_thankyou', array('Wc_class', 'my_uber_function'));
class Wc_class{
public static function my_uber_function($order_id)
{
stuff to do here
}
}
If you want to do something after WooCommerce order completed you can hook into woocommerce_order_status_completed.
add_action( 'woocommerce_order_status_completed', 'my_function' );
/*
* Do something after WooCommerce sets an order on completed
*/
function my_function($order_id) {
// order object (optional but handy)
$order = new WC_Order( $order_id );
// do some stuff here
}