I'm building an e-commerce site. I'm having some trouble with WooCommerce Variable Product.
The "Add to Cart" button works fine with simple products, but does not work with variable products. It gives a "Please choose product options…" notice.
I looked everywhere and tried several suggestions online, none of them work. So I looked into WooCommerce source file: class-wc-form-handler.php.
In the function add_to_cart_handler_variable:
function add_to_cart_handler_variable( $product_id ) {
$adding_to_cart = wc_get_product( $product_id );
$variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] );
$quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] );
$missing_attributes = array();
$variations = array();
$attributes = $adding_to_cart->get_attributes();
$variation = wc_get_product( $variation_id );
...
if ( $missing_attributes ) {
wc_add_notice( sprintf( _n( '%s is a required field', '%s are required fields', sizeof( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ), 'error' );
} elseif ( empty( $variation_id ) ) {
wc_add_notice( __( 'Please choose product options…', 'woocommerce' ), 'error' );
} else {
// Add to cart validation
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) !== false ) {
wc_add_to_cart_message( $product_id );
return true;
}
}
return false;
}
The error is caught in the elseif clause.
So I tried to echo out $variation_id, $variations, and $variation. None of them has anything in it because when I echo $variation_id: it doesn't output anything.
How can the error be resolved?
On shop page you can't use add-to-cart button for variable products, because you need first to go on single product page to chose the options for this variable product before adding it to cart.
On variable product pages, normally you have some displayed options to chose for a variable product, before using "add to cart" button. If you don't do it, you get the error message… So at this point:
The options are not displayed in the product page (Bad settings in your backend product page, a bug with your theme or some additional plugin):
Check your product backend settings
Try to switch to default wordpress theme (to see if this issue is still there)
Try to disable most of all plugins.
the options are displayed: So chose your options first for this product, then add to cart
If this issue is related to your theme, contact the author of your theme and open a support thread or ticket…
OUPUTTING PRODUCT VARIATIONS FOR A PRODUCT ID:
To get product variations programmatically for a variable product ID:
$product = wc_get_product( $product_id );
$product_variations = $product->get_available_variations();
echo var_dump($product_variations); // Displaying the array
Then to get the first variation ID:
$product = wc_get_product( $product_id );
$product_variations = $product->get_available_variations();
$variation_product_id = $product_variations [0]['variation_id'];
echo $variation_product_id; // Displaying the variation ID
Or to get an array of all variations ID of this product ID:
$product = wc_get_product( $product_id );
$product_variations = $product->get_available_variations();
$arr_variations_id = array();
foreach ($product_variations as $variation) {
$product_variation_id = $variation['variation_id'];
array_push( $arr_variations_id, $product_variation_id );
}
echo var_dump($arr_variations_id); // Displaying the array of variations ID
A reference : Change "Add to Cart" button to "Go to Product" in the Shop Page
Just in case anyone else is building a custom theme and encounters this issue with variations not adding to the cart as expected - you may need to check your theme is loading the /woocommerce/assets/js/frontend/add-to-cart-variation.min.js script - add the following to wherever you enqueue your scripts to manually add it:
wp_enqueue_script('wc-add-to-cart-variation');
This solved the issue for me.
While we all have variation swatches in common the error (bizarre as this sounds) lays with the theme being incompatible. To test simply switch to 2020 theme and the ordering should work. I would recommend then making 2020 suite your needs and stop using the theme where the developers take days off when woocommerce updates are rolled out! Disabling the swatches wont help as the code is already there. Good luck.
I was facing the same issue.....delete your variation swatches plugin and the problem will be solved
Had the same issue....deactivated the autoptimize plugin and the problem was solved.
Also,to know which plugin to disable, you can simply load the page or the website, inspect element or developers mode, then check the console to see the source of the error which you can then relate to the relevant plugin and then disable from your wp dashboard.
I use wishlist plugin and when I tried to add variable product to cart I have got: 'The selected product isn't a variation of Product name, please choose product options by visiting Product name.'
The problem was that my product haven't default variation. So user added to wishlist product without selected variation. So when after user tries to add this product to cart error appears.
Here is FIX: just set default variation to all cariation products!
(Manually or via code). So user COULD NOT add product with EMPTY variation. Variation will be selected by default or user changes variation by himself.
So now in wishlist we have variation selected and all works as it should. It will work on all pages, archives, wishlists etc. Good luck! ;)
you’ll need to modify the functions.php file. Simply go to wp-content/yourtheme/functions.php on your child theme. Here, we’ll show you the full code and then we’ll explain its main parts. So the full PHP script to create WooCommerce default product attributes programmatically is the following:
add_action('woocommerce_before_single_product_summary', 'quadlayers_product_default_attributes');
function quadlayers_product_default_attributes() {
global $product;
if (!count($default_attributes = get_post_meta($product->get_id(), '_default_attributes'))) {
$new_defaults = array();
$product_attributes = $product->get_attributes();
if (count($product_attributes)) {
foreach ($product_attributes as $key => $attributes) {
$values = explode(',', $product->get_attribute($key));
if (isset($values[0]) && !isset($default_attributes[$key])) {
$new_defaults[$key] = sanitize_key($values[0]);
}
}
update_post_meta($product->get_id(), '_default_attributes', $new_defaults);
}
}
}
Related
With WooCommerce I am using WooCommerce Subscriptions plugin. I have mainly Variable Subscription products and some few simple Subscription products.
I am using woocommerce_dropdown_variation_attribute_options_args filter hook, to update dropdown attribute values on my Variable Subscription products.
For Simple Subscriptions products I would like to add some conditions to allow or deny access to the product page.
So my question is: Which hook could I use to check if a product is a simple subscription, to allow or deny access to the product?
Any help/suggestion will be highly appreciated.
You can check product type on the WC_Product object for simple subscription like:
if( $product->get_type() === 'subscription' ) {
// Do something
}
or
if( $product->is_type('subscription') ) {
// Do something
}
And here below is an example usage that will avoid access to simple subscription product pages, redirecting customer to main shop page and displaying an error notice:
add_action('template_redirect', 'conditional_single_product_page_access');
function conditional_single_product_page_access(){
// Targeting single product pages
if ( is_product() ) {
$product = wc_get_product( get_the_ID() ); // Get the WC_Product Object
// Targeting simple subscription products
if( $product->get_type() === 'subscription' ) {
wc_add_notice( __("You are not allowed to access this product"), 'error' ); // Notice
wp_safe_redirect( get_permalink( wc_get_page_id( 'shop' ) ) ); // Redirection
exit();
}
}
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
Notes:
To target variable subscription product type use the slug variable-subscription.
To target a variation subscription, the product type slug is: subscription_variation.
You can use is_subscription() of WC_Subscriptions_Product. You need to pass $product object in is_subscription() function as parameter. Check the below code.
if( WC_Subscriptions_Product::is_subscription( $product ) ) {
// product is subscription.
} else {
// product is not subscription.
}
Update
Use woocommerce_product_is_visible filter hook for remove the product from product catalog. check below code.
add_filter( 'woocommerce_product_is_visible', 'hide_product_if_is_subscription', 20, 2 );
function hide_product_if_is_subscription( $is_visible, $product_id ){
if( WC_Subscriptions_Product::is_subscription( $product_id ) ) {
$is_visible = false;
}
return $is_visible;
}
I am using Woocommerce and I have integrated some custom fields to allow the user to specify new values that I will later append to the product title.
I am using update_post_meta/get_post_meta to save the new information. This part works fine.
Then I used the filter woocommerce_product_title to update the title. This filter is working fine when there is the use of $product->get_title() but will do nothing when using $product->get_name()which isn't an issue because in some places I don't want to append the new information.
I also used the filter the_title for the product page.
Basically my code looks like below where return_custom() will be the function than will build the new information based on the product ID.
function update_title($title, $id = null ) {
$prod=get_post($id);
if (empty($prod->ID) || strcmp($prod->post_type,'product')!=0 ) {
return $title;
}
return $title.return_custom($id);
}
function update_product_title($title, $product) {
$id = $product->get_id();
return $title.return_custom($id);
}
add_filter( 'woocommerce_product_title', 'update_product_title', 9999, 2);
add_filter( 'the_title', 'update_title', 10, 2 );
The issue arise when adding the product to the cart. The name used is the default one so my below code isn't enough to update the product name used in the cart. Same thing for the notification mails. I suppose this is logical since the email will use the information of the cart.
I am pretty sure that everything is happening inside add_to_cart() but I am not able to find any filter/hook related to the product name.
How to make sure the name used in the cart is good? What filter/hook shoud I consider in addition to the ones I am already using in order to append my new information to the product title within the cart?
I want to make sure that the new title will be seen during all the shopping process. From the product page until the notification mail.
The following will allow you to customize the product name in cart, checkout, orders and email notifications, just with one hooked function:
// Just used for testing
function return_custom( $id ) {
return ' - (' . $id . ')';
}
// Customizing cart item name in cart, checkout, orders and email notifications
add_action( 'woocommerce_before_calculate_totals', 'set_custom_cart_item_name', 10, 1 );
function set_custom_cart_item_name( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
// Required since Woocommerce version 3.2 for cart items properties changes
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
// Loop through cart items
foreach ( $cart->get_cart() as $cart_item ) {
// Get the product name and the product ID
$product_name = $cart_item['data']->get_name();
$product_id = $cart_item['data']->get_id();
// Set the new product name
$cart_item['data']->set_name( $product_name . return_custom($product_id) );
}
}
Code goes on function.php file of your active child theme (or active theme). Tested and works.
Try using woocommerce_cart_item_name filter.
[woocommerce_cart] shortcode uses cart/cart.php template, and the code displaying the title is this:
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}
I am trying to redirect my custom shop page to cart page after user select custom attributes (liability and hours) and then clicks the purchase button.
I have written custom JS code which retrieves the variation_id and attributes value and append it to the URL so that it automatically gets added to cart and get's redirected to cart page.
href="yourdomain.com/?add-to-cart=47&variation_id=88&quantity=3&attribute_pa_colour=blue&attribute_pa_size=m"
This is the URL format which I have found in a blog: (https://businessbloomer.com/woocommerce-custom-add-cart-urls-ultimate-guide/) and I made my link in this format.
My link is:
localhost/wordpress/cart/?add-to-cart=1185&variation_id=1641&quantity=1&attribute_pa_liability=2_million&attribute_pa_hours=500_hours
Where liability and hours is my custom attribute which has values as 1 million, 2 million and 500 hours, 750 hours respectively.
But when it get's redirected to cart page woocommerce give me an error and shows it's alert box which shows the error message as "liability and hours are required fields".
I think woocommerce is unable to get the attribute values through my URL.
Can anyone explain why is this happening and what is the error if there is any?
Updated
This "Business Bloomer" guide is a little outdated… You need 2 things:
1). The correct URL
You don't need to addto cart the product and the variation Id with all related attributes. You just need to add to cart the variation ID + your custom attributes like this: localhost/wordpress/cart/?add-to-cart=1641&quantity=1&pa_liability=2_million&pa_hours=500_hours
2). Registering (and display) your custom attributes:
// Store the custom data to cart object
add_filter( 'woocommerce_add_cart_item_data', 'save_custom_product_data', 10, 2 );
function save_custom_product_data( $cart_item_data, $product_id ) {
$bool = false;
$data = array();
if( isset( $_REQUEST['pa_liability'] ) ) {
$cart_item_data['custom_data']['pa_liability'] = $_REQUEST['pa_liability'];
$data['pa_liability'] = $_REQUEST['pa_liability'];
$bool = true;
}
if( isset( $_REQUEST['pa_hours'] ) ) {
$cart_item_data['custom_data']['pa_hours'] = $_REQUEST['pa_hours'];
$data['pa_hours'] = $_REQUEST['pa_hours'];
$bool = true;
}
if( $bool ) {
// below statement make sure every add to cart action as unique line item
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_variations', $data );
}
return $cart_item_data;
}
// Displaying the custom attributes in cart and checkout items
add_filter( 'woocommerce_get_item_data', 'customizing_cart_item_data', 10, 2 );
function customizing_cart_item_data( $cart_data, $cart_item ) {
$custom_items = array();
if( ! empty( $cart_data ) ) $custom_items = $cart_data;
// Get the data (custom attributes) and set them
if( ! empty( $cart_item['custom_data']['pa_liability'] ) )
$custom_items[] = array(
'name' => 'pa_liability',
'value' => $cart_item['custom_data']['pa_liability'],
);
if( ! empty( $cart_item['custom_data']['pa_hours'] ) )
$custom_items[] = array(
'name' => 'pa_hours',
'value' => $cart_item['custom_data']['pa_hours'],
);
return $custom_items;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Tested and works
You will need to add this data to the order items too
First uncheck the ajax add to cart option from admin panel
Then you need to make variation with your attributes then find out product id, quantity, attribute slug and attribute name(used to show in cart) and variation id and then make your cart url like given below.
The add to cart link with attribute is : https://www.your-domain.com/?add-to-cart=(product id)&quantity=(numeric quantity)&attribute_pa_(attribute slug)=(attribute name)&variation_id=(variation id)
For more details you can visit http://www.codemystery.com/wordpress-woocommerce-add-cart-link-variations/
The other answers are correct in regards to the add to cart url format (should be: /add-to-cart=product_id&my_custom_attr=whatever&my_custom_attr2=somthing)
Then there is a very good plugin to handle this type of functionality for storing the custom product attributes called WC Fields Factory.
And the writer of the plugin also has a great article on how to do this w/o need of a plugin. As well as an answer on a similar question here.
With WooCommerce, I am using WC Vendors Pro plugin + Rehub theme + Auction plugin (by wp giene) + Simple Auctions plugin (by WC Vendors).
How can I prevent post-authors from buying and bidding their own products in WooCommerce?
I don't want the post authors to bid on the products they have posted, to prevent price increases (which is not correct).
Where to start, any Ideas?
Thanks
I suppose that your "post authors" (vendors) have a custom role (or some specific capabilities). So you can target the user role "post authors" (or one of his specifics capabilities) checking and removing cart items on checkout page for this user roles.
Here is that code:
add_action( 'woocommerce_before_checkout_form', 'checking_allowed_cart_items_on_checkout', 100, 1);
function checking_allowed_cart_items_on_checkout() {
// Allow only "administrator" and "customer" user roles to buy all products
if( ! current_user_can('administrator') || ! current_user_can('customer') ){
// Ititializing variables
$found = false;
$cart_object = WC()->cart;
$current_user_id = get_current_user_id();
// Checking cart items
foreach($cart_object->get_cart() as $cart_item_key => $cart_item){
// get the WC_Product object and the product ID
$product = $cart_item['data'];
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
// Get the product post object to get the post author
$post_obj = get_post( $product_id );
$post_author = $post_obj->post_author;
if( $post_author == $current_user_id ){
// removing the cart item
$cart_object->remove_cart_item( $cart_item_key );
$found = true; // set to true if a product of this author is found
}
}
// Display a custom message in checkout page when items are removed
if( $found ){
// Display an error message
wc_add_notice( __( 'Items removed - As a Vendor, you are not allowed to buy your own products.' ), 'error' );
}
}
}
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.
I am adding two different products in my website and they both combines together to form one single product, what i am trying to achieve is that when i click on the add to cart button, I want to send two product id's to "add to cart" which means two different products, one is the page from where the a"dd to cart" is clicked and the second one is manual product id which i've assigned to hidden text box.
I tried the ajax call but that didn't work. Also I don't want to go with woocommerce paid extensions for bundle products and other types.
So it would be great if i can make some changes to add to cart.
Try something simple, like "Woocommerce Free Gift" plugin, there is a free version as well. You can setup automatic product add to cart on certain circumstances.
Otherwise, you need to modify your functions.php, whenever you are adding "product A" -> add "product B". Something likes this:
add_action( 'init', 'add_product_to_cart' );
function add_product_to_cart() {
if ( ! is_admin() ) {
global $woocommerce;
$product_id = ID_OF_PRODUCT_A;
$product_b = ID_OF_PRODUCT_B;
$found = false;
if( $woocommerce->cart->total > 0 ) {
//check if product already in cart
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->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 )
$woocommerce->cart->add_to_cart( $product_b );
} else {
// do something
}
}
}
}