Shopp is an e-commerce plugin-in for Wordpress.

The other day I was reading this good article from ilovecolors, talking about how to do a folding menu for Wordpress with jQuery. As I wasn't really happy with the classic nested menu that Shopp offers by default, I though that this would be great and no so hard to acheive...

In fact, if you don't have any sub-categories in your website, you don't need this at all. But if, like me, you have a lot of products and you want to organise them in different categories and sub-categories, then you will understand the need of having a better solution than the default nested menu that Shopp offers at start.

Before to start, please keep in mind that I'm not a pro at coding, I'm more of a designer. So feel free to correct me if needed or to help by providing something better.
Oh, you also need to include jQuery, but normally it should be the case already with Wordpress or Shopp.

Let's go! Here is the first version.


jQuery(document).ready(function(){
 jQuery(".children").hide();
 jQuery(".active").slideDown();
});

As you can see the first version is quite short ^_^
I'm using the built-in classes from the Shopp's nested menu (using either the widget or shopp('catalog','category-list') tag). The children instances have all the .children class and when you are in a category's page, this instance has the .active class. So with this really short piece of code, you already have an easy way to hide all your sub-categories and to make them visible only in the category you're in.

Ok, so now that we have a basic way to handle or sub-categories, let's add a little bit fun.
I though it would be great to have a "roll-over" action on the categories. The goal would be to show sub-categories when the user goes over a category with his mouse. When he goes out the category, the sub-categories should be hidden again. Of course I want to use the slideDown() and slideUp() functions from jQuery to add some nice movements.

Here is the second version.


jQuery(document).ready(function(){
 // Roll over functions
 jQuery(".shopp_categories li").hover(
 function() {
 jQuery(this).children(".children").slideDown(); // Show the sub-categories
 },
 function() {
 if(jQuery(this).children("ul").hasClass(".active") == false) {
 jQuery(this).children(".children").slideUp(); // Hide sub-categories if we are not in the current category
 }
 }
 ); // End roll over
 jQuery(".children").hide();
 jQuery(".active").slideDown();
});


Using the hover() function from jQuery, I've added 2 functions. The first one will show the sub-categories when you roll-over a category. The second one will hide them if we are not in the current category. So if you click on a category or a sub-category, the menu will stay open, but if you just roll-out from this category without clicking, the sub-categories will disapear again in a smooth movement.

As the CSS classes are always the same for children instances or active instances, this script should work for an unlimited number of levels.

Now, if you have tried the code above, perhaps you've noticed a little problem. It is too sensitive.
To avoid the accidental movements or very quick movements of the mouse, we should add a delay to the animations. Just try to go from one category to another and you will see what I mean. I could have used a simple timeout function, but why do that when a really nice jQuery plugin exists? The plugin is called hoverIntent and this is what the author, Brian Cherne, says about it:

"hoverIntent is a plug-in that attempts to determine the user's intent... like a crystal ball, only with mouse movement! It works like (and was derived from) jQuery's built-in hover. However, instead of immediately calling the onMouseOver function, it waits until the user's mouse slows down enough before making the call.Why? To delay or prevent the accidental firing of animations or ajax calls. Simple timeouts work for small areas, but if your target area is large it may execute regardless of intent."


To use it, download the script on the author's page and include it in your theme like a normal javascript (after jQuery). Then we just have to use the function hoverIntent() in place of hover() and that's all!

Here is the third and last version.


jQuery(document).ready(function(){
    // Roll over functions (you can comment all the roll over part if you don't want it)
 jQuery(".shopp_categories li").hoverIntent(
 function() {
 jQuery(this).children(".children").slideDown();
 },
 function() {
 if(jQuery(this).children("ul").hasClass(".active") == false) {
 jQuery(this).children(".children").slideUp();
 }
 }
 ); // End roll over
 jQuery(".children").hide();
 jQuery(".active").slideDown();
});

Now when we roll over a category, we have a short delay before the animation goes on.


Edit: I've just noticed that by default the timeout delay is 0 in hoverIntent.js


I will add two more steps to this article, one to simplify the script (rewriting) and the other to add the hoverIntent.js configuration.
Here we go:

Rewriting


jQuery(document).ready(function(){
    // Roll over functions (you can comment all the roll over part if you don't want it)
 jQuery(".shopp_categories li").hoverIntent(roll_over,roll_out);

 // Roll over and roll out functions
 function roll_over() {
 jQuery(this).children(".children").slideDown();
 }
 function roll_out() {
 if(jQuery(this).children("ul").hasClass(".active") == false) {
 jQuery(this).children(".children").slideUp();
 }
 } // End roll over

 jQuery(".children").hide();
 jQuery(".active").slideDown();
});

As you can see I've just put the slideDown() and slideUp() functions out of the hoverIntent. Like this it's more easy to read and to modify if needed.

Finally I will add the hoverIntent configuration's object.

Final final version.


jQuery(document).ready(function(){
    // Roll over functions (you can comment all the roll over part if you don't want it)
 jQuery(".shopp_categories li").hoverIntent(
 {
 sensitivity: 7,
 interval: 100,
 over: roll_over,
 timeout: 300, // Ajust timeout to your needs
 out: roll_out
 }
 );
 // Roll over and roll out functions
 function roll_over() {
 jQuery(this).children(".children").slideDown();
 }
 function roll_out() {
 if(jQuery(this).children("ul").hasClass(".active") == false) {
 jQuery(this).children(".children").slideUp();
 }
 } // End roll over

 jQuery(".children").hide();
 jQuery(".active").slideDown();
});

With this last version, I'm able to modify the hoverIntent's default configuration. The most important parameter for me is timeout. With 300 as a value, I'm sure that there won't be any hover loops when someone goes from one category to another.
I've updated the zip file below with this last version.

Here is a demo (see the left navigation menu, under "Notre Catalogue").


Here is a zip file to download with the 2 scripts, just in case you had some problems to copy and past from this page:

To install I think the easier is to open your Wordpress theme header.php file and to include the 2 javascripts just before the </head> tag.
Of course you can use this script as you want without any restriction.
Feel free to comment this article if you find it usefull or not, and perhaps to correct my English if needed ;-)

Old Comments

nate
nate
14 avr 2010

Thank you so very much for sharing this. You saved my day!!!!!!

This works wonderful!

Claude Spengler
Claude Spengler
19 avr 2010

Happy to hear it Nate :)

Chris
Chris
17 mai 2010

Thanks this looks awesome. It is so great you are posting mods for Shopp! I have just installed this plugin but think it is awesome so far, but help with customizing is much needed. Thanks a bunch!

Chris
Chris
17 mai 2010

A little help please :) I tried this on my theme just now, I just added the code in script tags after in my header.php file, but nothing changes. What am I doning wrong? Thanks!

Claude Spengler
Claude Spengler
18 mai 2010

Hi Chris,

A link to your website would really help to find the problem.

Otherwise, did you insert jQuery BEFORE my scripts? It's needed to do this kind of magic.

Chris
Chris
18 mai 2010

Okay, not sure what my issue was but I started fresh and it is working now. Thanks, it's awesome :)

Claude Spengler
Claude Spengler
18 mai 2010

Glad to hear it Chris. And good luck for your website!

jamiebrwr
jamiebrwr
18 mai 2010

Great Article!

This would be the perfect solution to my current problem except I can't seem to get the jQuery slide effect working. Any help would be greatly appreciated.

Thanks in advance!

Website URL: http//nwaudio.net/shop

jamiebrwr
jamiebrwr
18 mai 2010

I think I may be missing the .children class on my li tags? Any idea how to add that?

jamiebrwr
jamiebrwr
18 mai 2010

Actually after looking a bit more I'm missing the .children class on my ul tag. Do you know what shopp file I would edit to add that class to the ul tag?

Chris
Chris
19 mai 2010

Hey....sorry to be a pain! I added a few more categories and now I noticed that while my slideUp isn't working when I hover over a new category. Url is badassbodyjewelry.com....Any ideas? Thanks!

