Display product variations on category page - woocommerce

How do I show all product variations on WooCommerce category pages?
I have set up a variable product with three variations. I want each variation (not the variable product itself) to be displayed as a separate product on the product category page. The user should be able to open a variable product and add it to the cart.
Is this possible?

Example : http://bennyhendrikx.be/product-categorie/clothing/page/2/
Add this code in youre functions.php
if ( ! function_exists( 'woocommerce_template_loop_add_to_cart' ) ) {
function woocommerce_template_loop_add_to_cart() {
global $product;
if ($product->product_type == "variable" && (is_product() || is_product_category() || is_product_tag())) {
woocommerce_variable_add_to_cart();
}
else {
woocommerce_get_template( 'loop/add-to-cart.php' );
}
}
}

add_action('woocommerce_after_shop_loop_item_title','woocommerce_template_single_variation', 5);
function woocommerce_template_single_variation() {
global $product;
if ($product->product_type == "variable" && (is_product_category() || is_product_tag())) {
echo woocommerce_variable_add_to_cart();
}
}

Hi You can just paste this code in your theme functions.php
here is code
/**
* Replace add to cart button in the loop.
*/
function iconic_change_loop_add_to_cart() {
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
add_action( 'woocommerce_after_shop_loop_item', 'iconic_template_loop_add_to_cart', 10 );
}
add_action( 'init', 'iconic_change_loop_add_to_cart', 10 );
/**
* Use single add to cart button for variable products.
*/
function iconic_template_loop_add_to_cart() {
global $product;
if ( ! $product->is_type( 'variable' ) ) {
woocommerce_template_loop_add_to_cart();
return;
}
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
add_action( 'woocommerce_single_variation', 'iconic_loop_variation_add_to_cart_button', 20 );
woocommerce_template_single_add_to_cart();
}
/**
* Customise variable add to cart button for loop.
*
* Remove qty selector and simplify.
*/
function iconic_loop_variation_add_to_cart_button() {
global $product;
?>
<div class="woocommerce-variation-add-to-cart variations_button">
<button type="submit" class="single_add_to_cart_button button"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
<input type="hidden" name="add-to-cart" value="<?php echo absint( $product->get_id() ); ?>" />
<input type="hidden" name="product_id" value="<?php echo absint( $product->get_id() ); ?>" />
<input type="hidden" name="variation_id" class="variation_id" value="0" />
</div>
<?php
}

Even after so many years this one is not so simple for woocommerce.
The above examples shows the parent products with available variations below.
You maybe want to show the variations as simple products.
It's better to use a plugin for this. The Woocommerce single variations by weLaunch https://www.welaunch.io/en/product/woocommerce-single-variations/
it's the best i found so far. It gives you the opportunity to even exclude one variation from the category page (Most of the times, your products have 2 variations color/size. You simple want to show only the color variation).
If you want to go with custom code. You have to keep in mind, the images, pagination, filters, product links with variation parameters.
Woocommerce works with parent products on its core.

Related

Hide add to cart button in WooCommerce but show stock status

I want to hide the add to cart button in WooCommerce but still show the stock status message... It's easy in CSS but i am looking for a solution in php.
For now i've been using this code below but it hide all the shop functionnality, I just need to hide the add to cart button and show the out of stock message if the product is out of stock.
// Remove add to cart on single product pages
add_action( 'woocommerce_single_product_summary', 'hide_single_product_prices', 1 );
function hide_single_product_prices(){
global $product;
if ( has_term( array('category1', 'category2', 'category3', 'category4'), 'product_cat', $product->get_id() ) ) :
//Hide add-to-cart button, quantity buttons (and attributes dorpdowns for variable products)
if( ! $product->is_type('variable') ){
remove_action('woocommerce_single_product_summary','woocommerce_template_single_add_to_cart', 30 );
} else {
remove_action( 'woocommerce_single_variation', 'woocommerce_single_variation_add_to_cart_button', 20 );
}
endif;
}```
So the issue is that when you remove the function 'woocommerce_template_single_add_to_cart' from 'woocommerce_single_product_summary' what you're actually doing is telling woocommerce not to load the template at all, located in: templates/single-product/add-to-cart. Which template loads there depends on the product type, but I'll assume simple for now.
If you look at that template, its not ACTUALLY just the add to cart button. It contains the call to wc_get_stock_html() that displays what you're looking for. So there isn't actually a good way just with removing a hook, to hide ONLY the button.
Instead what you'll have to do is one of two things: You can copy the add-to-cart/simple.php template into your theme, and edit it there with your logic. You'll likely want to wrap the button like this:
<?php if( ! your_custom_function( $product ) : ?>
<div class='buttons-container'>
<button type="submit" name="add-to-cart" value="<?php echo esc_attr( $product->get_id() ); ?>" class="single_add_to_cart_button btn btn--pink"><?php echo esc_html( $product->single_add_to_cart_text() ); ?></button>
</div>
<?php endif; ?>
The downside to that is that if you want this to work for all product types, you'd have to copy each template and do something similar.
So alternatively, what you could do is remove the action - as you have in your code above, and then Re-add the stock display wherever you'd like it. I would lean this direction for the reason above. Something like this:
remove_action( 'woocommerce_single_product_summary','woocommerce_template_single_add_to_cart', 30 );
add_action( 'woocommerce_single_product_summary', function(){
global $product;
if( $product->is_purchasable() ){
echo wc_get_stock_html( $product );
}
}, 30 );

Display Product Price next to Product Title on Product Page (next to, not under or above)

After looking at the hooks used, the title has priority 5 and the price has priority 10. So, I did an remove_action and add_action and changed it to 6. That did not work.
What I need is this:
Product title: currency symbol price
Example:
Puzzle for kids: $29
The code I tried:
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 6 );
I have tried this code as well now without any luck:
remove_action('woocommerce_single_product_summary','woocommerce_template_single_title', 5);
add_action('woocommerce_single_product_summary', 'woocommerce_new_single_title', 5);
if ( ! function_exists( 'woocommerce_new_single_title' ) ) {
function woocommerce_new_single_title() {
$product = wc_get_product( $post_id );
$product->get_regular_price();
$product->get_sale_price();
$product->get_price();
$pprice = $product->get_price();
?>
<h1 itemprop="name" class="product_title entry-title"><span><?php the_title(); ?>: <?php $product->get_price(); ?></span></h1>
<?php
}
}
Any ideas where I am going wrong and how to fix this?
To change an action, simply add your custom function to this action.
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_title', 5 );
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
function show_title_with_price()
{
global $product;
$title = $product->get_title();
$price = $product->get_regular_price();
$symbol = get_woocommerce_currency_symbol();
//You may change <p> tag or add any inline CSS here.
echo "<p>$title: $symbol $price</p>";
}
add_action( 'woocommerce_single_product_summary', 'show_title_with_price', 5 );
This code removes the default title and default price sections (actions) from single product page and adds the custom function named "show_title_with_price()" to woocommerce_single_product_summary action with parameter '5' where the actual title is shown in product page.
Note: Code shows only regular price. I believe you already know how to show sale price if exists.
More about single product page actions: WooCommerce Single Product Page Default Actions
Woocommerce action hooks and overriding templates:Stackoverflow Reference
I tested the code, works fine. Have a good day.

How to change add-to-cart form?

Is there a way to change the WooCommerce add-to-cart form through functions.php?
The goal is to add a checkbox for an additional product. When the checkbox is checked this product will also be added to the cart after a click on the add to cart button.
I am looking for a solution which doesn't rely on javascript.
A better title would be "WooCommerce up-sells as checkboxes".
A lot of research and several strategies to tackle this problem lead me to a solution which I thought was not even possible in the beginning.
The solution is now exactly what I wanted. A non-JavaScript, no-template-override, but a simple and pure addition to functions.php. It works for simple and variable products (and probably with grouped and external products too).
It misses some nice features still. It won't work yet if an up-sell is a variable product. Quantity selection and limiting up-sells per item or order would be nice additions too. Based on the code below adding those features should not be a big deal anymore.
// create the checkbox form fields and add them before the cart button
add_action( 'woocommerce_before_add_to_cart_button', 'action_woocommerce_before_add_to_cart_form', 10, 0 );
function action_woocommerce_before_add_to_cart_form(){
global $woocommerce, $product;
// get the product up-sells
$upsells = $product->get_upsells();
// store the number of up-sells and pass it on to the add-to-cart hook
?>
<input type="hidden" name="upsells_size" value="<?php echo(sizeof($upsells)); ?>">
<div id="wb-upsell-div">
<?php
// iterate through all upsells and add an input field for each
$i = 1;
foreach( $upsells as $value ){
$product_id = $value;
?>
<input id="wb-upsell-checkboxes" type="checkbox" name="upsell_<?php echo($i) ?>" value="<?php echo($product_id); ?>"><?php echo( '' . get_the_title( $product_id ) . "". " ($" . get_post_meta( $product_id, '_regular_price', true) . ")"); ?><br>
<?php
$i++;
}
?>
</div>
<?php
}
// function to add all up-sells, where the checkbox have been checked, to the cart
add_action('woocommerce_add_to_cart', 'custom_add_to_cart', 10, 3);
function custom_add_to_cart() {
global $woocommerce;
// get the number of up-sells to iterate through
$upsell_size = $_POST['upsells_size'];
// iterate through up-sell fields
for ($i=1; $i<=$upsell_size; $i++){
// get the product id of the up-sell
$product_id = $_POST['upsell_' . $i];
$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 );
}
}
}
And here is the CSS for formatting the <div>and the checkboxes. It goes into the style.css file:
#wb-upsell-div {
margin-top: 10px;
margin-bottom: 20px;
}
#wb-upsell-checkboxes{
}
So there's an actual answer to this question, you can add whatever you want inside the add to cart <form> using hooks. For example:
add_action( 'woocommerce_before_add_to_cart_button', 'so_34115452_add_input' );
function so_34115452_add_input(){
echo '<input type="checkbox" name="something"/>' . __( 'Some Checkbox', 'text-domain' );
}

Making the coupon field mandatory on WooCommerce

I was wondering if it was possible to make the coupon field mandatory on WooCommerce.
I know that this is possible using functions, however this is slightly above my current skill level so I was wondering if you could give me a step-by-step version of how to accomplish this. Any answer would be much appreciated.
I don't know about the function but you can modify the plugin to achieve this in following manner :
Make one folder in your theme folder woocommerce and in new created woocommerce folder, create another folder with checkout name.
So now it will look something like wp-content > themes > your-theme > woocommerce > checkout.
Now go to your plugin directory and follow below path :
wp-content > plugins > woocommerce > templates > checkout
When you go in above path, you will find one file named as form-coupon.php. Copy that file and paste it to the directory which we created at top of that answer.
wp-content > themes > your-theme > woocommerce > checkout > form-coupon.php.
Now its time to modify the code in wp-content > themes > your-theme > woocommerce > checkout > form-coupon.php :
Find following code line in above mentioned file :
<input type="text" name="coupon_code" class="input-text" placeholder="<?php _e( 'Coupon code', 'woocommerce' ); ?>" id="coupon_code" value="" />
And replace above line with
<input type="text" name="coupon_code" class="input-text" placeholder="<?php _e( 'Coupon code', 'woocommerce' ); ?>" id="coupon_code" value="" required/>
Note: Here I have added required attribute of html.
Tell me if you have any doubt.
UPDATED:
add_action('woocommerce_check_cart_items', 'make_coupon_code');
function make_coupon_code()
{
global $woocommerce;
if(is_cart() || is_checkout()){
$my_coupon = $woocommerce->cart->applied_coupons;
echo $woocommerce->cart->get_applied_coupons;
if(empty($my_coupon))
{
$woocommerce->add_error("Please enter coupon code to checkout.");
}
}
}
Please give it a try and let me know feedback.
NOTE: UNTESTED
to solve the problem try this code:
<?php
add_action('woocommerce_check_cart_items', 'make_coupon_code');
function make_coupon_code()
{
global $woocommerce;
if(is_cart() || is_checkout()){
$my_coupon = $woocommerce->cart->applied_coupons;
echo $woocommerce->cart->get_applied_coupons;
if(empty($my_coupon))
{
wc_add_notice( '<strong>' . $btn['label'] . '</strong> ' . __( 'insert coupon code', 'woocommerce' ), 'error' );
}
}
}
?>
in functions.php instead of the one above...
for me it works
Add the following code in functions.php
Require Coupon for Single Product
add_action( 'woocommerce_check_cart_items', 'mandatory_coupon_for_specific_items' );
function mandatory_coupon_for_specific_items() {
$targeted_ids = array(37); // The targeted product ids (in this array)
$coupon_code = 'summer2'; // The required coupon code
$coupon_applied = in_array( strtolower($coupon_code), WC()->cart->get_applied_coupons() );
// Loop through cart items
foreach(WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids and applied coupon
if( in_array( $cart_item['product_id'], $targeted_ids ) && ! $coupon_applied ) {
wc_clear_notices(); // Clear all other notices
// Avoid checkout displaying an error notice
wc_add_notice( sprintf( 'The product"%s" requires a coupon for checkout.',
$cart_item['data']->get_name() ), 'error' );
break; // stop the loop
}
}
}
Replace 37 by the your product ID in $targeted_ids = array(37); you can have multiple product IDs like $targeted_ids = array(37,48,12);
Replace "summer2" by any other coupon code in $coupon_code = 'summer2';
Don't forget to add this coupon code in WooCommerce before using it.
Require coupon for all products
add_action( 'woocommerce_check_cart_items', 'mandatory_coupon_code' );
function mandatory_coupon_code() {
$product_categories = array( 'clothing' ); // Category ID or slug of targeted category
$coupon_code = 'summer2'; // The required coupon code
$coupon_applied = in_array( strtolower($coupon_code), WC()->cart->get_applied_coupons() );
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ){
if( has_term( $product_categories, 'product_cat', $cart_item['product_id'] ) && !$coupon_applied ) {
wc_clear_notices(); // Clear all other notices
// Avoid checkout displaying an error notice
wc_add_notice( sprintf( 'The product"%s" requires a coupon for checkout.',
$cart_item['data']->get_name() ), 'error' );
break; // stop the loop
}
}
}
Replace $product_categories = array( 'clothing' ); by any other category name or category ID.

Add meta box to categories admin panel in Wordpress

I'm working on a Wordpress theme and I need to add a meta box (checkbox) to the category admin panel.
I've written the code to add the meta box to the panel but there is 2 problems:
1- First it appears below the "Add category button"
2- What functions should I use to save the checkbox value in the database ?
and there is the code to add the checkbox
add_action ( 'category_add_form_fileds', 'add_to_main_page');
add_action('category_edit_form', 'add_to_main_page');
function add_to_main_page() {
?>
<input type="checkbox" name="add_to_main" id="add_to_main" value="1">
<label for="add_to_main">This category on main page</label>
<?php }
Thanks in advance
After fixing one typo—"category_add_form_fileds" to "category_add_form_fields"—your code worked fine for me. I get a checkbox on both forms above the "Add New Category" / "Update" buttons. This is a complete version and should do the trick:
add_action( 'category_add_form_fields', 'add_to_mainpg_fields' );
add_action( 'category_edit_form', 'add_to_mainpg_fields' );
function add_to_mainpg_fields() {
?>
<input type="checkbox" name="add_to_main" id="add_to_main" value="1" />
<label for="add_to_main">This category on main page</label>
<?php
}
add_action( 'created_category', 'add_to_mainpg_save' );
add_action( 'edited_category', 'add_to_mainpg_save' );
function add_to_mainpg_save( $term_id ) {
if( !isset( $_POST['add_to_main'] ) )
return;
$stickies = get_option( 'main_page_cats' );
if( !is_array( $stickies ) )
$stickies = array( $term_id );
if( !in_array( $term_id, $stickies ) )
$stickies[] = $term_id;
update_option( 'main_page_cats', $stickies );
}
This is a modified version of the stick_post function used for sticky posts.
This tutorial is instructive for saving multiple options. Two robust solutions are this plugin and this library. I understand if you don't want all that for a single field, but others might. :)

Resources