Skip to content

Instantly share code, notes, and snippets.

@Lysindr
Last active September 29, 2023 14:59
Show Gist options
  • Save Lysindr/87ea06eb017a2bc58e2f9ed057b27d0f to your computer and use it in GitHub Desktop.
Save Lysindr/87ea06eb017a2bc58e2f9ed057b27d0f to your computer and use it in GitHub Desktop.
Shopify AJAX filter collection page with TAGS
<div class="collection__main">
<!-- COLLECTION SIDEBAR -->
{%- capture categories -%}
{%- for tag in collections[collection.handle].tags -%}
{%- if tag contains 'categories' -%}
{%- assign tag_patterns = tag | split: '_' -%}
<li class="collection-sidebar__filter-item main-filter" data-tag="{{ tag | handle }}">{{ tag_patterns[1] }}</li>
{%- endif -%}
{%- endfor -%}
{%- endcapture -%}
{%- capture filters -%}
{%- assign filter_title = '' -%}
{%- assign div_opened = 0 -%}
{%- assign div_closed = 0 -%}
{%- for tag in collection.all_tags -%}
{%- unless tag contains 'categories' or tag contains 'display' -%}
{%- assign tag_patterns = tag | split: '_' -%}
{%- assign heading = tag_patterns[0] -%}
{%- assign value = tag_patterns[1] -%}
{%- if value != blank -%}
{%- if heading != filter_title -%}
{%- if filter_title != blank -%}
</ul>
</div>
{%- assign div_closed = div_closed | plus: 1 -%}
{%- endif -%}
<div class="collection-sidebar__additional-filter" data-filter="{{ tag_patterns[0] }}">
<h3 class="collection-sidebar__filter-title accordion-heading">{{ heading }} <i class="fa fa-plus" aria-hidden="true"></i></h3>
<ul class="collection-sidebar__filter-items accordion-content">
{%- assign filter_title = heading -%}
{%- assign div_opened = div_opened | plus: 1 -%}
{%- endif -%}
<li class="collection-sidebar__filter-item" data-tag="{{ tag | handle }}">{{ tag_patterns[1] }}</li>
{%- endif -%}
{%- endunless -%}
{%- endfor -%}
{%- if div_opened != div_closed -%}
</ul>
</div>
{%- endif -%}
{%- endcapture -%}
{%- if categories != blank or filters != blank -%}
<section class="collection-sidebar" data-collection-url="https://{{ shop.domain }}{{ collection.url }}" data-section-id="collection-sidebar" data-section-type="collection-sidebar">
<h3 class="collection-sidebar__heading accordion-heading">Filters <i class="fa fa-plus" aria-hidden="true"></i></h3>
<div class="collection-sidebar__content accordion-content">
{%- if categories != blank -%}
<div class="collection-sidebar__categories-filter">
<h3 class="collection-sidebar__filter-title">Categories</h3>
<ul class="collection-sidebar__filter-items">
{{ categories }}
</ul>
</div>
{%- endif -%}
{%- if filters != blank -%}
<h3 class="collection-sidebar__filter-heading">Refine your selection</h3>
{{ filters }}
{%- endif -%}
</div>
</section>
{%- endif -%}
<!-- COLLECTION SIDEBAR END -->
<!-- COLLECTION GRID -->
<div class="collection-grid {% if categories == blank and filters == blank %}full-width{% endif %}">
<div class="collection-grid__header">
<div class="collection-grid__products-count">
<!-- @TODO add change products count -->
<span class="js-product-grid__count">{{ collection.products_count }}</span> products | <a href="{{ collection.url }}">See all</a>
</div>
<div class="collection-grid__sort-by">
<label for="sort-by">Sort by:</label>
<select id="sort-by">
<option value="manual">Featured</option>
<option value="price-ascending">Price: Low to High</option>
<option value="price-descending">Price: High to Low</option>
<option value="title-ascending">A-Z</option>
<option value="title-descending">Z-A</option>
<option value="created-ascending">Oldest to Newest</option>
<option value="created-descending">Newest to Oldest</option>
<option value="best-selling">Best Selling</option>
</select>
<i class="fa fa-angle-down"></i>
</div>
</div>
{% paginate collection.products by 21 %}
{%- assign products_count = 0 -%}
<div id="AjaxinateLoop" class="collection-grid__products" data-products-count="{{ collection.products_count }}">
{% if collection.products_count > 0 %}
{% for product in collection.products %}
{%- assign products_count = products_count | plus: 1 -%}
{% include 'product-grid-item' %}
{% endfor %}
{% else %}
<p class="collection-grid__empty">{{ 'collections.general.no_matches' | t }}</p>
{% endif %}
</div>
<div id="AjaxinatePagination">
{% if paginate.next %}
<a href="{{ paginate.next.url }}" class="collection__load-more">Loading More</a>
{% endif %}
</div>
{% endpaginate %}
</div>
<!-- COLLECTION GRID END -->
</div>
const cssClasses = {
collectionSidebar: '.collection-sidebar',
accordionHeading: '.accordion-heading',
accordionContent: '.accordion-content',
filterItem: '.collection-sidebar__filter-item',
filter: '.collection-sidebar__filter-items',
};
// Accordion
const accordionHeading = $(cssClasses.accordionHeading);
var endlessScroll = new Ajaxinate({
container: '#AjaxinateLoop',
pagination: '#AjaxinatePagination',
method: 'click',
offset: 150,
beforeLoad: function () {
$('.collection__main').addClass('ajax-loading');
},
callback: function () {
$('.collection__main').removeClass('ajax-loading');
}
});
accordionHeading.on('click', function () {
const parentItem = $(this).parent();
const content = parentItem.find(cssClasses.accordionContent).first();
$(this).toggleClass('open');
content.slideToggle();
});
// Tag filter
const url = window.location.origin + window.location.pathname;
const filterItem = $(cssClasses.filterItem);
let collectionUrl = $(cssClasses.collectionSidebar).data('collection-url');
var productsContainer = $('.collection-grid__products');
filterItem.each(function () {
const tag = $(this).data('tag');
if (url.indexOf(tag) !== -1) {
$(this).addClass('active');
console.log($(this), 'add class active');
const accordionHeading = $(this).parent().parent().find(cssClasses.accordionHeading);
if (accordionHeading.length !== 0) {
accordionHeading.trigger('click');
}
}
});
filterItem.on('click', function () {
let search = window.location.search;
if (search.indexOf('page') !== -1) {
const pageParam = search.split("&")[0];
search = search.replace(pageParam, '').replace('&', '?');
}
const filter = $(this).parents('[data-filter]');
const filterItems = filter.find(cssClasses.filterItem);
/* var addActiveClass = true;
if ($(this).hasClass('active')) {
addActiveClass = false
}
filterItems.removeClass('active');
if (addActiveClass) {
$(this).addClass('active');
}*/
$(this).toggleClass('active');
var activeItems = $('.collection-sidebar').find(cssClasses.filterItem + '.active');
var activeTags = [];
activeItems.each(function (index, el) {
var tag = $(el).attr('data-tag');
if (tag) {
activeTags.push(tag);
}
});
var tagsUrl = activeTags.join('+');
var newUrl = collectionUrl;
if (tagsUrl) {
newUrl += '/' + tagsUrl;
}
newUrl += search;
$('.collection__main').addClass('ajax-loading');
console.log(newUrl);
console.log('---');
$.get({
url: newUrl,
success: function (data) {
var newProductsWrapper = $(data).find(".collection-grid__products");
var newProductsHtml = newProductsWrapper.html();
productsContainer.html(newProductsHtml);
var newItemCount = newProductsWrapper.attr('data-products-count');
$('.js-product-grid__count').text(newItemCount);
var newPaginationHtml = $(data).find("#AjaxinatePagination").html();
$('#AjaxinatePagination').html(newPaginationHtml);
var pagination = $("#AjaxinatePagination");
if (pagination.length) {
pagination.html(newPaginationHtml);
new Ajaxinate({
container: '#AjaxinateLoop',
pagination: '#AjaxinatePagination',
method: 'click',
offset: 150,
beforeLoad: function () {
$('.collection__main').addClass('ajax-loading');
},
callback: function () {
$('.collection__main').removeClass('ajax-loading');
}
});
}
history.pushState({
page: newUrl
}, null, newUrl);
$('.collection__main').removeClass('ajax-loading');
}
})
});
@mrpetreli
Copy link

Hi, how do I add to shopify...could you point me into a tutorial?

@CisForChi
Copy link

this doessn't seem to be working? is there any code missing from this gist?

@CisForChi
Copy link

if you could email me at hi@chiaracodes.com i would forever be grateful!

@Lysindr
Copy link
Author

Lysindr commented Jun 3, 2020

@CisForChi hi!
This gist was added many time ago so, i don't know is it working on current time.
But, first that you need to check is:
Do you add the "Ajaxinate" js script to the your store?
Link: https://ajaxinate.elkfox.io/
You need add this script at first, try it.

@nobelnrj
Copy link

Hey @Lysindr, I implemented this in my project and it worked perfectly. Thank you.

@FearTheWild
Copy link

FearTheWild commented Jun 14, 2021

I've tried implementing this code but I get a 404 error on the $.get returning [object%20Object] - Are there any certain data attributes or classes the product-grid-item needs perhaps I'm missing?

EDIT: I have managed to get it working for my scenario. Thank you, still works with slight tweaking depending on your situation.

@elliotkidd
Copy link

Anyone checking this out now, I needed to change $.get to $.ajax.
I then ran into a CORS issue when developing locally using Shopify CLI theme serve, but in the live environment that isn't an issue.

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