Claude Spengler
Claude Spengler
19 mai 2010

@jamiebrwr
Hi Jamie,
I've visited your website and I think it's working like it should. I'm happy you finally found the solution.

Claude Spengler
Claude Spengler
19 mai 2010

@Chris

Hi again Chris!

I've visited your website too and I see that jQuery is included twice. Once from the classic Wordpress include and once from a plugin called jquery-dropdown-menu-plugin > this one is causing the problem I think. And you should not have two jQuery inclusion anyway... Perhaps you could just disable it?

By the way you should considere to disable the plugins you're not using and to check each time you enable a new one if it is not breaking something else...

jamiebrwr
jamiebrwr
19 mai 2010

Yes I found my problem. I was loading the scripts and jQuery function before tag in my header. After moving below the tag it started working!

Gilbert
Gilbert
12 juil 2010

Hi I have a question I included the jquery and both the scripts but it's not showing up...what am I doing wrong? Could you please help? Thanks!

http://www.shoobphoto.com/shop/

Claude Spengler
Claude Spengler
13 juil 2010

@Gilbert

Hi Gilbert,

I've checked your website and the problem is your left menu.

In my tutorial I'm simply using the Shopp catalog tag "category-list". I'm not sure how you are generating your menu, but you don't have any sub-category, hence why the effect is not working. With this script, the first level is of course visible, and the sub-categories are appearing when you hover a first level category.



Try to add sub-categories or to change your left menu, because otherwise it should work.



Good luck!

Gilbert
Gilbert
13 juil 2010

@Claude

So I tried that and it didn't work. Because I have some categories with subcategories but it doesn't show up like that. Could you give me an example php coding on how the catalog.php page should look?

Claude Spengler
Claude Spengler
15 juil 2010

@Gilbert

Well, I can't really give you my catalog.php page because it is highly customized, but in order to display the menu with sub-categories, you just have to use that tag:
shopp('catalog','category-list','title=<h3>Notre catalogue</h3>&hierarchy=on');
Of course it is php, not html.
The menu should appear with categories and sub-categories.

I can see in your code that you have some php code wrapped with <!?php ... ?>. Is it normal?

Gilbert
Gilbert
15 juil 2010

@Claude

Used your code and it works, thank you very much! Could you help me out with the css on how to customize it? Thanks!

And the ! is to cancel out some php coding.

Gilbert
Gilbert
16 juil 2010

@Claude

Also can you show me how in the css you get the children subcategories to indent? Thank you!

Claude Spengler
Claude Spengler
20 juil 2010

@Gilbert
Hi again Gilbert. Sorry for the late answer, but I had a lot to do... So, here is how to style your menu:
/* This is the first level */
ul.shopp_categories li {
}
/* This is the sub-categories */
ul.children li {
padding-left: 10px !important; /* this will indent the sub-cat, the !important is to overwrite other styles on this selector */
font-size: 14px;
}
With those 2 selectors, you can do almost what you want. Have fun!

Gilbert
Gilbert
20 juil 2010

@Claude

Thank you so so so so much for all your help! You are a life saver!!!

Masselyn
Masselyn
08 août 2010

Hi:

I used this on another site, and it works wonderful. If I use the Widget code for Shopp, again it is wonderful, but if I am manually creating my hierarchy of categories then I find that the menu is expanded when someone goes to a page and will only start working (collapsing when the mouse is away) if you hover over it first. Hope that makes sense, but you can see it here on a site I am finishing up (http://tre-femmes.net/?page_id=3). Can you see what might be wrong?

I am manually creating the category list because this client has a very specific order of categories they want and I was not able to achieve it another way.

Thanks for a wonderful feature, I appreciate the time you spent working and sharing it with us!

Masselyn
Masselyn
08 août 2010

Oops, I should know to try one more thing before asking for help! :)

I figured out why that was happening, because I had li classes as "children active" so it was assuming that the category was active and therefore expanded it.

