Hide payment method if specific variation is in Checkout Page | Woocommerce - php

I'm using this code on my WordPress website to hide the payment gateway when a particular Product variation is selected. However, as soon as I insert the code, WordPress displays a Critical error from the backend. Kindly help me with how to use this code on my website?
Product attribute: Personalization Required
Variables: Yes| No
I want to achieve if someone selects a 'Yes' variation then COD options get disabled on the checkout page. Alternatively, if they select 'No' then only the cod option is available.
Product Page URL: https://savvyandgroovy.com/product/prashant/
This is what I am currently using:
add_filter(‘woocommerce_available_payment_gateways’, ‘conditional_payment_gateways’, 10, 1);
function conditional_payment_gateways($available_gateways)
{
$in_cart=false;
foreach(WC()->cart->get_cart_contents() as $key=>$values)
{
// See if there is an attribute called ‘pa_size’ in the cart
// Replace with whatever attribute you want
if(array_key_exists(‘personalization-required’, (array)$values[‘data’]->get_attributes()))
{
foreach($values[‘data’]->get_attributes() as $attribute=>$variation) ;
// Replace ‘small’ with your value.
if($variation==‘Yes’) $in_cart=true; //edited
}
}
if($in_cart)
unset($available_gateways[‘cod’]); // unset ‘cod’
return $available_gateways;
}

Your code is working properly but it is giving error because of quotes which you are using. I have updated it as bellow:
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
$in_cart = false;
if ( !empty(WC()->cart) ) {
foreach ( WC()->cart->get_cart_contents() as $key => $values ) {
// See if there is an attribute called ‘pa_size’ in the cart
// Replace with whatever attribute you want
//echo '<pre>';
//print_r($values['data']->get_attributes());
//echo '</pre>';
if (array_key_exists('personalization-required', (array) $values['data']->get_attributes() ) ) {
foreach ($values['data']->get_attributes() as $attribute => $variation);
// Replace ‘small’ with your value.
// if ($variation == 'No') $in_cart = true; //edited
if ($variation == 'Yes') {
$in_cart = true; //edited
// unset($available_gateways['cod']); // unset ‘cod’
}
}
}
if ( $in_cart )
unset($available_gateways['cod']); // unset ‘cod’
}
return $available_gateways;
}
I want to achieve if someone selects a 'NO' variation then cod options get disabled on the checkout page Alternatively, if they select 'YES' then only the cod option is available.
This will not work reverse in your code because you have written if ($variation == ‘Yes’) $in_cart = true; //edited so you need to update it also. So that also I have updated in above code.

The code above is not quite full since the OP wants to hide payment gateways in both scenarios so i just tweak the 1st answer a bit.
add_filter('woocommerce_available_payment_gateways', 'conditional_payment_gateways', 10, 1);
function conditional_payment_gateways( $available_gateways ) {
if( is_admin() )
return $available_gateways;
$hide_cod = $hide_rest = false;
foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if($cart_item["variation"]["attribute_pa_personalization-required"] === 'no') {
$hide_rest = true;
}
if($cart_item["variation"]["attribute_pa_personalization-required"] === 'yes') {
$hide_cod = true;
}
}
if($hide_cod) {
unset($available_gateways['cod']);
}
if($hide_rest) {
unset($available_gateways['bacs']);
unset($available_gateways['cheque']);
unset($available_gateways['ppcp-gateway']);
//etc
}
return $available_gateways;
}
Keep in mind that if you add both variations in cart youll be left with no payment method.

Related

