Using URL Hash to Load a jQuery Drop Down Already Open

I’ve written about how I create jQuery drop down content blocks, and it’s a technique I continue to use all the time (including on my own FAQ page). I’ve found it useful in my FAQ implementation to be able to link to a particular question and have it load the page with that answer open and visible, so in this post I’ll share the modified code that makes that happen.

Deep link to an open drop down content block

The implementation is made up of some HTML markup for the content, some CSS to style it all, and then a bit of jQuery to create the dropdown effect.

Markup

The markup for this FAQ block is like this (repeated for each Q&A pair):

<div class="faq-block" id="topic-slug">
    <h2 class="question">Question</h2>
    <div class="answer">Answer text here</div>
</div>

Each ID is unique, as is required in HTML, and the ID is also what gets added to the link to determine which answer is open on load. For example, if you head to my FAQ page with #hosting on the end, you’ll jump right to the FAQ block div with that ID, and it will display with the answer visible.

Try it if you’d like: http://zoerooney.com/about/faqs/#hosting

Styling

Per usual with these tutorials I’m not going to include all my styling code, but the main things you’ll want to keep in mind are to do with the hover effects. You’ll want to make sure your questions have a nice hover interaction, and you’ll probably want to give them cursor: pointer; so they look clickable.

Additionally, I’ve found that padding and margins inside the answer content can make the open/ close interaction look a little jumpy, so if you’re seeing that issue check your padding and dimensions.

Interactions

The script to make the dropdown interactions work uses jQuery, so you’ll need to make sure your theme or site is already loading jQuery or you’ll need to add it.

Then, here’s the script you’d add to the page:

<script>
jQuery(document).ready(function($){
    // Hide the answers using jQuery
    $('.answer').hide();

    // Open the answer if we've linked directly to a question
    if(window.location.hash) {
        var hash = window.location.hash;
        $('.faq-column').find(hash+' .answer').show();
    }
    // Toggle when clicking questions
    $('.question').click( function() {

        $(this).next().animate({

            // The combo of height and opacity gives a nice open-and-fade effect
            height: 'toggle',
            opacity: 'toggle',

        });
    });       
});
</script>

The only part of this that is different from the original tutorial is this bit:

// Open the answer if we've linked directly to a question
if( window.location.hash ) {
    var hash = window.location.hash;
    $('.faq-column').find(hash+' .answer').show();
}

This checks the window for a hash in the URL – if it finds one, then it assigns it to the variable hash.

Then, it finds the .answer block within the element with that ID (that’s a helpful thing about URL hashes – they are the same format as IDs so you can use them to select an element), and shows it.

The $('.faq-column') bit makes sure we’re just looking within that column on the page, the .find(hash+' .answer') bit finds the correct element with the hash as its ID and then finds the child answer within it. The .show(); bit shows the answer, negating the $('.answer').hide(); line from earlier in the script block.


I use this feature on my FAQ all the time since it lets me direct people who’ve asked me a question to the exact answer they need on the page (hosting is the most common one I use, I’d say).

ADVERTISEMENT

WP Engine Spring Sale special offer code SPRINGTIME for 33% off the first 2 months

Q, but no A: On Growth, Pricing, and Loving Your Work

Warning: there is a lot of pondering in this post and very little in the way of advice or answers. If you have answers, I would love to hear them, though!

Not to long ago I shared some links on pricing and I mentioned that it’s a topic that is pretty much always on my mind. This is partly because I have to think about it every single time I write an estimate or send an invoice, and partly because I’m always thinking about what’s next both personally and professionally, and like it or not income plays a role in that line of thought.

A couple weeks ago, I was feeling particularly unclear about my long-term direction as a business owner so I took to Twitter, as happens in such situations:

A couple of themes emerged in the conversation, with a lot of people as completely as unsure as I am (which is reassuring), and others talking about plans for saving and/or for shifting to product-based businesses with less emphasis on client services:

One of the things that was underneath asking these questions in the first place is that I have really struggled with figuring out how to grow my business, and recently that has manifested in questioning whether I should even grow my business at all.

After a couple of years of very slow incremental growth, I’ve actually started shrinking my business back down as I try to figure out (a) what I actually want this business to look like and (b) if scale is really possible with the type of work I want to take on.

As mentioned in a couple of those pricing articles, once you have a certain level of demand, one solution is to raise your prices.

I have worked really hard and have been really fortunate and am now pretty consistently booked out weeks in advance. I’ve been able to raise my prices continuously.

But the thing about raising prices is that at a certain point you price people out. Sometimes that’s okay, or even necessary, and I’ve raised prices and then found myself left with better fit clients.