Now, this brings up a point. Since I am manually creating my list, do you think that function won't work? Where if someone navigates to "necklaces-sterling silver" the sidebar won't know to show that active category and will just stay collapsed?

Just thinking out loud, I welcome thoughts!

Thanks once again.

Claude Spengler
Claude Spengler
08 août 2010

Hi Masselyn,

I'm afraid you're right. As you're making the menu manually, the script doesn't know which category is active...

drpfenderson
drpfenderson
31 août 2010

Thank you so much for this Claude. I had a really hard time doing it on my own, and your step-by-step approach made it really simple.

Just a few things: .active is now .current in Shopp 1.1.

Also, I would like to make it so that if I'm on a .current page, that part of the menu NEVER collapses. Right now it stays open, but if I move the cursor over that section of the menu and then away, it rolls up. How would you recommend going about this?

Rics
Rics
06 janv 2011

Thank you for this code Claude.
I've found it really useful!

Claude Spengler
Claude Spengler
09 janv 2011

My pleasure Rics :-)

I have not updated the code for Shopp 1.1 by the way. I hope the comment from drpfenderson will help...

micb11
micb11
21 mars 2011

Hi Claude thankyou for the script. I have uploaded my site from local host to testing server and I am getting an error in the error console in FF

If you go here http://shop.wey2creative1.com/ you can see the menu is working but if you then go onto a category page or product page the menu stops working the error is this

Error: syntax error
Source File: http://shop.wey2creative1.com/shop/category/cards-by-occasion/dad/wp-content/themes/twentyten/js/folding.js/
Line: 1
Source Code:


Error: syntax error
Source File: http://shop.wey2creative1.com/shop/category/cards-by-occasion/dad/wp-content/themes/twentyten/js/jquery.hoverIntent.minified.js/
Line: 1
Source Code:

Claude Spengler
Claude Spengler
23 mars 2011

Hi micb11,
Sorry to be late on this!
I've just checked your website and every thing seems to be ok (nice site btw).
Did you find a solution?
The comment n°26
from drpfenderson also suggests a small modification in the css classes and in the .js for Shopp 1.1...

Masselyn
Masselyn
22 avr 2011

Hi:

I am using this on a new site, running 1.1.7, and I did make note that .active is now .current. I changed those references in the code, but unfortunately it still is not woking. Any thoughts on whether there is some other piece I am missing? Thanks so much, for the support and great tutorial.

http://chocolateandsteel.com/shop

Claude Spengler
Claude Spengler
03 mai 2011

Hi Masselyn,

I think the problem is that you put the code for the menu BEFORE the
jQuery.js script. Try to put the code after and it should work.

TraciBunkers
TraciBunkers
07 mars 2012

Hi, thanks for taking the time to write the code. I have it working fine on my site using FireFox as the browser, but it doesn't work in Safari, Opera, or Chrome (I haven't tested any others. Is there something I can do so it will work in all of the browsers?

Thanks,
Traci Bunkers
http://www.TraciBunkers.com/blog/shop

TraciBunkers
TraciBunkers
07 mars 2012

I got it to work in the other browsers. I didn't have my path correct in my header for the javascript. For some reason even with that mistake it still worked on firefox, but not the others. Correcting it made it worked in the other browsers.

Is there a way to show the first subcategory for each category all the time?

Claude Spengler
Claude Spengler
09 mars 2012

Hello TraciBunkers!

I'm happy to see that this code is still working for someone ^^,

About your last question, it's possible to always show the first subcat easily. Here is what I've done for you, it should do exactly what you want:




jQuery(document).ready(function(){
// Roll over functions (you can comment all the roll over part if you don't want it)
jQuery(".shopp_categories li").hoverIntent(
{
sensitivity: 7,
interval: 100,
over: roll_over,
timeout: 300, // Ajust timeout to your needs
out: roll_out
}
);
// Roll over and roll out functions
function roll_over() {
jQuery(this).children(".children").slideDown();
}
function roll_out() {
if(jQuery(this).children("ul").hasClass(".active") == false) {
jQuery(this).children(".children .children").slideUp();
}
} // End roll over

jQuery(".children .children").hide();
jQuery(".active").slideDown();
});


