WooCommerce Checkout - wordpress

I'm creating a plugin for WooCommerce to modify the Checkout page. I would like to do some conditional filters based on the users shopping cart. Is there a way to look at the items in the shopping cart, and determine if any of the items are NOT downloadable/virtual?
So far I have a filter and in the filter I want to hide the address fields. This works great, but now I want to make it conditional, and only hide the address fields if a non-downloadable product is included. Thanks
// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
$hasPhysicalProduct = 0;
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( SOMEHOW CHECK IF THE PRODUCT IS DOWNLOADABLE ) {
$hasPhysicalProduct = 1;
}
}
}

$_product is an instance of WC_Product, so you should be able to do this:
if ( $_product.is_downloadable() ) {
$hasPhysicalProduct = 1;
}
The WooCommerce docs has information about the WC_Product class members

Related

Empty cart if specific product not in it

So I need a little help. I have a wooocommerce webshop where there are two main products, and then 3 products, that visitors only will be able to buy, if one of the two main products are in the cart. I have found some code, that works like this: If I remove a main product, the additional product will be removed automatic, which it should. My problem is, i dont know how to modify the code, so it includes 3 products id's (one id, for each of the additional products). I have tried plenty of things, but cant get it to work. Can you maybe help me? This it the code I have (which now contains one product id, and it should contain three id's):
// Add to cart validation for the discounted product
add_filter( 'woocommerce_add_to_cart_validation', 'check_specific_discounted_product', 10, 3 );
function check_specific_discounted_product( $passed, $product_id, $quantity ) {
// Settings
$discounted_product_id = 3008;
if( WC()->cart->is_empty() && $discounted_product_id == $product_id ) {
wc_add_notice( __("This product can't be purchased alone."), 'notice' );
return false;
}
return $passed;
}
// Removing the discounted product if it's alone in cart
add_action( 'woocommerce_before_calculate_totals', 'conditionally_remove_a_discounted_product' );
function conditionally_remove_a_discounted_product( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Settings
$discounted_product_id = 3008;
// Initializing variables
$discounted_item_key = false;
// Loop through cart items (first loop)
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ){
// When free productis is cart
if ( in_array( $discounted_product_id, array($cart_item['product_id'], $cart_item['variation_id']) ) ) {
$discounted_item_key = $cart_item_key;
}
// if any other product is in cart: EXIT
else {
return;
}
}
// When the discounted product is alone in cart, remove it
if( $discounted_item_key ) {
// display notice on removal (optional)
wc_clear_notices();
wc_add_notice( __("The discounted product can't be purchased alone and has been removed."), 'notice' );
$cart->remove_cart_item( $discounted_item_key ); // Remove
}
}
I have tried to modify the code like this:
$discounted_product_id = 3004, 3008, 3157;
And like this:
$discounted_product_id = 3004;$discounted_product_id = 3008;$discounted_product_id = 3157;
Also like this:
$discounted_product_id = array('3004','3008','3157');
But it's not working :(

Hide shipping methods if a virtual product is in the cart

