Skip to content

Instantly share code, notes, and snippets.

@Garconis
Last active September 27, 2023 03:26
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save Garconis/b750bee39aed5f0e8e596bb2fac16cab to your computer and use it in GitHub Desktop.
Save Garconis/b750bee39aed5f0e8e596bb2fac16cab to your computer and use it in GitHub Desktop.
WooCommerce | Expand and collapse child categories with custom toggle in the sidebar widget | https://i.gyazo.com/e1a39ed551096444134324bb429722bb.mp4
/* - woo cat toggling elements, injected via jQuery - */
/* make list item be relative, to be able to position toggle within this item, if desired */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent {
position: relative;
}
/* the new toggle element wrapper, which is added via jQuery */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle {
cursor: pointer;
display: inline-block;
text-align: center;
margin-left: 0.5em;
width: 1.5em;
line-height: 1em;
-webkit-transform: rotate(-90deg);
transform: rotate(-90deg);
transition: all 0.4s ease;
width: 20px;
height: 20px;
background: rgba(0,0,0,0.05);
text-align: center;
line-height: 20px;
border-radius: 50%;
}
/* when it's popped, style the toggle wrapper differently */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle.cat-popped {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
background: rgba(0,24,113,1);
color: white;
}
/* toggle icon */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle::before {
font-weight: normal;
font-style: normal;
font-size: 24px;
text-transform: none;
speak: none;
content: '+';
line-height: 20px;
width: 20px;
height: 20px;
text-align: center;
}
/* toggle icon when triggered */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle.cat-popped::before {
content: '\2013';
}
/* hide sub cats by default */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle ~ ul.children {
overflow: hidden;
max-height: 0;
transition: all 0.4s ease;
}
/* show sub cats when triggered via jQuery toggle */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle.cat-popped ~ ul.children {
max-height: 300px;
}
jQuery(function($){
// add a new toggle element after the parent category anchor
$( "<div class='woo-cat-toggle'></div>" ).insertAfter( "#sidebar .widget_product_categories .product-categories > .cat-item.cat-parent > a" );
// when the new toggle element is clicked, add/remove the class that controls visibility of children
$( "#sidebar .widget_product_categories .product-categories .woo-cat-toggle" ).click(function () {
$(this).toggleClass("cat-popped");
});
// if the parent category is the current category or a parent of an active child, then show the children categories too
$('#sidebar .widget_product_categories .product-categories > .cat-item.cat-parent').each(function(){
if($(this).is('.current-cat, .current-cat-parent')) {
$(this).children('.woo-cat-toggle').toggleClass("cat-popped");
}
});
});
@mgpap
Copy link

mgpap commented Oct 28, 2020

Hi @Garconis, I am new to woocommerce and I am trying to do exactly what you implemented above. But, where should I include those files in order to work? I have tried to include them to functions.php, but nothing changed.

Thanks in advance!

@lemonph
Copy link

lemonph commented Nov 6, 2020

I use wordpress and installed a plugin called snippets. I pasted both css and js in one snippet and it works well.

@Garconis
Copy link
Author

Garconis commented Nov 6, 2020

Add the CSS to your theme in its CSS area, or within your child theme's style.css

Then add the JavaScript to the footer area (you can use a Header Footer plugin) and make sure it's wrapped with <script> tags.

@mgpap
Copy link

mgpap commented Nov 6, 2020

Στιγμιότυπο οθόνης 2020-11-06 234138
As you in the above screenshot, this is the default product-category styling provided by the woocommerce. After doing your modifications nothing changed.

I followed the steps as described:

  1. Add the css to the theme's style.css ( I have no child theme). I use storefront.
  2. With the Head, Footer and Post Injections plugin I added the js code to the footer area as displayed below.
    image

Am I missing something? Thank you for your time! @Garconis @lemonph

@Garconis
Copy link
Author

Garconis commented Nov 6, 2020

I'd need a link to your site to troubleshoot it. Otherwise, you may need to check your category structure to make sure it's within a #sidebar, etc. If not, you may need to change some of the rules to match your own category widget structure: #sidebar .widget_product_categories ul.product-categories > li.cat-parent

@mgpap
Copy link

mgpap commented Nov 6, 2020

Yes. I have the widget inside a sidebar. The code is imported but no change is happening. I am working locally since I am still new to it. I don't know if the following screenshot helps, but it shows the elements of the product-categories, with the script included.
image

@Garconis
Copy link
Author

Garconis commented Nov 6, 2020

In all instances of my code, change #sidebar to be #secondary instead.

@mgpap
Copy link

mgpap commented Nov 6, 2020

@Garconis, now all set. Everything is working!!
Thank you very much!!

@mgpap
Copy link

mgpap commented Nov 7, 2020

Hi, I would like to ask one more thing. How could I modify the code in order to display only the child product-categories when a parent category is selected (clicked)?
Thanks!

@DEBA1801
Copy link

Great job. Removed an extra plugin and piece of code. Although anybody using the code should take into notice that, this piece of code needs to be modified as per the ID of the sidebar wrapper. Works well!

@lemonph
Copy link

lemonph commented Nov 19, 2020

The only problem i got here is it's not working on Safari and Firefox browsers. Any suggestion? thanks

@lemonph
Copy link

lemonph commented Nov 19, 2020

it's my fault. It works after cleaning cache.

@Dante383
Copy link

Dante383 commented May 25, 2021

Hi, so if anyone would want parent parent categories to also be collapsable (so for example we have category A and in there we have category B and in category B there are for example 10 categories - currently only category A will be collapsed) just change line 3 of JS from

