Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
<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>
@carolineschnapp

This comment has been minimized.

Copy link
Owner Author

@carolineschnapp carolineschnapp commented Jun 1, 2014

Hi @typeofgraphic, sort_by only works with those values:

  • manual
  • price-ascending
  • price-descending
  • title-ascending
  • title-descending
  • created-ascending
  • created-descending
  • best-selling
@carolineschnapp

This comment has been minimized.

Copy link
Owner Author

@carolineschnapp carolineschnapp commented Jul 15, 2015

How do I change the default sorting order on the collection page, when the collection is sortable on the storefront? Example: By default, it shows the products A to Z, and I want to sort by publication date.

Answer

The type of ordering selected on the collection page in your admin becomes the default sort order on your storefront for said collection.

For example, if you order from A to Z in the admin, if you visit your collection page on your store front, the sort order will be from A to Z. From there, if you pick 'Featured' in the sort drop-down, you will see the Manual order of products as last set by yourself in your admin.

So, to change the default type of sort on your storefront, go to the admin page of your collection, and select a different type of sort.

If you're interested in changing the default order on your Catalog page, you will need to create a collection with handle “all”, and select a sort order for it.

The above is entirely done on the collection pages in your admin, and not in the theme.

@customstudio

This comment has been minimized.

Copy link

@customstudio customstudio commented Jul 17, 2015

Hi Caroline, thanks for the filtering code above. Do you know how I could set the default display order to be by vendor (as in this thread: https://ecommerce.shopify.com/c/ecommerce-design/t/sort-filter-sorting-by-vendor-and-type-161547) but still allow users the option of reordering?

@kristianbangsoe

This comment has been minimized.

Copy link

@kristianbangsoe kristianbangsoe commented Sep 21, 2015

The easy way to do this is by going to Online Store (The globe) / Navigation / and on the end of the links type ex. ?sort_by=best-selling or ?sort_by=title-ascending

@luiscielak

This comment has been minimized.

Copy link

@luiscielak luiscielak commented Sep 28, 2015

@carolineschnapp What about setting the default sort for a collection based on a type? for example /collections/types?q=shirt

@bradmadiuk

This comment has been minimized.

Copy link

@bradmadiuk bradmadiuk commented Jan 1, 2016

Thank you!

@gabebrown-freestyle

This comment has been minimized.

Copy link

@gabebrown-freestyle gabebrown-freestyle commented Jan 5, 2016

Hello, if we'd like to change the "Best Sellers" sort item to use $$ sold instead of units sold, how would we modify the search variable?

@benjaminsehl

This comment has been minimized.

Copy link

@benjaminsehl benjaminsehl commented Aug 26, 2016

Hi, @carolineschnapp!

I've done the following so that I could display the items all at once instead of a drop-down:

<!-- /snippets/collection-sorting.liquid -->
<div class="form-horizontal">
  <div class="os_categoryFilterLinks">
    <ul>
      <li><a href="#sort" data-select="manual">{{ 'collections.sorting.featured' | t }}</a></li>
      <li><a href="#sort" data-select="best-selling">{{ 'collections.sorting.best_selling' | t }}</a></li>
      <li><a href="#sort" data-select="created-descending">{{ 'collections.sorting.date_descending' | t }}</a></li>
      <li><a href="#sort" data-select="price-ascending">{{ 'collections.sorting.price_ascending' | t }}</a></li>
      <li><a href="#sort" data-select="price-descending">{{ 'collections.sorting.price_descending' | t }}</a></li>
    </ul>
  </div>
</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]);
      }
    }
  }

    var $select = $('#SortBy');
    $('a[href="#sort"]').click(function () {
        $select.val( $(this).data('select') );
        event.preventDefault();
        Shopify.queryParams.sort_by = jQuery(this).data('select');
        location.search = jQuery.param(Shopify.queryParams);
    });

  $(function() {
    $('#SortBy')
      .val('{{ collection.sort_by | default: collection.default_sort_by }}')
      .bind('change', function() {
        Shopify.queryParams.sort_by = jQuery(this).val();
        location.search = jQuery.param(Shopify.queryParams);
      }
    );
  });
</script>

Unfortunately, while the URL resolves correctly, my collection isn't sorting! Help?!

@marcobiedermann

This comment has been minimized.

Copy link

@marcobiedermann marcobiedermann commented Feb 23, 2017

This could be easily implemented with some newer APIs and ES2015 syntax. No need for jQuery:

document.querySelector('#sort-by').addEventListener('change', function() {
  const urlSearchParams = new URLSearchParams(window.location.search);

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

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

I like to use the latest web techniques and use some build tool like babel to transpile it for older browsers. Also check for URLSearchPrams support. If not, load a shim.

@Timbodas

This comment has been minimized.

Copy link

@Timbodas Timbodas commented Jun 23, 2017

Hi Caroline, I used your first code and it worked perfectly, however, I would like to align right. Right now, it's aligning left. I don't know anything about code or CSS. Please help. Thanks.

@Mobashir1995

This comment has been minimized.

Copy link

@Mobashir1995 Mobashir1995 commented Jul 31, 2017

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

@IonDaLion

This comment has been minimized.

Copy link

@IonDaLion IonDaLion commented Oct 23, 2017

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

@james-zedd

This comment has been minimized.

Copy link

@james-zedd 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

This comment has been minimized.

Copy link

@zomars 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

This comment has been minimized.

Copy link

@eannehope12 eannehope12 commented Jul 20, 2018

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

This comment has been minimized.

Copy link

@RoohBear 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

This comment has been minimized.

Copy link

@dhavalwd dhavalwd commented Dec 17, 2018

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

This comment has been minimized.

Copy link

@tomaszbujnowicz tomaszbujnowicz commented May 20, 2019

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

This comment has been minimized.

Copy link

@zomars zomars commented May 20, 2019

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

@tomaszbujnowicz

This comment has been minimized.

Copy link

@tomaszbujnowicz tomaszbujnowicz commented May 22, 2019

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

This comment has been minimized.

Copy link

@eballeste eballeste commented Jun 14, 2019

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

This comment has been minimized.

Copy link

@Maggie-Jimmy Maggie-Jimmy commented Jun 29, 2019

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

This comment has been minimized.

Copy link

@markostj markostj commented Oct 14, 2019

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

@saramog

This comment has been minimized.

Copy link

@saramog 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

This comment has been minimized.

Copy link

@cfxd 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

This comment has been minimized.

Copy link

@mangamasta 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

This comment has been minimized.

Copy link

@coppinger coppinger commented Apr 17, 2020

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

This comment has been minimized.

Copy link

@cfxd cfxd commented Apr 17, 2020

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

@alvinkonda

This comment has been minimized.

Copy link

@alvinkonda alvinkonda commented May 25, 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>
@capatina

This comment has been minimized.

Copy link

@capatina 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
    }
}
@qiandongyq

This comment has been minimized.

Copy link

@qiandongyq qiandongyq 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

@LightUpFam

This comment has been minimized.

Copy link

@LightUpFam LightUpFam commented Sep 28, 2020

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

This comment has been minimized.

Copy link

@hoektoe 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

This comment has been minimized.

Copy link

@germanohaus germanohaus commented Oct 23, 2020

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

This comment has been minimized.

Copy link

@eballeste eballeste commented Oct 24, 2020

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

This comment has been minimized.

Copy link

@germanohaus germanohaus commented Oct 24, 2020

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.