Make "Ship to different address" mandatory if specific products are in WooCommerce cart [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I'm trying to add a snipped to activate the "Ship to other address" open by default, when a specific product is in the checkout.
I found Enable 'Ship to a different address' check box for specific products in Woocommerce related answer thread which is working perfectly!
However, it should not be possible to unselect the check box "Ship to other address". If a specific product is in the checkout, then providing a different shipping address is required.
Goal: Gray-out the "Ship to other address" checkbox for those specific products.
I just changed in the code $products_ids = array(10800, 11907); to feet my needs.
I already tried to unhook the function but then the whole code does not work. So I'm searching the best way to gray-out that checkbox but keep the code above fully working.
If I have understood, you want to keep your code functionality, disabling the checkbox.
The best thing is to hide the checkbox first. Then to avoid the shipping address to be shown or hidden by clicking on the checkbox label, jQuery will remove it when it is checked.
The php code (and inline CSS):
// Hide the checkbox (inline CSS) - Only on checkout page
add_filter( 'wp_head', 'shipping_address_checkbox_ccs' );
function shipping_address_checkbox_ccs() {
if( is_checkout() && ! is_wc_endpoint_url() ) {
?><style>body.checkout-hide-checkbox #ship-to-different-address-checkbox { display:none; } body.checkout-hide-checkbox #ship-to-different-address label { cursor: default; }</style><?php
}
}
// Conditional function
function mandatory_shipping_address(){
$products_ids = array(10800, 11907);
$found = $others_found = false;
foreach ( WC()->cart->get_cart() as $cart_item ){
if ( in_array( $cart_item['data']->get_id(), $products_ids ) ){
$found = true;
} else {
$others_found = true;
}
}
return $found && ! $others_found ? true : false;
}
// Conditionally Enable checkbox (checked)
add_filter( 'woocommerce_ship_to_different_address_checked', 'filter_cart_needs_shipping_address');
function filter_cart_needs_shipping_address( $checked ) {
return mandatory_shipping_address() ? true : $checked;
}
// Conditionally Add a body class - Only on checkout page
add_filter( 'body_class', 'shipping_address_checkbox_body_class' );
function shipping_address_checkbox_body_class( $classes ) {
if( is_checkout() && ! is_wc_endpoint_url() && mandatory_shipping_address() ) {
$classes[] = 'checkout-hide-checkbox';
}
return $classes;
}
The jQuery code:
// Remove the checkbox when is checked - Only on checkout page
add_action( 'template_redirect', 'cart_needs_shipping_address_js');
function cart_needs_shipping_address_js() {
if( is_checkout() && ! is_wc_endpoint_url() ) :
wc_enqueue_js( "jQuery( function($){
var a = '#ship-to-different-address-checkbox';
if( $(a).is(':checked') ) {
$(a).remove(); // Remove checkbox
}
});");
endif;
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
So when checkbox is checked you will get (for your defined products):
You could add a custom class to the checkout body tag when there are products in the cart.
So with a CSS rule you can hide the "Ship to a different address?" checkbox.
Using this answer:
Enable 'Ship to a different address' check box for specific products in Woocommerce
You can take the code and create a new custom function (returns the same result as before, the function has not been modified except the product ids):
function check_if_product_is_in_cart() {
$products_ids = array( 10800, 11907 );
$found = $others_found = false;
foreach ( WC()->cart->get_cart() as $cart_item ){
if (in_array( $cart_item['data']->get_id(), $products_ids ) ){
$found = true;
} else {
$others_found = true;
}
}
if ( $found && ! $others_found ) {
return true;
} else {
return false;
}
}
Then you can enable or disable the checkbox based on the result of the function:
add_filter( 'woocommerce_ship_to_different_address_checked', 'filter_cart_needs_shipping_address');
function filter_cart_needs_shipping_address( $checked ) {
return check_if_product_is_in_cart();
}
Finally you can use the same function to add the custom class to the checkout body tag:
add_filter( 'body_class', 'add_body_class' );
function add_body_class( $classes ) {
if ( ! is_checkout() ) {
return $classes;
}
if ( check_if_product_is_in_cart() ) {
$classes[] = 'hide_ship_to_different_address_checkbox';
}
return $classes;
}
At this point you just have to add the CSS rules in the style sheet of your active theme:
Make WooCommerce checkout shipping fields visible and remove "Ship to different address?" checkbox
The code has been tested and works. Add it to your active theme's functions.php.

Check if item is already in cart, if yes, then redirect user to checkout without adding product

I have a wordpress shop, where I sell digital products.
What the function should do:
User clicks add to cart button.
Function checks if the item is already in the cart.
If yes: Redirect user to checkout page without adding the product to cart (so the quantity doesn't change, it stays at 1).
If no: Redirect to checkout and add product to cart (quantity goes from 0 to 1).
What the function looks like:
add_filter('woocommerce_add_to_cart_validation', 'my_validation_handler', 10, 2);
function my_validation_handler($is_valid, $product_id) {
$url = WC()->cart->get_checkout_url();
foreach(WC()->cart->get_cart() as $cart_item_key => $values) {
if ($values['data']->id == $product_id) {
$url = WC()->cart->get_checkout_url();
wp_redirect($url);
exit();
}
else {
return $is_valid;
}
}
}
What happens:
When I implement the code in the functions.php of my child theme: (I already have the product in the cart) I click on the add to cart button again, but nothing happens.
If the cart is empty same thing, nothing happens, no reload nothing, I'm still on the products page.
Important detail:
I know there is a native WooCommerce function (sold seperately). But I have a custom products page and I don't want a message to appear that says "you already added that to cart".
Since I'm retargeting website visitors, the item is still in there sometimes from their last visit. And a expire session solution also not really what I'm looking for.
You can use the following, explanation as comment lines in the code
function my_validation_handler( $passed, $product_id, $quantity, $variation_id = null, $variations = null ) {
// Get checkout url
$checkout_url = wc_get_checkout_url();
// Set variable
$in_cart = false;
// Loop
foreach( WC()->cart->get_cart() as $cart_item ) {
if ( $cart_item['data']->get_id() == $product_id ) {
$in_cart = true;
break;
}
}
// True
if ( $in_cart ) {
wp_safe_redirect( $checkout_url );
exit();
} else {
// Add product to cart
WC()->cart->add_to_cart( $product_id, $quantity );
wp_safe_redirect( $checkout_url );
exit();
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'my_validation_handler', 10, 5 );

How can I set tabs if the New product is in a certain type

In the Woocommerce Admin Tab for Products,
I want the product tabs to reflect a custom layout when a user adds a new product.
Now I have working code for when a product exits but I want this to reflect also when a user clicks to add a new product (you know the screen before the product is inserted into the database? )
So this is the working code I'm testing with
function Reboot_remove_linked_products($tabs){
global $post;
$Product_is_what_Im_looking_for=false;
if ( is_product() && has_term( 'Forensic Evidence', 'product_cat' ) ) {
$Product_is_what_Im_looking_for= true;
}elseif( is_product() && has_category( 'Forensic Evidence' ) ) {
$Product_is_what_Im_looking_for= true;
}
if ($Product_is_what_Im_looking_for== true){
unset($tabs['general']);
unset($tabs['inventory']);
unset($tabs['shipping']);
unset($tabs['linked_product']);
unset($tabs['attribute']);
unset($tabs['advanced']);
}
return($tabs);
}
add_filter('woocommerce_product_data_tabs', 'Reboot_remove_linked_products', 10, 1);
May be you should change priority of that hook like this:-
add_filter('woocommerce_product_data_tabs', 'Reboot_remove_linked_products', 999, 1);
For the new screen, you have to check whether product is published or not.
UPDATED Code:-
function Reboot_remove_linked_products($tabs){
global $post;
$Product_is_what_Im_looking_for=false;
if ( is_product() && has_term( 'Forensic Evidence', 'product_cat' ) ) {
$Product_is_what_Im_looking_for= true;
}elseif( is_product() && has_category( 'Forensic Evidence' ) ) {
$Product_is_what_Im_looking_for= true;
} elseif('publish' === get_post_status( $post->ID )) {
$Product_is_what_Im_looking_for= true;
}
if ($Product_is_what_Im_looking_for== true){
unset($tabs['general']);
unset($tabs['inventory']);
unset($tabs['shipping']);
unset($tabs['linked_product']);
unset($tabs['attribute']);
unset($tabs['advanced']);
}
return($tabs);
}
add_filter('woocommerce_product_data_tabs', 'Reboot_remove_linked_products', 999, 1);
So took too long to figure this out but the answer is surprisingly simple and was actually in the Woocommerce documentation ..
function Reboot_remove_linked_products($tabs){
$tabs['inventory']['class'][] = 'hide_if_forensic_evidence';
$tabs['shipping']['class'][] = 'hide_if_forensic_evidence';
$tabs['linked_product']['class'][] = 'hide_if_forensic_evidence';
$tabs['attribute']['class'][] = 'hide_if_forensic_evidence';
$tabs['advanced']['class'][] = 'hide_if_forensic_evidence';
return($tabs);
}
add_filter('woocommerce_product_data_tabs', 'Reboot_remove_linked_products', 10, 1);
So what is going on you ask?
So the tabs in standard form are never unset when switching product types according to Woo.
They have built in functions to hide the tab based on the product type selected.
so ALL you have to do is add a class called "hide_if" with your custom product type.
So in my case it's "hide_if_forensic_evidence".
You do this to all the tabs you want "disabled"
Woo will automatically know to hide those tabs when your product type is selected.

WooCommerce 502 Bad gateway when using add_to_cart function

As the title says, I'm getting Error 502 Bad Gateway when I try to use the standard function add_to_cart() from WooCommerce
WC()->cart->add_to_cart( 8622 );
Any ideas what's going on? I also tried adding more arguments to the function such as the quantity and etc but doesn't seems to change anything...
WooCommerce documentation: https://docs.woocommerce.com/wc-apidocs/class-WC_Cart.html
Okay, I have managed to fix this by making another function to be called in the function.php file. I am not sure why this works now since it's the same concept, except that the function is now called from the functions.php file from the theme.
Here's the code for anyone that needs this:
// Add item to cart
function add_id_to_cart( $product_id ) {
$flag = true;
//check if product already in cart
foreach(WC()->cart->get_cart() as $key => $val ) {
$_product = $val['data'];
if($product_id == $_product->id ) {
$flag = false;
}
}
// if product not in cart, add it
if ( $flag ) {
WC()->cart->add_to_cart( $product_id );
}
}

Hide payment method based on product meta in Woocommerce

We are using this WooCommerce Custom Fields commercial plugin on our Woocommerce e-shop for individual customization of our products and I am trying to find a way how to hide payment method if key 'wccf' is in product meta.
I am trying to upgrade a code below, I want to replace shipping country checking, but I don't know how to get and check 'wccf' key.
function payment_gateway_disable_country( $available_gateways ){
global $woocommerce;
if (isset($available_gateways['cod']) && $woocommerce->customer->get_shipping_country() <> 'IT'){
unset($available_gateways['cod']);
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_country');
Does anybody can you help me?
Try with below code. Put the code in functions.php
function payment_gateway_disable_country($available_gateways){
global $woocommerce;
if (isset($available_gateways['cod']) && $woocommerce->customer->get_shipping_country() <> 'IT'){
//fetching the cart
$session_data = WC()->session->get('wccf');
if(!empty($session_data)){
unset($available_gateways['cod']);
}
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_country');
Something like the following in your filter should do it, assuming the product has a wccf entry in its meta data.
function payment_gateway_disable_wccf($available_gateways){
$cart = WC()->cart;
if( $cart ){
foreach($cart->get_cart() as $currItem){
if( get_post_meta($currItem['product_id'], 'wccf', true) )
unset($available_gateways['cod']);
}
}
return $available_gateways;
}
add_filter('woocommerce_available_payment_gateways', 'payment_gateway_disable_wccf');
Thank you all for your support and help! Finally, plugin developer send me a code which solved my problem.
$cart = WC()->cart->get_cart();
$wccf_is_set = false;
foreach ($cart as $cart_item) {
if (isset($cart_item['wccf'])) {
// mark that there's data set
$wccf_is_set = true;
}
}
if ($wccf_is_set === true) {
// do what you need if the data is set
}

Categories