If a woocommerce cart has a virtual item only it does not show shipping methods.
I have a unique situation where I'd like this to be the case also if the cart contains physical products but at least one virtual product (ie any virtual product in the cart, regardless of whatever else is in the cart, hide shipping methods). Whereas if no virtual products are in the cart then show shipping methods as normal.
I've tried the code below but it doesn't seem to work:
Thanks for your help
add_filter( 'woocommerce_cart_needs_shipping_address', 'filter_cart_needs_shipping_address_callback' );
function filter_cart_needs_shipping_address_callback( $needs_shipping_address ){
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->is_virtual() ) {
$needs_shipping_address = false;
break; // Stop the loop
}
}
return $needs_shipping_address;
}
Thanks, it was throwing the error "Uncaught Error: Call to a member function get_cart() on null" but have managed to fix it with this:
if ( is_null( WC()->cart ) ) {
wc_load_cart();
} else
Let me know if there is a better way to do it? Thanks
add_filter( 'woocommerce_cart_needs_shipping', 'filter_cart_needs_shipping_address_callback' );
function filter_cart_needs_shipping_address_callback( $needs_shipping ){
// Loop through cart items
if ( is_null( WC()->cart ) ) {
wc_load_cart();
} else {
foreach ( WC()->cart->get_cart() as $item ) {
if ( $item['data']->is_virtual() ) {
$needs_shipping = false;
break; // Stop the loop
}
}
return $needs_shipping;
}
}
I think I figured out how to do it for you.
The Hook you're using in your example is not the right one since it's just filtering the shipping address callback.
What I think you need to do is use the woocommerce cart needs shipping hook.
Since it was throwing an error you could try to only run the code on the cart and checkout page. You can do that by using if ( is_cart() || is_checkout() ) {
Try the edited code below and let me know how it works.
Have a wonderful day!
add_filter( 'woocommerce_cart_needs_shipping', 'remove_virtual_product_shipping_methods' );
function remove_virtual_product_shipping_methods( $needs_shipping ){
//Only execute code on cart and checkout page.
if ( is_cart() || is_checkout() ) {
//Loop trough cart items
foreach ( WC()->cart->get_cart() as $item ) {
//If a product in cart is a vritual product remove all shipping
if ( $item['data']->is_virtual() ) {
$needs_shipping = false;
break;
}
}
return $needs_shipping;
}
}

Show or hide checkout postcode field based on specfic product in WooCommerce

in WooCommerce, I am trying to hide the postal code field on checkout whenever specific product is selected. I've tried a bunch of different things.
This is my last attempt:
/**
* Conditionally remove a checkout field based on products in the cart
*/
function wc_ninja_product_is_in_the_cart() {
// Add your special product IDs here
$ids = array( '9531', '9072', '9035' );;
// Products currently in the cart
$cart_ids = array();
// Find each product in the cart and add it to the $cart_ids array
foreach( WC()->cart->get_cart() as $cart_item_key => $values ) {
$cart_product = $values['data'];
$cart_ids[] = $cart_product->id;
}
// If one of the special products are in the cart, return true.
if ( ! empty( array_intersect( $ids, $cart_ids ) ) ) {
return true;
} else {
return false;
}
}
function wc_ninja_remove_checkout_field( $fields ) {
if ( ! wc_ninja_product_is_in_the_cart() ) {
unset( $fields['billing']['billing_postcode'] );
}
return $fields;
}
add_filter( 'woocommerce_checkout_fields' , 'wc_ninja_remove_checkout_field' );
<!-- end snippet -->

Hide specific products on woocommerce when ACF true/false is true in a product

I have created a custom field true/false, and I want when true is selected in a product not to be displayed in the eshop.
I want to insert the code inside the functions.php
example
if ( in_array( 'subscriber', (array) $user->roles ) || !is_user_logged_in() ) {
$postid = get_the_ID();
$prd_only_for_Customers = get_field('prd_clients', $postid); // The ACF true/false field }
Can anyone help ?
As Howard said your question is incomplete but you can use the following method to set product hidden.
You can use pre_get_posts hook in your functions.php. Since Woocommerce 3 the products visibility is now handled by the 'product_visibility' custom taxonomy for the terms 'exclude-from-catalog' and 'exclude-from-search'… See this thread or this one too.
So you should use instead the WC_Product CRUD setter methods set_catalog_visibility() this way:
function get_post_ids_by_meta_key_and_value($key, $value) {
global $wpdb;
$meta = $wpdb->get_results("SELECT post_id FROM `".$wpdb->postmeta."` WHERE meta_key='".$wpdb->escape($key)."' AND meta_value='".$wpdb->escape($value)."'");
$post_ids = [];
foreach( $meta as $m ) {
$post_ids[] = $m->post_id;
}
return $post_ids;
}
add_action('pre_get_posts', function( $query ){
if ( $query->is_main_query() && is_woocommerce() && !is_user_logged_in() ) {
$product_ids = get_post_ids_by_meta_key_and_value('prd_clients', 1);
foreach($product_ids as $id){
// Get an instance of the product
$product = wc_get_product($id);
// Change the product visibility
$product->set_catalog_visibility('hidden');
// Save and sync the product visibility
$product->save();
}
}
});
This code isn't tested, let me know if it worked or you faced any problem.
This is my final code if anyone needs something like this
// Specific products show only for Customer and administrator role
add_action('pre_get_posts', function( $query ){
$user = wp_get_current_user();
if ( $query->is_main_query() && is_woocommerce()) {
if (!check_user_role(array('customer','administrator')) || !is_user_logged_in() ) {
$product_ids = get_post_ids_by_meta_key_and_value('prd_clients', 1);
foreach($product_ids as $id){
// Get an instance of the product
$product = wc_get_product($id);
// Change the product visibility
$product->set_catalog_visibility('hidden');
// Save and sync the product visibility
$product->save();
}
}
else{
$product_ids = get_post_ids_by_meta_key_and_value('prd_clients', 1);
foreach($product_ids as $id){
// Get an instance of the product
$product = wc_get_product($id);
// Change the product visibility
$product->set_catalog_visibility('visible');
// Save and sync the product visibility
$product->save();
}
}
}
});

Wordpress variable, user created, woocommerce product

Basically I am interested in using woocommerce to sell a product . This product is a Print Order of a external printing service that I have implemented in a brand new plugin.
What I want now is after the order, is to be able to put that "order" in the buy cart, and buy it normally as just another woocommerce product.
The product has to be created on the fly, manually by a way of some function that I can use to create a product during a certain workflow point.
Can you help me to find a solution?
Using woocommerce or not!
What i understand from your requirement/comments is that you want to be able to dynamically create a product, which is bad idea. But here is my suggestion.
Lets say you have a simple product called "Print Job" with a price of $1 and with an id of 10. And i am supposing that your external printing service would send back a response with the order and the price of printing, lets say $64.
Once you recieve the response you can simply call add_product_to_cart(10), this will automatically add the print job product to your cart.
/************* functions.php ***************/
function add_product_to_cart($product_id) {
if ( ! is_admin() ) {
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
You also need to add this function in your functions.php, this function will override the price of the product i.e "Print Job" with the actual price of $64.
/******************* Functions.php ****************/
add_action( 'woocommerce_before_calculate_totals', 'override_printing_price' );
function override_printing_price( $cart_object ) {
$custom_price = 64;
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
}
}

Resources