Add message below shipping methods based on taxonomy terms in WooCommerce - wordpress

I'd like to add a custom message below the available shipping methods in the cart, but only if ALL products in the cart have a tag named 'express'.
Therefore I use this snippet:
add_action( 'woocommerce_after_shipping_rate', 'action_after_shipping_rate', 20, 2 );
function action_after_shipping_rate ( $method, $index ) {
if( 'flat_rate:1' === $method->id ) {
echo __("<p>Arriving on your chosen date between 9am - 1pm Perfect for business addresses & special occasions</p>");
}
if( 'flat_rate:2' === $method->id ) {
echo __("<p>Arriving on your chosen date between 9am - 7pm Perfect for residential addresses</p>");
}
}
add_filter( 'woocommerce_shipping_details', 'hide_shipping_details', 10, 2 );
function hide_shipping_details( $rates, $package ) {
$terms = array( 'express' );
$taxonomy = 'product_tag';
$found = false;
foreach( $package['contents'] as $cart_item ) {
if ( !has_term( $terms, $taxonomy, $cart_item['product_id'] ) ){
$found = true;
break;
}
}
if ( $found === false ) {
remove_action( 'woocommerce_after_shipping_rate', 'action_after_shipping_rate', 20, 2 );
}
}
But right now, the custom message remains if 1 or 2 products have the tag 'express' but not ALL products. Can someone help me solve this problem?

No need to call from one hook to another, while you can just loop through all the products in cart in the woocommerce_after_shipping_rate hook
So you get:
function action_woocommerce_after_shipping_rate( $method, $index ) {
// Settings
$terms = array( 'express', 'tag-1' );
$taxonomy = 'product_tag';
// Initialize
$flag = false;
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Checks if the current product has NOT any of given terms
if ( ! has_term( $terms, $taxonomy, $cart_item['product_id'] ) ) {
$flag = true;
break;
}
}
// When false
if ( ! $flag ) {
// Compare
if ( $method->get_id() === 'flat_rate:1' ) {
$text = 'My text 1';
} elseif ( $method->get_id() === 'flat_rate:3' ) {
$text = 'My text 2';
} elseif ( $method->get_id() === 'local_pickup:1' ) {
$text = 'My text 3';
}
// When isset
if ( isset( $text ) ) {
// Output
echo '<p>' . sprintf( __( '%s', 'woocommerce' ), $text ) . '</p>';
}
}
}
add_action( 'woocommerce_after_shipping_rate', 'action_woocommerce_after_shipping_rate', 10, 2 );

Related

How to find out the cheapest shipping method and change the shipping label in woocommerce?

So here's what I need to do: find out the cheapest shipping method and change the "Free Shipping" method label to "Free Shipping" + "Cheapest method label". This way the customer will be able to know what is the shipping method used for the free shipping.
First I thought about global variables.. then used the wp_options, but I am not certain if the wp_options are user shared or user-specific data.
Would you have any good ideas or corrections on the following code, which by the way isn't working? Thanks!
add_filter( 'woocommerce_shipping_chosen_method', 'wf_default_shipping_method', 10 );
function wf_default_shipping_method( $method ) {
$the_cheapest_cost = 1000000;
$packages = WC()->shipping()->get_packages()[0]['rates'];
foreach ( array_keys( $packages ) as $key ) {
if ( ( $packages[$key]->cost > 0 ) && ( $packages[$key]->cost < $the_cheapest_cost ) ) {
$the_cheapest_cost = $packages[$key]->cost;
$transport_label = $packages[$key]->label;
$method_id = $packages[$key]->id;
}
}
if(get_option('atransport')){
update_option('atransport', $transport_label);
}else{
add_option('atransport', $transport_label);
}
return $method_id;
}
add_filter( 'woocommerce_package_rates', 'change_shipping_methods_label_names', 20, 2 );
function change_shipping_methods_label_names( $rates, $package ) {
$transport = get_option('atransport');
foreach( $rates as $rate_key => $rate ) {
if ( __( 'Free Shipping', 'woocommerce' ) == $rate->label ){
$rates[$rate_key]->label = __( 'FreeShipping -' . $transport, 'woocommerce' ); // New label name
}
}
delete_option('atransport');
return $rates;
}
You can iterate a loop of $rates and get the cheapest method. then based on the found cheapest method you can change the label. code will go in your active theme functions.php file.
add_filter( 'woocommerce_package_rates', 'hide_other_shipping_when_free_is_available', 100, 1 );
function hide_other_shipping_when_free_is_available( $rates ) {
$cheapest_method = '';
// Loop through shipping rates
if ( is_array( $rates ) ) {
foreach ( $rates as $key => $rate ) {
// Set variables when the rate is cheaper than the one saved
if ( empty( $cheapest_method ) || $rate->cost < $cheapest_method->cost ) {
$cheapest_method = $rate;
}
}
}
// Return the cheapest rate when possible
if ( ! empty( $cheapest_method ) ) {
$free = array();
foreach ( $rates as $rate_id => $rate ) {
if ( $rate->id === $cheapest_method->id ) {
if ( __( 'Free Shipping', 'woocommerce' ) == $rate->label ){
$rates[ $rate_id ] = $rate;
// Here we append the labbelled saved price formated display
$rates[ $rate_id ]->label = 'Free Shipping '.$rates[ $rate_id ]->label;
break; // stop the loop
}
}
}
return $rates;
}
return $rates;
}
Tested and works

If WoooCommerce Product Is In Cart Show Message on Product Page with Cart Count

I am trying to, based on if one or more product is in the cart, to display a custom DIV-tag with a cart count before the product.
It works, but the count does not work. Why?
This is my code:
add_action('woocommerce_before_single_product', 'product_count', 1, 1 );
function product_count( $cart ) {
if ( is_admin() && !defined( 'DOING_AJAX' ) ) return;
global $product;
$product_count = $cart->cart_contents_count;
$product_ids = array( 1708 );
$in_cart = false;
foreach( WC()->cart->get_cart() as $cart_item ) {
$product_in_cart = $cart_item['product_id'];
if ( in_array( $product_in_cart, $product_ids ) ) {
$in_cart = true;
break;
}
}
if ( ! $in_cart ) {
return;
} else {
echo '<div class="product-count">You have added a total of '.$product_count.' products.</div>';
}
}

Disable payment gateway when specific products in WooCommerce cart

I want to unset the payment method 'bacs' for the product ID 6197.
I have tried the code below, but this does not have the desired result.
add_filter( 'woocommerce_available_payment_gateways', 'wp_unset_gateway_by_id', 10, 2 );`
function wp_unset_gateway_by_id( $available_gateways, $products) {
global $woocommerce;
$unset = false;
$product_ids = array('6197');
if( in_array( $product->get_id(), $product_ids ) || ( $product->is_type('variation') && in_array( $product->get_parent_id(), $product_ids ) ) ){
unset( $available_gateways['bacs'] );
return $available_gateways;
}
}
I believe I am doing something wrong, but I am relatively new to this. Any advice would be appreciated.
$products is not passed as argument to the woocommerce_available_payment_gateways filter hook
Apply it in the following way:
function filter_woocommerce_available_payment_gateways( $payment_gateways ) {
// Not on admin
if ( is_admin() ) return $payment_gateways;
// The targeted product ids (several can be added, separated by a comma)
$targeted_ids = array( 6197 );
// Flag
$found = false;
// WC Cart
if ( WC()->cart ) {
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
if ( array_intersect( $targeted_ids, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
$found = true;
break;
}
}
}
// True
if ( $found ) {
// Bacs
if ( isset( $payment_gateways['bacs'] ) ) {
unset( $payment_gateways['bacs'] );
}
}
return $payment_gateways;
}
add_filter( 'woocommerce_available_payment_gateways', 'filter_woocommerce_available_payment_gateways', 10, 1 );

How to rename the Add to Cart button if the product is already added to cart in WooCommerce

When Ajax add to cart functionality is active on my WooCommerce store, on Ajax add to cart first click It shows a checked icon symbol like:
The code below changes the add to button cart text to "Seçildi !" if product is already in to cart, only after refreshing page like:
//Rename the button on the Product page
add_filter( 'woocommerce_product_single_add_to_cart_text', 'ts_product_add_cart_button' );
function ts_product_add_cart_button( $label ) {
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$product = $values['data'];
if( get_the_ID() == $product->get_id() ) {
$label = __('Seçildi !', 'woocommerce');
}
}
return $label;
}
//Rename the button on the Shop page
add_filter( 'woocommerce_product_add_to_cart_text', 'ts_shop_add_cart_button', 99, 2 );
function ts_shop_add_cart_button( $label, $product ) {
if ( $product->get_type() == 'simple' && $product->is_purchasable() && $product->is_in_stock() )
{
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if( get_the_ID() == $_product->get_id() ) {
$label = __('Seçildi !', 'woocommerce');
}
}
}
return $label;
}
But if you don't refresh the page the button remains like before with the checked icon symbol.
What I would like is to change add to cart button with the quantity that has been added for this product like:
Is this possible? What do I need to change? Any help is appreciated.
You can use WC woocommerce_product_add_to_cart_text action hook and you can get wc cart loop through all products and compare path second params $prodcuct object. check below code. code will go active theme functions.php file.
function change_add_to_cart_text_if_product_already_in_cart( $add_to_cart_text, $product ) {
if ( WC()->cart ) {
$cart = WC()->cart; // Get cart
if ( ! $cart->is_empty() ) {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$_product_id = $cart_item['product_id'];
if ( $product->get_id() == $_product_id ) {
$add_to_cart_text = '('.$cart_item['quantity'].')'.' Already in cart';
break;
}
}
}
}
return $add_to_cart_text;
}
add_filter( 'woocommerce_product_add_to_cart_text', 'change_add_to_cart_text_if_product_already_in_cart', 10, 2 );
add_filter( 'woocommerce_product_single_add_to_cart_text', 'change_add_to_cart_text_if_product_already_in_cart', 10, 2 );
Updated ( as per OP request how to change text quick on click with quantity ).
There is two way You can do this.
you can use woocommerce_loop_add_to_cart_args and add product qty attribute and based on that you can display.
function add_product_qty( $args, $product ){
if ( WC()->cart ) {
$cart = WC()->cart; // Get cart
if ( ! $cart->is_empty() ) {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$_product_id = $cart_item['product_id'];
if ( $product->get_id() == $_product_id ) {
$args['attributes']['data-product-qty'] = $cart_item['quantity'];
}else{
$args['attributes']['data-product-qty'] = 0;
}
}
}else{
$args['attributes']['data-product-qty'] = 0;
}
}
return $args;
}
add_filter( 'woocommerce_loop_add_to_cart_args', 'add_product_qty', 10, 2 );
add_action( 'wp_footer', 'ajax_button_text_quick_change_js_script' );
function ajax_button_text_quick_change_js_script() {
?>
<script>
(function($) {
$(document.body).on('click', '.ajax_add_to_cart', function(event){
$this = $(this);
var product_qty = parseInt($this.attr('data-product-qty')) + 1;
$this.attr('data-product-qty',product_qty);
var buttonText = '<span class="add_to_cart_text product-is-added">('+product_qty+') Already in cart</span><i class="cart-icon pe-7s-cart"></i>';
$this.html(buttonText).attr('data-tip','('+product_qty+') Already in cart');
});
})(jQuery);
</script>
<?php
}
You can use added_to_cart jQuery event that triggers after adding to the cart you call ajax and get add_to_cart_text in response.
add_action( 'wp_footer', 'ajax_button_text_js_script' );
function ajax_button_text_js_script() {
?>
<script>
(function($) {
$(document.body).on('added_to_cart', function(event, fragments, cart_hash, button){
var product_id = button.data('product_id'),
product_qty = button.data('quantity');
button.addClass('loading');
$.ajax({
url: "<?php //echo admin_url('admin-ajax.php'); ?>",
method: 'POST',
data:{action:'change_add_to_cart_text',product_id:product_id},
dataType: "json",
success: function( response ){
var buttonText = '<span class="add_to_cart_text product-is-added">'+response.data.button_text+'</span><i class="cart-icon pe-7s-cart"></i>';
button.html(buttonText).attr('data-tip',response.data.button_text);
button.removeClass('loading');
},error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
console.log(msg);
},
});
});
})(jQuery);
</script>
<?php
}
add_action('wp_ajax_change_add_to_cart_text', 'change_add_to_cart_text');
add_action('wp_ajax_nopriv_change_add_to_cart_text', 'change_add_to_cart_text');
function change_add_to_cart_text(){
$product_id = $_POST['product_id'];
if ( WC()->cart ) {
$cart = WC()->cart; // Get cart
if ( ! $cart->is_empty() ) {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$_product_id = $cart_item['product_id'];
if ( $product_id == $_product_id ) {
$add_to_cart_text = '('.$cart_item['quantity'].')'.' Already in cart';
break;
}
}
}
}
wp_send_json_success(array(
'button_text' => $add_to_cart_text
));
}
This below code only for OP site.
add_filter( 'woocommerce_loop_add_to_cart_link', 'custom_add_quantity_fields', 99, 2 );
function custom_add_quantity_fields($html, $product) {
//add quantity field only to simple products
if ( $product && $product->is_type( 'simple' ) && $product->is_purchasable() && $product->is_in_stock() && ! $product->is_sold_individually() ) {
if ( WC()->cart ) {
$cart = WC()->cart; // Get cart
if ( ! $cart->is_empty() ) {
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$_product_id = $cart_item['product_id'];
if ( $product->get_id() == $_product_id ) {
$data_product_qty = $cart_item['quantity'];
}else{
$data_product_qty = 0;
}
}
}else{
$data_product_qty = 0;
}
}
//rewrite form code for add to cart button
$html = '<form action="' . esc_url( $product->add_to_cart_url() ) . '" class="cart" method="post" enctype="multipart/form-data">';
$html .= woocommerce_quantity_input( array(), $product, false );
$html .= '<button type="submit" data-quantity="1" data-product_id="' . $product->get_id() . '" class="button alt ajax_add_to_cart add_to_cart_button product_type_simple" data-product-qty="'.$data_product_qty.'">' . esc_html( $product->add_to_cart_text() ) . '</button>';
$html .= '</form>';
}
return $html;
}
Tested and works.

Checkbox field that add a subscription product and change prices of other products

In Woocommerce checkout section, I am trying to add a checkbox that adds an additional subscription product. It is working fine and I took help from here
One more requirement is that if there are other products in the cart then I want to change each product prices based on custom fields and new prices should display in the checkout.
Thanks in advance.
I used this code and working fine but product price is not changing in PayPal payment page.
// Display a custom checkout field
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'custom_checkbox_checkout_field' );
function custom_checkbox_checkout_field() {
$value = WC()->session->get('add_a_product');
woocommerce_form_field( 'cb_add_product', array(
'type' => 'checkbox',
'label' => ' ' . __('Please check here to get VIP Membership'),
'class' => array('form-row-wide'),
), $value == 'yes' ? true : false );
}
// The jQuery Ajax request
add_action( 'wp_footer', 'checkout_custom_jquery_script' );
function checkout_custom_jquery_script() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
// Remove "ship_different" custom WC session on load
if( WC()->session->get('add_a_product') ){
WC()->session->__unset('add_a_product');
}
if( WC()->session->get('product_added_key') ){
WC()->session->__unset('product_added_key');
}
// jQuery Ajax code
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on( 'change', '#cb_add_product', function(){
var value = $(this).prop('checked') === true ? 'yes' : 'no';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'add_a_product',
'add_a_product': value,
},
success: function (result) {
$('body').trigger('update_checkout');
//console.log(result);
}
});
});
});
</script>
<?php
endif;
}
// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_add_a_product', 'checkout_ajax_add_a_product' );
add_action( 'wp_ajax_nopriv_add_a_product', 'checkout_ajax_add_a_product' );
function checkout_ajax_add_a_product() {
if ( isset($_POST['add_a_product']) ){
WC()->session->set('add_a_product', esc_attr($_POST['add_a_product']));
echo $_POST['add_a_product'];
}
die();
}
// Add remove free product
add_action( 'woocommerce_before_calculate_totals', 'adding_removing_specific_product' );
function adding_removing_specific_product( $cart ) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// HERE the specific Product ID
$product_id = 179;
if( WC()->session->get('add_a_product') == 'yes' && ! WC()->session->get('product_added_key') )
{
foreach ( $cart->get_cart() as $cart_item ) {
$cart_item_key = $cart->add_to_cart( $product_id );
WC()->session->set('product_added_key', $cart_item_key);
// get the product id (or the variation id)
$product_id = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = get_post_meta( $product_id, 'pro_price_extra_info', true );
// Updated cart item price
$cart_item['data']->set_price( floatval( $new_price ) );
}
}
elseif( WC()->session->get('add_a_product') == 'no' && WC()->session->get('product_added_key') )
{
$cart_item_key = WC()->session->get('product_added_key');
$cart->remove_cart_item( $cart_item_key );
WC()->session->__unset('product_added_key');
}
}
I got solution for my above post. It might help others in future.
// Display a custom checkout field
add_action( 'woocommerce_checkout_before_terms_and_conditions', 'custom_checkbox_checkout_field' );
function custom_checkbox_checkout_field() {
$value = WC()->session->get('add_a_product');
woocommerce_form_field( 'cb_add_product', array(
'type' => 'checkbox',
'label' => ' ' . __('Please check here to get VIP Membership'),
'class' => array('form-row-wide'),
), $value == 'yes' ? true : false );
}
// The jQuery Ajax request
add_action( 'wp_footer', 'checkout_custom_jquery_script' );
function checkout_custom_jquery_script() {
// Only checkout page
if( is_checkout() && ! is_wc_endpoint_url() ):
// Remove "ship_different" custom WC session on load
if( WC()->session->get('add_a_product') ){
WC()->session->__unset('add_a_product');
}
if( WC()->session->get('product_added_key') ){
WC()->session->__unset('product_added_key');
}
// jQuery Ajax code
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on( 'change', '#cb_add_product', function(){
var value = $(this).prop('checked') === true ? 'yes' : 'no';
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'add_a_product',
'add_a_product': value,
},
success: function (result) {
$('body').trigger('update_checkout');
//console.log(result);
}
});
if(value == 'no'){
window.location.reload();
}
});
});
</script>
<?php
endif;
}
// The Wordpress Ajax PHP receiver
add_action( 'wp_ajax_add_a_product', 'checkout_ajax_add_a_product' );
add_action( 'wp_ajax_nopriv_add_a_product', 'checkout_ajax_add_a_product' );
function checkout_ajax_add_a_product() {
if ( isset($_POST['add_a_product']) ){
WC()->session->set('add_a_product', esc_attr($_POST['add_a_product']));
echo $_POST['add_a_product'];
}
die();
}
// Add remove free product
add_action( 'woocommerce_before_calculate_totals', 'adding_removing_specific_product' );
function adding_removing_specific_product( $cart ) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
$has_sub = wcs_user_has_subscription( '', '179', 'active' );
$product_id = 179;
if( WC()->session->get('add_a_product') == 'yes' && ! WC()->session->get('product_added_key') ){
// HERE the specific Product ID
foreach ( $cart->get_cart() as $cart_item ) {
// get the product id (or the variation id)
$product_idnew = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = get_post_meta( $product_idnew, 'pro_price_extra_info', true );
$old_price = $cart_item['data']->get_price();
if($new_price == NULL){
$cart_item['data']->set_price( floatval( $old_price ) );
} else {
$cart_item['data']->set_price( floatval( $new_price ) );
}
}
$cart_item_key = $cart->add_to_cart( $product_id );
WC()->session->set('product_added_key', $cart_item_key);
} elseif( WC()->session->get('add_a_product') == 'no' && WC()->session->get('product_added_key') ) {
$cart_item_key = WC()->session->get('product_added_key');
$cart->remove_cart_item( $cart_item_key );
WC()->session->__unset('product_added_key');
}elseif ( $has_sub ) {
foreach ( $cart->get_cart() as $cart_item ) {
// get the product id (or the variation id)
$product_idnew = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = get_post_meta( $product_idnew, 'pro_price_extra_info', true );
$cart_item['data']->set_price( floatval( $new_price ) );
}
}
}
function woo_in_cart($product_id) {
global $woocommerce;
foreach($woocommerce->cart->get_cart() as $key => $val ) {
$_product = $val['data'];
if($product_id == $_product->id ) {
return true;
}
}
return false;
}
add_action( 'woocommerce_cart_loaded_from_session', 'adding_vip_product' );
function adding_vip_product( $cart ) {
$product_id = 179;
if(woo_in_cart($product_id) ) {
foreach ( $cart->get_cart() as $cart_item ) {
// get the product id (or the variation id)
$product_idnew = $cart_item['data']->get_id();
// GET THE NEW PRICE (code to be replace by yours)
$new_price = get_post_meta( $product_idnew, 'pro_price_extra_info', true );
if($new_price != 0){
$cart_item['data']->set_price( floatval( $new_price ) );
}
}
}
}

Resources