$( "<div class='woo-cat-toggle'></div>" ).insertAfter( "#sidebar .widget_product_categories .product-categories > .cat-item.cat-parent > a" );

to
$( "<div class='woo-cat-toggle'></div>" ).insertAfter( "#sidebar .widget_product_categories .product-categories .cat-item.cat-parent > a" );

@shenalorlof
Copy link

If i have more children categories under the current children category. how can i change the code dear friend?

@escozul
Copy link

escozul commented Jan 13, 2022

So as @Dante383 Said You should also change line 9 from
$('#sidebar .widget_product_categories .product-categories > .cat-item.cat-parent').each(function(){
to
$('#sidebar .widget_product_categories .product-categories .cat-item.cat-parent').each(function(){

to have it "detect" the current sub category and expand to it.

@PythonMillionaire
Copy link

Sorry to bother you but do you happen to have the link to the page for which you built this solution so that I can take a look at its source code? The structure of my website is completely different (https://saddhustore.com.br/moda/?product_cat=feminino). I don't know much CSS or JQuery and I'm trying to make it work for my website as well.

image

Thanks a lot!

@escozul
Copy link

escozul commented Jan 19, 2022

Why don't you test it by making a copy of my fiddle?
https://jsfiddle.net/escozul/nrxek35q/30/
you need to play around with the classes and the ids to match your product categories tree

@PythonMillionaire
Copy link

Hi @escozul!

Thanks a lot for replying. Perfect!! Exactly what I was looking for. Thanks a lot!

@PythonMillionaire
Copy link

PythonMillionaire commented Jan 21, 2022

I struggled to make it work but, in the end, failed (though I learn a bunch of JQuery and CSS, which was neat). Then it occurred to me that I should check my theme to see if it was the culprit for the different structure. It wasn't, so I researched and found out it was all because of the shittyass Gutenberg block thing so all I had to do was install a plugin called "Disable Gutenberg" and, in its settings, mark both checkboxes.

image

After that, all I needed to do is replace "sidebar" with "secondary" as described above. Now IT WORKS and I can customize it to fit my own needs.

EDIT: JUST ONE THING. I just noticed that when a sub-category is expanded the new items that should have appear are cut off and become invisible instead of being moved downThis can be seen in @escozul's JSFiddle as well under category "ΒΡΕΦΙΚΟ". Simply changing

/* show sub cats when triggered via jQuery toggle */
#sidebar .widget_product_categories ul.product-categories > li.cat-parent .woo-cat-toggle.cat-popped ~ ul.children {
max-height: 300px;
}

from 300px to something enormous fixed it.

Thank you all so much for all your help! I love you forever

@tacuar
Copy link

tacuar commented Feb 12, 2022

So amazing codes! Worked like a charm!!!

Just one question, can anyone tell how to put the toggle icon on the left side, i mean, before the "category name"?

@PythonMillionaire
Copy link

What do you mean? It should appear on the left by default. I had to change the CSS to position it to the right instead

@tacuar
Copy link

tacuar commented Feb 13, 2022

well, just realized i could simply replace that After with Before, as simple as that. Thanks all guys!!!

@Garconis
Copy link
Author

FYI, here is a version for use with a widget that uses the block method. You'll need to update the block ID to your proper ID:

jQuery(function($){
	// add a new toggle element after the category count
	$( "<div class='woo-cat-toggle'></div>" ).insertAfter( "#block-12 .wp-block-woocommerce-product-categories .wc-block-product-categories-list > .wc-block-product-categories-list-item > .wc-block-product-categories-list-item-count" );
	// when the new toggle element is clicked, add/remove the class that controls visibility of children
	$( "#block-12 .wp-block-woocommerce-product-categories .wc-block-product-categories-list .woo-cat-toggle" ).click(function () {
		$(this).toggleClass("cat-popped");
	});
	// check each of the list items (each li)
	$('#block-12 .wp-block-woocommerce-product-categories .wc-block-product-categories-list > .wc-block-product-categories-list-item').each(function(){
		// see if the list item DOES have a ul child in it with a class used for category wrapper, meaning this list DOES seem to have any subcategories
		if($(this).find('ul.wc-block-product-categories-list').length !== 0) {
			// if it did have a ul with that class, then we add a class to the list item to let us know it does have children
			$(this).addClass("cat-children-yes");
		}
		else {
			// otherwise it did not find a ul child with that class, so it seems to not have any child categories, so we add a class to let us know
			$(this).addClass("cat-children-no");
			// we also then find and remove the toggle div we added earlier
			$(this).find('.woo-cat-toggle').remove();
		}
	});
	// if the parent category is the current category or a parent of an active child, then show the children categories too
	$('#block-12 .wp-block-woocommerce-product-categories .wc-block-product-categories-list > .wc-block-product-categories-list-item').each(function(){
		// FYI this doesn't work for block sidebar, since it doesn't have proper classes to know if it's the current category or not, so this won't actually auto pop them as coded
		if($(this).is('.current-cat, .current-cat-parent')) {
			$(this).children('.woo-cat-toggle').toggleClass("cat-popped");
		} 
	});
});

@escozul
Copy link

escozul commented May 19, 2022

Hello @PythonMillionaire,

I'm trying to find where in the jsfiddle those categories disappear. I can't find it. Could you please explain more thoroughly?
I think I'm missing an error here that is right in front of me.

@GeriSoft
Copy link

Thank you for this great solution :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment