Skip to content

Instantly share code, notes, and snippets.

@carolineschnapp
Last active July 23, 2022 15:16
Show Gist options
  • Save carolineschnapp/11352987 to your computer and use it in GitHub Desktop.
Save carolineschnapp/11352987 to your computer and use it in GitHub Desktop.
<div>
<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>
</div>
<script>
Shopify.queryParams = {};
if (location.search.length) {
for (var aKeyValue, i = 0, aCouples = location.search.substr(1).split('&'); i < aCouples.length; i++) {
aKeyValue = aCouples[i].split('=');
if (aKeyValue.length > 1) {
Shopify.queryParams[decodeURIComponent(aKeyValue[0])] = decodeURIComponent(aKeyValue[1]);
}
}
}
jQuery('#sort-by')
.val('{{ collection.sort_by | default: collection.default_sort_by | escape }}')
.bind('change', function() {
Shopify.queryParams.sort_by = jQuery(this).val();
location.search = jQuery.param(Shopify.queryParams).replace(/\+/g, '%20');
});
</script>
@Mobashir1995
Copy link

What should I need to do, if I want to do it with ajax...
Thanks for any suggestion.

@IonDaLion
Copy link

Hey guys, is there a way to change the font of the text inside the drop down?
Thanks!

@james-zedd
Copy link

james-zedd commented Apr 24, 2018

Hey all. This is a great code and I'm thankful for everyone's contribution.

I tried installing this on a new Shopify theme built with Slate, and I ran into some problems with the original code. I then swapped the JS with what @marcobiedermann posted but I had to add "sort_by" to the last line to make it work properly.

After a few tries and some help with the code, here is what I am using in my <script> tag that is working. Thanks again everyone for your contributions!

document.querySelector('#sort-by').addEventListener('change', function() {
  const urlSearchParams = new URLSearchParams(
    window.location.search.indexOf("sort_by") > -1
    ? window.location.search.replace(/sort_by/gi,"")
    : window.location.search
  );

  urlSearchParams.set(this.name, this.value);

  window.location = `?sort_by${urlSearchParams}`;
});

@zomars
Copy link

zomars commented May 14, 2018

I've took your code @james-zedd and made it so it renders the current selected option:

<div id="sort-by-container"></div>
<script>
  var currentURL = new URL(window.location);
  var currentParams = currentURL.searchParams.get('sort_by');
  var urlSearchParams = new URLSearchParams(
    window.location.search.indexOf("sort_by") > -1
    ? window.location.search.replace(/sort_by/gi,"")
    : window.location.search
  );

  var render = function (template, node) {
    node.innerHTML = template;

    node.querySelector('#sort-by').addEventListener('change', function() {
      urlSearchParams.set(this.name, this.value);
      window.location = `?sort_by${urlSearchParams}`;
    });
  };

  var SortOptions = [{
    label: 'Featured',
    value: 'manual'
  }, {
    label: 'Price: Low to High',
    value: 'price-ascending'
  }, {
    label: 'Price: High to Low',
    value: 'price-descending'
  }, {
    label: 'A-Z',
    value: 'title-ascending'
  }, {
    label: 'Z-A',
    value: 'title-descending'
  }, {
    label: 'Oldest to Newest',
    value: 'created-ascending'
  }, {
    label: 'Newest to Oldest',
    value: 'created-descending'
  }, {
    label: 'Best Selling',
    value: 'best-selling'
  }];

  var template = `
    <div>
      <label for="sort-by">Sort by</label> 
      <select id="sort-by">
        ${SortOptions.map((item) =>
          `<option value="${item.value}" ${currentParams === item.value ? 'selected' : ''}>${item.label}</option>`
        ).join('')}
      </select>
    </div>
  `;

  render(template, document.querySelector('#sort-by-container'));
</script>

@eannehope12
Copy link

Hi
Attached is a screenshot of my current set-up for Shopify. I am having trouble figuring out what to get rid of, and where to add this dropdown code. Currently, it sorts by tag, which is what we don't want. Any help appreciated!
screen shot 2018-07-20 at 12 48 02 pm

