Hide payment method based on product meta in Woocommerce - php

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
}

Related

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

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.

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.

Remove some payment gateways if any coupon code is applied in Woocommerce

I started to work on small Woocommerce project. I have 3 payment gateways into this store: Paypal, Credit Card and Direct bank Transfer.
What I would like is: If coupon code is used, I would like to disable (or remove) Paypal and Credit Card from available payment gateways, and just keep "Direct bank Transfer" as available payment gateway choice.
To show how is look current state from checkout page:
I found a similar solution, but this is for removing gateway based on product category.
add_filter( 'woocommerce_available_payment_gateways', 'unset_payment_gateways_by_category' );
function unset_payment_gateways_by_category( $available_gateways ) {
global $woocommerce;
$unset = false;
$category_ids = array( 8, 37 );
foreach ( $woocommerce->cart->cart_contents as $key => $values ) {
$terms = get_the_terms( $values['product_id'], 'product_cat' );
foreach ( $terms as $term ) {
if ( in_array( $term->term_id, $category_ids ) ) {
$unset = true;
break;
}
}
}
if ( $unset == true )
unset( $available_gateways['cheque'] );
return $available_gateways;
}
So I think that this function can be used, but slightly modified per my problem.
Any help is appreciated.
The following code will remove all payment gateways except "Direct bank Transfer" (bacs) only if at least one coupon code has been applied by the customer:
add_filter('woocommerce_available_payment_gateways', 'applied_coupons_hide_payment_gateways', 20, 1 );
function applied_coupons_hide_payment_gateways( $available_gateways){
// Not in backend (admin)
if( is_admin() )
return $available_gateways;
// If at least a coupon is applied
if( sizeof( WC()->cart->get_applied_coupons() ) > 0 ){
// Loop through payment gateways
foreach ( $available_gateways as $gateway_id => $gateway ) {
// Remove all payment gateways except BACS (Bank Wire)
if( $gateway_id != 'bacs' )
unset($available_gateways[$gateway_id]);
}
}
return $available_gateways;
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
here you go :
add_filter('woocommerce_available_payment_gateways', 'unset_gatway_by_applied_coupons');
function unset_gatway_by_applied_coupons($available_gateways)
{
$coupons = WC()->cart->applied_coupons;
if (!empty($coupons)) {
unset($available_gateways['bacs']);
}
return $available_gateways;
}
what we did here we checked if any coupons is applied trough WC()->cart->applied_coupons; which will return an array of coupons if coupons array not empty remove specific payment gateway
if you want to check if certain coupon is applied and remove gatway based on your condition you can use the following:
add_filter('woocommerce_available_payment_gateways', 'unset_gatway_by_applied_coupons');
function unset_gatway_by_applied_coupons($available_gateways)
{
$coupons = WC()->cart->applied_coupons;
foreach ($coupons as $coupon) {
if ($coupon == 'my_coupon') { //here you can specific your coupon name
unset($available_gateways['bacs']);
}
}
return $available_gateways;
}
of course both functions are tested, you just need to place them in your functions.php

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 );
}
}

Conditionally making WooCommerce product non purchasable

I've been struggling with a snippet for WooCommerce that I'd like to add to my child's theme functions but I am reaching the limits of my PHP knowledge.
I have set a custom attribute called pdt_volume, that I will fill everytime I add a product. I would like to remove the Add_to_cart button when the sum of this attribute for all the items already in the cart have reach a max_volume limit.
For example, the Max_volume is 100, I have 4 products of pdt_volume = 20, therefore, the add_to_cart button for a product with a pdt_volume of 25 should be removed so that I cannot add it to the cart.
So I have come up with this snippet, with bits of code found here and there.
But the functions.php won't save it, and others variations of this code has succeeded to register in the functions.php but the website would then give a 500 error...
Please, does someone has any idea how to achieve this?
What am I doing wrong?
Thanks.
EDIT 1 : Alright, so I got this code to actually be registered in the functions.php by the editor without breaking, but on the site, I still get the internal server error. Like something is not computing or something.
EDIT 2 (29/01/2017)
I used the ACF plugin I had purchased a long time ago but didn't find any suitable purpose... so far.
Here is the working code I was able to come up with. This is not a code masterpiece and I won't get any award for this, but it seems to be working so far. At least, it allows me to get a TRUE/FALSE statement that I can use in a if condition to change the add_to_cart button to a Your_box_is_full button.
Indeed, I didn't need any global $woocommerce or $product !
function get_cart_volume() {
$cart_volume = 0;
foreach( WC()->cart->get_cart() as $cart_item ) {
$item_id = $cart_item['product_id'];
$item_volume = get_field('product_volume', $item_id);
$item_qty = $cart_item['quantity'];
$vol_by_qty = $item_volume * $item_qty;
$cart_volume += $vol_by_qty;
}
return $cart_volume;
}
function check_if_full($candidate) {
$max_volume = 100;
$candidate = $product->id;
$a_volume = get_field('product_volume', $candidate);
$b_volume = get_cart_volume();
$check_volume = $a_volume + $b_volume;
if ($check_volume > $max_volume)
return true;
else
return false;
}
//Just a function to see if it's working on the cart page fur debugging purpose
add_action( 'woocommerce_check_cart_items', 'current_volume');
function current_volume() {
if (is_cart() || is_checkout()) {
global $woocommerce;
$current_volume = get_cart_volume();
wc_add_notice( sprintf( '<strong>Volume is %s.</strong>', $current_volume ),
'error' );
}
}
As Helgatheviking says, you get already, with woocommerce_is_purchasable hook in your hooked function, the $product object as 2nd argument. So you don't need and you have to remove global $woocommerce, $product; to make it work without throwing an error.
Your code is going to be:
add_filter('woocommerce_is_purchasable', 'if_room_is_purchasable', 10, 2);
function if_room_is_purchasable ($is_purchasable, $product){
$cart_volume = 0;
$max_volume = 100;
foreach( WC()->cart->get_cart() as $cart_item ){
$item_id = $cart_item['product_id'];
$terms = get_the_terms( $item_id, 'pa_pdt_volume');
foreach($terms as $key => $term){
$cart_volume += $term->name; // May be better with $term->slug;
}
}
$candidate_volume = $cart_volume + $product->get_attribute( 'pa_pdt_volume' );
if ( $candidate_volume > $max_volume )
return false;
else
return true;
}
This should work now without error.

Categories