On the other hand, I really love working with individuals and micro-businesses and people doing interesting, creative, but not necessarily big money things, and I fully understand and respect that those people have real budgets to contend with.

From what I’ve seen around the industry, company growth often goes hand-in-hand with larger projects. Scale in company size and you’re looking at working with larger companies as clients, potentially more “corporate” clients, and so on. That’s not really at all (let’s be honest) what I want.

So for now, that’s left me at scaling my company back down a little bit, keeping my prices somewhat stable this year, and doing a lot of reflecting on what this business means to me, how I want it to work and feel and be, and what that might mean longer-term.

My tendency is to be very goal- and data-driven, and to have a plan and be working on it at all times, but I’ve also realized that it’s completely okay and normal to change my mind about what I want for my business over time. Not only okay and normal, but it’s probably a good thing, because goodness knows staying stagnant in this business is dangerous.

Three Quick Links: Search Engine Optimization (SEO)

Three quick links related to search engine optimisation (SEO)

SEO is not one of my favorite topics, mainly because of how it’s often talked about in the business blogging/ services for online businesses world (as a big scary thing that you have to bend over backwards for, potentially involving keywords and shady tactics).

That said, a strong presence in the results for relevant search terms is important, so I do try to keep up on my SEO-related reading so I’m aware of general (non-shady) best practices. In honor of next week’s changes in Google’s algorithms (see #2 below), here are three especially strong articles I’ve read recently on search engine optimization:

1

I feel like I link to Arianne’s articles a lot, but she’s got a lot of experience in the online world and also we tend to have similar perspectives on a lot of topics. Her recent post on why you don’t really need to worry that much about SEO is a great example – I nodded my head all the way through it.

2

You’ve probably heard about Google’s upcoming changes (effective next Tuesday) to their algorithms that incorporate mobile-friendliness as a ranking factor. This post right from the source introduced these changes back in February. The gist, from what I’ve read, is that this will mainly have an impact on mobile searchers’ results (e.g. if you are searching on a mobile device, this algorithm update will impact your results).

To sneak in an extra reference, I especially liked the way this was interpreted in this Practical E-commerce post, where they closed with:

[I]f mobile search doesn’t play a significant role in your organic search performance today, the mobile-friendly update represents a continuing loss of opportunity rather than an abrupt loss of existing visits and sales.

3

Another recent change in the algorithm relates to HTTPS and SSL, which I think is very interesting (especially if you get into the nuances of how SSL impacts Google Analytics data). There’s a great article over on the Moz Blog with tips and tricks related to SSL and SEO.

Shopify Product Breadcrumbs with Tag Support

Shopify product breadcrumbs with tags and hierarchy

Somehow this turned into Shopify breadcrumbs week, because today I’m writing about incorporating tags into them again, this time on product pages (yesterday I talked about tag breadcrumbs in a blog context). Better than talking about how today is tax day here in the U.S., I suppose!

Getting tags to show on the product page is way more involved, as it’s a different model compare to showing relevant tags on a blog archive page (a “tag page”) or on a collection page.

Context

I feel like this is hard to explain – I alway struggle with it when it comes up with clients – because it gets into the various objects within Shopify and how they relate to each other.

Both blogs and collections have tags as part of their object, and that’s what we’re using when we display the tag info and use it on the page. Products have tags, too, but they’re the list of tags assigned to the product.

In the context of breadcrumbs, we’re interested in the path someone took to the product, which includes a tag in some cases, and that tag is also one of the product tags. Generally this happens when someone is using a collection that is then filtered by a tag in the Shopify navigation lists (this is a setting they offer, so it’s not unusual).

If you get to a product by way of a collection page, the collection is transferred to the product page as part of the URL when you use {{ product.url | within: collection }}.

By contrast, any tag that was part of the path to the product isn’t delivered to the product page. That’s why there’s no built-in way to display it or get info about it.

This is a Hack

I’m going to go ahead and call the method I came up with to solve this problem a hack. It does work, but there are a few assumptions it makes and it relies on jQuery to display the tag link client-side.

Assumptions

Here are a few of the assumptions I’m making with this code:

  • The store is using collections as top level menu items and tag-filtered collections as submenus/ drop downs, creating a category/ subcategory structure
  • The product breadcrumbs should follow that hierarchy by displaying as Collection > Tag
  • The nav menu has an active class added to the top level item when appropriate
  • The theme is loading jQuery already

Limitations

I’ve tested this pretty thoroughly with the above assumptions in place, but there are some corollary limitations I’m aware of that you should know about if you’re thinking about implementing this:

  • I haven’t tested this with tag-filtered items as the top level, but I think there would be issues
  • It also wouldn’t work as-is with separate collections as the second level (subcategories) since it uses both the collection in the URL and the tag
  • If you’re filtering by multiple tags that are all in the collection subnav, only the first one alphabetically will be in the breadcrumbs
  • If you’re filtering by tags that are not in the collection subnav, there won’t be tags in the breadcrumbs at all (just the collection), which I think could be in “feature not bug” territory but is worth mentioning

There are probably other limitations and unsupported edge cases, if you think of or find one please post it in the comments.

Technique

So now that I’ve thoroughly introduced this method, let’s look at how it works. There are three steps to this:

  1. Modify your links to your products on your collection page to include the tag as a URL parameter, thus giving us something to work with on the product page
  2. Modify your navigation menu to include some extra tag data on the submenu items
  3. Create your breadcrumb structure to display on the product page

I’ll show you the code I’ve used for each of these steps as an embedded Gist and point out some of the highlights.

1. Product Links

As mentioned previously, the URL for products on the collection page generally already includes the collection in it via this template tag:

{{ product.url | within: collection }}

If you didn’t include that | within: collection filter, your link URL for your product would look like this:

http://store.myshopify.com/products/product-handle

By contrast, the filter gives you a URL to your product that includes the current collection:

http://store.myshopify.com/collections/collection-handle/products/product-handle

Since we need to also pass through the current tag (if there is one) in the URL so that we have that info on the product page, I’ve added a URL parameter in my link code:

This is the additional code:

{% if current_tags %}?tag={{ current_tags.first | handleize }}{% endif %}

If there are currently tags in use on the collection page, it adds the URL parameter and includes the first of the current tags (alphabetically). The tag name is run through the | handleize filter to make sure it’s lowercase and matches the tag slug/handle format.

That way, when you get to the product page you have both the collection and the tag in your URL to work with, like so:

http://store.myshopify.com/collections/collection-handle/products/product-handle?tag=tag-handle

If you’re looking for where to put this modification in your theme, start with collection.liquid, although it may be in a snippet (or multiple snippets, if each product has multiple links, e.g. around a thumbnail and around the title).

2. Navigation Data

Having the tag to work with on the product page is an important first step, but it’s just the tag slug and that doesn’t actually get you very far as far as displaying a link to the tag and its name.

In fact, once I started to think about this, I ran into another potential breadcrumbs issue, which is that the navigation list items can have completely different labels than the actual tag names and collection titles. In the context of breadcrumbs, what should you display?

For tags, I think it’s definitely the label as shown in the navigation, although for the top level collection I think it could go either way.

For my solution, I decided I wanted to use the navigation labels for both collection and tag in the breadcrumbs to mirror the navigation structure.

I needed a few different things to match up my collections and tags to my navigation structure:

  • I needed to know which collection is the active or parent of the product
  • I needed to be able to get the collection name from the active item (this happens in the next step)
  • I needed to be able to match up my tag URL parameter to a navigation item in the menu
  • I needed to be able to display the tag URL and the tag name from the navigation item in the breadcrumbs (this happens in the next step, too)

Here’s how I ended up setting up all this info in the navigation menu code:

The {% if link.active %} class="active"{% endif %} bit on the parent link is standard – that’s a Shopify construct that tells you which link is active and handles parent collection relationships nicely.

My main additions were in the submenu (this is often found in theme.liquid although some themes may put it in a snippet – it’s the main site category navigation):

{% assign parenthandle = link.url | remove: '/collections/' %}
     {% for link in linklists[handle].links %}
          <li>
               <a href="{{ link.url }}" data-tag-slug="{{ link.url | remove: '/collections/' | remove: parenthandle | remove: '/' }}" data-tag-name="{{ link.title }}" >
                    {{ link.title }}
               </a>
          </li>
     {% endfor %}

The first line of this snippet is getting the parent link URL and removing the /collections/ bit, which results in the parent collection slug. I needed that so I could remove it from the tag URL structure.

Then, on the submenu link (the link to the tag-filtered collection page), I’ve added two data attributes that contain key tag information.

The {{ link.url }} structure for those submenu items looks like this:

/collections/collection-slug/tag-slug

I wanted to extract just the tag slug so that I could later match it up with my URL parameter, and I also wanted to put the tag link label as a data attribute so that I could easily grab it with jQuery.

The tag name as done in the navigation list was easy enough:

data-tag-name="{{ link.title }}"

For the slug, I ended up using that link URL and removing everything else. Not the most elegant thing in the world, as we have to remove three different sets of things (the /collections/ base, the collection slug, and the last backslash) but it works pretty nicely:

data-tag-slug="{{ link.url | remove: '/collections/' | remove: parenthandle | remove: '/' }}"

With that done, the submenu link markup looks something like this:

<a href="/collections/collection-slug/tag-slug" data-tag-slug="tag-slug" data-tag-name="tag label in nav">tag label in nav</a>

Lots of data in there, ready to go!

3. Breadcrumbs Structure

Finally, this all gets put together in the actual breadcrumbs structure:

This looks longer than it really is because I’ve put a lot of comments into the script section to narrate what’s going on there. If you’re adding this to your theme, it’s probably best added as a snippet, then included into product.liquid, just to keep things nice and tidy.

In the first segment, we’ve got the markup for the breadcrumbs, starting with a “Home” link and the link to the collection page we came from:

<div class="breadcrumbs">
    <a href="/" class="homepage-link">Home</a>
    {% if collection.handle %}
         > 
        {% capture url %}/collections/{{ collection.handle }}{% endcapture %}
        <a href="{{ collection.url }}" class="collection-link">
            {{ collection.title }}
        </a>
    {% endif %}
    <span class="bc-tags"></span><!-- this is a placeholder for the tag if there is one -->
</div> <!-- end .breadcrumbs -->

As you can see in the comments, I’ve added a placeholder span <span class="bc-tags"></span> that will be the container for a tag breadcrumb link if we are able to add one. If there aren’t any usable tags, that span collapses and isn’t visible.

Then, the rest of the work happens in jQuery (you’ll need to make sure you’ve already got jQuery included in your theme). The jQuery is pretty well commented so I won’t go line by line, but I wanted to point out a couple things.

Replacing Collection Titles

As mentioned, I decided for the site I was working on to replace the collection titles with the label for the collection in the navigation menu. For this particular site, they were different in many cases and the labels were more detailed and likely to be helpful.

These are the lines in the jQuery that get the collection label and use it to replace the collection title in the breadcrumbs:

var parent = $('.active').text();

// update the displayed collection title to match the nav item label
$('.collection-link').text(parent);

If you just want to display the collection title normally, delete or comment out those lines.

Then, a bit lower I’ve got a conditional to check if there’s a tag URL parameter. I included some console.log() outputs in this code because i found them helpful as I was building this to double check my work, but you could remove those if you want.

If there is a tag parameter, I’ve used jQuery to match up the URL parameter to a link in the navigation using that data-tag-slug attribute:

// find the nav item for this tag using the data attribute for the slug
var tagElement = $('a[data-tag-slug="' + tag + '"]');

Then, I grab the tag display name from that element using my data-tag-name attribute:

// get the display name from the other data attribute
var tagname = tagElement.data('tag-name');

Data attributes are my favorite.

Finally, I spit out the link into the breadcrumb:

$('.bc-tags').html(' > <a href="/{{ collection.url }}/' + tag + '">' + tagname + '</a>');

That gives me the desired hierarchical breadcrumb structure!

Results

If you’d like to see this in action, check out Three Bird Nest, a project I recently worked on with Aeolidia (I did not code the whole site, just some bits and pieces including the updated breadcrumbs).

Here’s how it looks, for quick reference:

sample product breadcrumbs

(This is actually sort of killing me because now I’m thinking about how I could probably apply the same technique (more or less) to blog posts reached via the tag archive pages I talked about yesterday. There’s always something, right?)

Shopify Blog Breadcrumbs with Tag Support

Shopify blog breadcrumbs with tags

This snippet came up when a client reported that their blog breadcrumbs didn’t include the tag when you were on a tag archive.

While not really a bug because nothing was broken, I realized that most breadcrumbs snippets for Shopify are missing this feature and it’s a perfectly reasonable thing to expect to see, so I added it into their site.

Here’s the full updated blog breadcrumbs snippet:

<div id="breadcrumb">
    <a href="/" class="homepage-link" title="Back to the frontpage">Shop Home</a>
    {% if current_tags %}
        <span class="seperator">|</span> 
        {{ blog.title | link_to: blog.url }}
        <span class="separator">|</span>
        {{ current_tags.first }}
    {% else %}
        {% case template %}
        {% when "article" %}
            <span class="seperator">|</span> 
            {{ blog.title | link_to: blog.url }}
        {% endcase %}
        <span class="seperator">|</span>
        <span class="page-title">{{ page_title }}</span>
    {% endif %}
</div>

This will display breadcrumbs like so:

Shopify blog breadcrumbs example

That screenshot is from one of those tag archive pages, e.g. if you clicked into the blog category/tag page for “Kid Stuff” to see all the posts with that tag. Both Shop Home and Blog are clickable.

You can check it out live on Sea Urchin Studio, an Aeolidia project. I did not code the bulk of that site, but I really loved tackling a few updates – such gorgeous artwork!

Interestingly, the documentation on breadcrumbs does include tags in the breadcrumbs, but only in the collections context, not in the blog.