@RoohBear
Copy link

RoohBear commented Oct 6, 2018

I was able to add this without much difficulty using the Radiance theme. Thank you!

Got any ideas on how I can make the items show up in RANDOM order first? Because I have 9000 different items, it's always the first 30 or so that get the most exposure which isn't fair... I want a random product list THEN let the user do a sort.

@dhavalwd
Copy link

Thanks everyone for your awesome contribution on this. Helped me a lot. I used @james-zedd code. Only one thing I added to preserve current selection in dropdown. Below is my updated code.

Shopify.queryParams = {};
{% comment %} console.log("location", location); {% endcomment %}
if (location.search.length) {
  for (var aKeyValue, i = 0, aCouples = location.search.substr(1).split('&'); i < aCouples.length; i++) {
    aKeyValue = aCouples[i].split('=');
    if (aKeyValue.length > 1) {
      Shopify.queryParams[decodeURIComponent(aKeyValue[0])] = decodeURIComponent(aKeyValue[1]);
    }
  }
}

if (Shopify.queryParams.sort_by) {
  document.querySelector('#sort-by').value = Shopify.queryParams.sort_by;
} else {
  document.querySelector('#sort-by').value = "manual";
}

document.querySelector('#sort-by').addEventListener('change', function() {
  const urlSearchParams = new URLSearchParams(
    window.location.search.indexOf("sort_by") > -1
    ? window.location.search.replace(/sort_by/gi,"")
    : window.location.search
  );

  urlSearchParams.set(this.name, this.value);

  window.location = `?sort_by${urlSearchParams}`;
});

@tomaszbujnowicz
Copy link

I took your code @zomars and it seems to work just fine although I have some issues to get it working together with the search query on the search results page.
Has anybody been able to get that work on the search page?

@zomars
Copy link

zomars commented May 20, 2019

You need to re-add the search query in the window.location line @ tomaszbujnowicz

@tomaszbujnowicz
Copy link

Thanks @zomars but I think I have just figured it out.
Filtering search results based on these values is not possible at the moment - at least this is what I read in the docs.
I'll need to find another way, however your code works just fine for other than search results pages. Thanks ;)

@eballeste
Copy link

y'all trippin'

const $sorter = $('.js-collection-sort')
let sortBy = false

if (window.location.search.length) {
  sortBy = new URLSearchParams(window.location.search).get('sort_by')
}

//preserve current selection
// set sort value to present query
if(sortBy) {
  $sorter.val(sortBy)
}

$sorter.on('change', (e) => {
  const { value } = e.currentTarget
  
  window.location = `?sort_by=${value}`
})

@Maggie-Jimmy
Copy link

Thanks for this worked great! My "sort by" is showing stacked on the RH side of the page though while the drop down menu is showing fine on the left hand side. Does anyone know how to fix this?
image

@markostj
Copy link

@james-zedd and @zomars thank you it works great :)

@saramog
Copy link

saramog commented Oct 17, 2019

Thanks everyone, this is just what I needed? I've used your code @james-zedd and although it works perfectly, it always shows 'Featured' rather than the current selected sort order. @zomars I tried your code as you say you got it to 'preserve current selection in dropdown' which I THINK is what I mean, but that code doesn't sort at all for me. Can either of you/anyone help me show the current sort order in the drop down? Thank you in advance!

@cfxd
Copy link

cfxd commented Dec 1, 2019

I wanted something lean like @eballeste, but I also wanted to make sure that it's dependency free, that existing URL parameters are preserved, and that the active sorting method is correctly selected when a page loads. I wrote more details in a post about the right way to add a sort by dropdown in Shopify.

@mangamasta
Copy link

mangamasta commented Mar 6, 2020

Thanks, it worked great. I wanted to manipulate my code rather than relying on Shopify. Just clarification for everyone else.

Put this code inside the Collection.Liquid which can be found in your Templates Folder

