Shopify AJAX API vs capture “hack”: Product object

Most recently, we developed a web app for a makeup company called The Lip Bar that allows it’s customers to find the best foundation shade based on their complexions or on their current foundations from another company. We knew right off that that we’d have to use Javascript to get this done, so why not do as much of it as possible in Javascript from the start?

The problem is, we needed to get ahold of some metafield data that, at the time of this article, wasn’t easily available via the AJAX API. After some deliberation and a lot of googling… google-ing?, we settled on the “hack” solution we’ll go over in this tutorial.

Before we dive in, I want to appease the people got here with the intent of simply using the AJAX API to get the product object. There’s nothing worse than clicking into a promising post only to find that the information you needed wasn’t there.

Not to mention, the searches we’ve found on this can be strangely vague, so here you go… You’ll need to add jQuery and the AJAX API scripts to either your theme page or the page you’re working in:

{{ '//ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js' | script_tag }}
{{ 'api.jquery.js' | shopify_asset_url | script_tag }}

Then in your script:

$.getJSON( '/products/product-handle-here.json', function( product ) {
  // Do stuff with your product object here
})

Hopefully that helped.

Now, on to the hack. We’ll be using the capture tag. Maybe you don’t consider this a hack, but we do because we don’t feel that this is how Shopify intended for this to work and as a warning, it’s fairly delicate in that if you don’t account for potential errors or missing data, your object could break. So use with caution!

Basically, what we’re going to do is build an object within liquid that our javascript then has access to. It feels totally wrong, almost like writing HTML in Javascript, but it worked for our needs and in a way, it might be slightly lighter than the AJAX API as it gives you the opportunity to only add the data you need into your object rather than getting all of the data from the API.

In our case, we needed to make a JSON of product objects from a specific collection with metafield data from a namespace called ‘brands’. Here’s how we did it:

{% capture 'complexionsObj' %}
  {
    {% for product in collections['complexions'].products %}
      {% if product.type contains 'Foundation' %}
        "{{ product.title }}" : {
          product : "{{ product.handle }}",
          image : "{{ product.images[1] | img_url: 'medium' }}",
          {% if product.metafields.brands.brand %}
            brands : {
              {% for brand in product.metafields.brands.brand %}
                "{{ brand }}" : "{{ product.metafields.brands.products[forloop.index0] }}",
              {% endfor %}
            }
          {% endif %}
        },
      {% endif %}
    {% endfor %}
  }
{% endcapture %}

Here’s what’s happening. In liquid, we begin the capture tag and name the variable ‘complexionsObj’. Then we open the object with an opening curly bracket. We then loop through all the products in a specific collection with:

{% for product in collections['complexions'].products %}
{% endfor %}

Within that for loop, if the product type is ‘Foundation’ we create a product object with the title as the key.

NOTE: because this is sort of ‘hacky’, its important to put unknown variables in quotations. The object is very picky and if there’s some weird stuff in the title of your product, you might end up with a broken object.

Next we set the key ‘product’ to the products handle, and the ‘image’ key with a product image (In our case, the second product image.)

After this, we check if the ‘brands’ metafield exists, and if it does, we create a ‘brands’ key and loop through the brands metafield. Notice the forloop.index0. This is just the index of the loop starting at 0.

Finally we close our object with the closing curly bracket.

Lastly, at the bottom of our page, we give Javascript access to the complexionsObj variable with the following:

<script type = "text/javascript">
  let complexionsData = {{ complexionsObj }}
</script>

Now when we console our complexionsData variable, we have a JSON object with all the data we need and none of the extra stuff to slog through.