You can see that when the script slideUp or Hide the content of the menu, the cibling is now ".children .children".

I hope this will help you.


TraciBunkers
TraciBunkers
20 mai 2012

Claude, I just found your reply because I was having trouble with the script. So sorry for not responding sooner. For some reason I didn't get an e-mail when you replied to me.

Now I'm having the opposite problem. The script works fine in Safari, Chrome & Opera, but not on Firefox (for mac). I tried it on my old PC in firefox, and it did work there. So maybe it has something to do with the version I'm using.

In firefox, the whole menu shows all the time, and for some reason it's causing my sub-category dropdown menu to not work. So if you click on a category in the sidebar, and it takes you to that page. Then when you click on "select a sub-category" in the dropdown menu and select a sub-category, nothing happens. But, if I remove the javascript for for folding menu from he header, then the drop-down menu works. I'm not sure what to do. It's odd it works fine in the other browsers.

TraciBunkers
TraciBunkers
20 mai 2012

I figured it out! I know nothing about coding, so I am not sure which change I made is what caused it to work in my version of Firefox. I had another javascript in my header (after yours) that worked, so I looked at some of the differences. I didn't have to change your script (the part you show here on your blog). I changed the very beginning & ending. I hope the code will show up in case it might help someone else

Here's what I now have right before your
jQuery(document).ready(function(){




traciBunkers
traciBunkers
20 mai 2012

shoot--the code didn't show up. Let me know what I need to type before or after the code for it to show and I'll redo it.

Claude Spengler
Claude Spengler
22 mai 2012

Hi TraciBunkers,

It's not really possible for you. I'm usually using the html edition in my back-office. I'm sorry for that...

Anyway, I'm happy that you did found a solution!

Erum
Erum
25 juin 2012

Hi, This used to work perfectly but ever since I upgraded to 1.2.1 for Shopp, it is acting very weird. Firstly the drop down is not overlapping the stuff on the page. Second, the links are not working. Third it just rolls up as soon as you take your mouse off the main category.

You can see it at http://jodieaziz.com

Erum
Erum
25 juin 2012

Never mind. Got it working. Thanks for this! Very useful!!!!

PS It will be nice to captcha in English. It is a bit tough to answer otherwise.

Claude Spengler
Claude Spengler
27 juin 2012

@Erum

Nice to hear that you've found a solution.
About the captcha: I know, sorry for the annoyence. In fact the CMS I'm using just changed something on it and now it's not translated anymore. I have to check that, thanks for the feedback!
Update: the captcha is translated and working again.

TraciBunkers
TraciBunkers
08 août 2012

I just upgraded to shopp 1.2.3 (from 1.1.9), and now the script isn't working--it's just a static list of categories. Is there something that I need to do so that it will work with this version of shopp? Thanks!

Claude Spengler
Claude Spengler
10 août 2012

@TraciBunkers
Hey, it's been a long time ^^,
So, I had a look to your website and the menu seems to work. What's the problem exactly?

TraciBunkers
TraciBunkers
12 août 2012

Claude, I've got it on my test blog until I can get it figured out. The shop you looked at was still using the old version of shopp, and the folding menu still worked fine on it. So please look here where I am using shopp 1.2.3:

https://www.tracibunkers.com/testblog/shop

Thanks!

Claude Spengler
Claude Spengler
16 août 2012

@TraciBunkers

Ok!!! So I had a look at the test version and it is pretty simple. All you have to do is to change the class used from


jQuery(".shopp_categories li").hoverIntent(

to this:

jQuery(".shopp-categories-menu li").hoverIntent(

Then it should work.

TraciBunkers
TraciBunkers
17 août 2012

That fixed it! Thank you so much! Now I have it working on my "real" shop with 1.2.3 shopp installed.

Do you have any idea why my category, Handmade Items, that doesn't have any products in it is showing?