<div>
  <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>
</div>
<script>

And put this code into your theme.js which can be found in your Assets Folder

Shopify.queryParams = {};
if(location.search.length) {
  for(var aKeyValue, i = 0, aCouples = location.search.substr(1).split('&'); i < aCouples.length; i++) {
    aKeyValue = aCouples[i].split('=');
    if (aKeyValue.length > 1) {
      Shopify.queryParams[decodeURIComponent(aKeyValue[0])] = decodeURIComponent(aKeyValue[1]);
    }
  }
}
document.querySelector('.sort-by').addEventListener('change', (e) => {
  const { value } = e.currentTarget;
  Shopify.queryParams.sort_by = value;
  location.search = new URLSearchParams(Shopify.queryParams).toString();
});

If you want to play around with moving the sort and changing colors etc. use CSS. You can do so by going into theme.scss.liquid which can be found in your Assets Folder
e.g. Adding the following at the end of your CSS page.

body.template-collection #sort-by {
  margin-left: 30%;
}

body is the body of the page.
template-collection is the class of that body.
sort-by is the id of where you want to use CSS.

You can right-click on your website page and find all of this information. Then its easier to find what you want to and play around with CSS.
Inspect:
image
CSS:
image

@coppinger
Copy link

After reading through the above comments and being overwhelmed, I went with this guide and it worked perfectly with a fresh ThemeKit theme posted by @cfxd:

The right way to add a sort by dropdown in Shopify

@cfxd
Copy link

cfxd commented Apr 17, 2020

@coppinger thanks for the good vibes and happy that it worked!

@alvinkonda
Copy link

Simply add the following.

    <select class="custom-select" name="sort_by" onchange="javascript:location.href = window.location.href.split('?')[0] + `?sort_by=${this.value}`;">
      {% for option in collection.sort_options %}
        <option value="{{ option.value }}" {% if option.value == collection.sort_by %}selected{% endif %}>{{ option.name }}</option>
      {% endfor %}
    </select>

@capatina
Copy link

capatina commented Jun 6, 2020

After reading all the above, here is what I think makes the most sense:

<div id="sort">
    <div class="sort-title">Sort by:</div>
    <select name="sort_by" 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>
    </select>
</div>
const sorter = document.querySelector('#sort-by');

if (sorter) {
    sorter.addEventListener('change', function () {
        const urlSearchParams = new URLSearchParams(window.location.search);

        urlSearchParams.set(this.name, this.value);

        window.location = `?${urlSearchParams}`;
    });
}

if (window.location.search.length) {
    sortBy = new URLSearchParams(window.location.search).get('sort_by');
    if (sorter) {
        sorter.value = sortBy
    }
}

@dong-qian
Copy link

dong-qian commented Jun 30, 2020

Simply add the following.

    <select class="custom-select" name="sort_by" onchange="javascript:location.href = window.location.href.split('?')[0] + `?sort_by=${this.value}`;">
      {% for option in collection.sort_options %}
        <option value="{{ option.value }}" {% if option.value == collection.sort_by %}selected{% endif %}>{{ option.name }}</option>
      {% endfor %}
    </select>

thanks, this is should be the best answer

@FrequencyRoleplay
Copy link

I signed in just to let everyone know that after much googling. Shopify has this feature but its not well know.
i decided to post this to clarify how to set the default sort type.

From your Shopify admin, go to Products > Collections.

Click a collection.

In the Products section, click the drop-down list beside Sort, and then select a sort order.

If you select Manually, then you can click and drag the products in the list to reorder them.

You can also click and select one or more products in the list. Click Move to reorder them to a specific position in the collection.
Your should be notified that it was been updated.

This helped me keep my new arrivals collection sorted by newest .
you can set each collection as desired.

Your welcome.

@hoektoe
Copy link

hoektoe commented Oct 18, 2020

