So recently I’ve set up a webshop for handmade bracelets. In this particular case we have incredibly few products, a bracelet, belt or keychain; with incredibly many variations; first color, second color, lock, length, etc.. you get it.
We didn’t want to flood the view under the different product-categories, so instead of filling it with all the different previous creations for show, we chose to create a single product, the variable product, and a single subcategory, a gallery of previous creations.
But the gallery is now a subcategory and these show up before the products when you view a category. My client didn’t like that, so I fixed it.
First of all, if you haven’t already made a child theme and copied the plugins/woocommerce/template folder into themes/yourtheme/template and renamed it to themes/yourtheme/woocommerce you should do that. There’s a guide here, if you need more: http://docs.woothemes.com/document/template-structure/.
Open the yourtheme/woocommerce folder and locate archive-product.php.
There’s a loop:
<?php woocommerce_product_loop_start(); ?> <?php woocommerce_product_subcategories(); ?> <?php while ( have_posts() ) : the_post(); ?> <?php $terms = wp_get_post_terms(get_the_ID(), $wp_query->query_vars['taxonomy']); if ($terms[0]->term_id == $term->term_id){ ?> <?php wc_get_template_part( 'content', 'product' ); ?> <?php } ?> <?php endwhile; // end of the loop. ?> <?php woocommerce_product_loop_end(); ?>
As you can see, the woocommerce_product_subcategories tag that posts the categories comes before the loop that posts your products. Now you might just be enclined to move it down after the loop like below.
<?php woocommerce_product_loop_start(); ?> <?php while ( have_posts() ) : the_post(); ?> ... post loop ... <?php endwhile; // end of the loop. ?> <?php woocommerce_product_subcategories(); ?> // now after loop.. <?php woocommerce_product_loop_end(); ?>
Done, right? No!
Woocommerce actually does something pretty nifty with a counter when it determines when to linebreak; it depends on the number of products you have chosen to have in a column. What woocommerce also does, for some reason, is to reset this counter, somewhere in-between the loop that pastes the products finish and the woocommerce_product_subcategories call is made.
Looking into either the content-product_cat.php or the content-product.php templates, we can examine what’s actually going on – they’re using a global counter called $woocommerce_loop[‘loop’], to maintain what number item they’re currently printing. For the sake of not cluttering this post, I’m not gonna go into detail about how this works – look in the files, it’s simple but powerful.
Now, for some reason $woocommerce_loop[‘loop’] is reset, and I wasn’t really able to figure out why or where it happens, (but if you find out I’ll totally throw you a cupcake). We need some other place that’s not reset to store what happens inside the loop, before it exits.
We need our own counter!
<?php woocommerce_product_loop_start(); ?> <?php $counter = $woocommerce_loop['loop']; ?> <?php while ( have_posts() ) : the_post(); ?> ... post loop ... <?php $counter++; ?> <?php endwhile; // end of the loop. ?> <?php $woocommerce_loop['loop'] = $counter; ?> <?php woocommerce_product_subcategories(); ?> // now after loop.. <?php woocommerce_product_loop_end(); ?>
But does this really work? … no, it doesn’t.
We haven’t made the variable $woocommerce_loop available to the file archive-product.php yet. Luckily however that’s easily done by altering the line, (found somewhere in the beginning) from
global $wp_query;
to
global $wp_query, $woocommerce_loop;
Are we done yet!? .. Almost!.. If you looked in the template files that use the counter, you’ll notice that they check whether the counter is instantiated, and if it isn’t they reset it. So we’re gonna do that as well! After the line you just added, add the code
// Store loop count we're currently on if ( empty( $woocommerce_loop['loop'] ) ) $woocommerce_loop['loop'] = 0;
ARE WE THERE YET??? Yes! we made it back alive.
We went from here,
To here,