Simply add the following.

    <select class="custom-select" name="sort_by" onchange="javascript:location.href = window.location.href.split('?')[0] + `?sort_by=${this.value}`;">
      {% for option in collection.sort_options %}
        <option value="{{ option.value }}" {% if option.value == collection.sort_by %}selected{% endif %}>{{ option.name }}</option>
      {% endfor %}
    </select>

thanks, this is should be the best answer

This worked , and is the simplest and best. No external JS required

@germanohaus
Copy link

Would anyone know of a way to get the same output as using ?sort_by=best-selling but programatically?
I've remade the search/filter/sort system on my landing page using a mix of js and liquid, i'm able to sort and query by any of the product's information provided by the product object, but i can't seem to find a way to query the number of times a product has been sold in order to get the best selling items.
Can anyone help me out with this?
my store is on at: store.streamspell.com in case anyone wants to better understand my case...

@eballeste
Copy link

Would anyone know of a way to get the same output as using ?sort_by=best-selling but programatically?
I've remade the search/filter/sort system on my landing page using a mix of js and liquid, i'm able to sort and query by any of the product's information provided by the product object, but i can't seem to find a way to query the number of times a product has been sold in order to get the best selling items.
Can anyone help me out with this?
my store is on at: store.streamspell.com in case anyone wants to better understand my case...

hacky but maybe create a collection that is sorted by best seller and output that collection w/liquid and work with that?

@germanohaus
Copy link

Would anyone know of a way to get the same output as using ?sort_by=best-selling but programatically?
I've remade the search/filter/sort system on my landing page using a mix of js and liquid, i'm able to sort and query by any of the product's information provided by the product object, but i can't seem to find a way to query the number of times a product has been sold in order to get the best selling items.
Can anyone help me out with this?
my store is on at: store.streamspell.com in case anyone wants to better understand my case...

hacky but maybe create a collection that is sorted by best seller and output that collection w/liquid and work with that?

That's actually the only way i was able to achieve the result i wanted.
I created a collection with that sort by default and looped through it getting the product id and setting an index value to each product.id based on their position in the new collection. That did the trick but may not be a very scalable solution for stores with large amounts of product data.
I really wish there was at least a way to see what kind of logic shopify uses in their default sort by.
Anyways, thanks!

@adigoras
Copy link

Hi All,

Would someone be able to help me with arranging the drop down filter to display the tag values in this order:

  • Size 00
  • Size 0
  • Size 1
  • Size 2
  • ...
  • Size 10
  • Size 11

(instead of the current order as in the image attached below)
image

I've tried a few things but unsuccessful in the past few weeks. Any help would be heaps appreciated.

FYI, I am using the Venture theme of Shopify. Thank you in advance!

@mythrz
Copy link

mythrz commented May 11, 2021

Hello everyone,

any ideas in how to exclude variants with price lower than 1 euro, when filtering by price?
The store has samples in every product, it is affecting the price sort :\

<div>
  <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>
</div>
<script>
Shopify.queryParams = {};
if (location.search.length) {
  for (var aKeyValue, i = 0, aCouples = location.search.substr(1).split('&'); i < aCouples.length; i++) {
    aKeyValue = aCouples[i].split('=');
    if (aKeyValue.length > 1) {
      Shopify.queryParams[decodeURIComponent(aKeyValue[0])] = decodeURIComponent(aKeyValue[1]);
    }
  }
}
jQuery('#sort-by')
  .val('{{ collection.sort_by | default: collection.default_sort_by | escape }}')
  .bind('change', function() {
    Shopify.queryParams.sort_by = jQuery(this).val();
    location.search = jQuery.param(Shopify.queryParams).replace(/\+/g, '%20');
  });
</script>

@beckjh95
Copy link

beckjh95 commented Jun 8, 2021

Thank you all for the codes! It worked for me on the Debut theme. I was just wondering if anyone knew how to add space below the sort by drop down menu as it is currently touching the product image below it. Thanks

@Munazzahafeez
Copy link

Thank you soo much. Its working perfectly fine for me. Huge Thanks.

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