Using Prismic within a Shopify Build
For those of you that have been following my writings you’ll know that I like to over engineer the hell out of Shopify sites :). Though, in my defense the Shopify CMS is non-existent and the Meta fields editors out there just aren’t enough.
Let’s cover the why
The client needed Wordpress style ACF fields for managing content. I’m more than experienced with using Wordpress as a headless API, but this time around I wanted to try another solution, something that was headless by default. Enter Prismic an absolutely lovely project, complete with a GUI for creating post types/groups of content/slices of content and a JSON editor. The interface is really nice for clients, and the backend is all the power I want for fetching and displaying the content. I’ve dropped in React to a number of Shopify builds now, as my goto of choice framework for fetching data and displaying it. So let’s look at my stack for this one:
- Prismic
- Shopify (Timber starter theme)
- React
- Webpack/Gulp (gulp task for handling SASS and pushing updates to shopify)
I do have a gripe with the Shopify starter theme; I feel like it should be modernized with some build tools and code minification, but the issue there is that the default Timber SASS/JS are liquid templates that actually contain a lot of information from the shopify backend so minifying it is basically a nightmare. I for the most part leave those two files alone or delete most of the contents of them as I rewrite the functionality I actually need and proceed with custom styling.
But Kevin how?!
So you absolutely have to be familiar with modern build practices, we’re going to need React, webpack, and other tools to get this all up and running. This isn’t going to be a tutorial into any of that but I am actually planning on writing a little starter react site for people interested in checking Prismic out. The most important part of our project is the Prismic API. I actually like to abstract this a little bit and set up some custom methods that I’ll actually end up using in the project:
This allows us to include the API in other files and clean up our requests just a little bit. You don’t have to do this, but I think it makes everything look nicer.
Then on any page we want to have the prismic data loaded we should set up a div that React will render into, so for the index.liquid
file:
<div class="react--load">
<div id="Home"></div>
</div>
I created a simple wrapper that extends the length of the page and can also be used as a loader, since we’re doing the rendering on the client side we have to wait for the request to complete after the shopify stuff happens, this means the content being rendered is after shopify server rendering so keep that in mind for SEO/Facebook stuff (you’ll still want to have that set up in your dom head). Then in our app.js let’s render our component:
Next let’s take a look inside a simple Home component and render some basic information from Prismic:
You’ll notice we have 2 calls in our callPrismic()
function. The first call calls a page we have in prismic with a UID defined as home
the second call is passed an array of product IDs. In prismic I have a Products content type where I set the UID to be the same as the shopify product ID. This allows for us to extend the products and add as many custom fields as we want. For those of you that have used some of the meta field editors you’re probably familiar with having to associate your meta fields with the ID of the product, this is a similar convention. We do this so we can create a product carousel of featured products within React that has actual shopify data, things like the url/name/id. We can set this up in our index.liquid
file at the top:
<script>
let products = [];
{% for product in collections.home.products limit:6 %}
products.push({id: {{product.id}}, url: '{{product.url}}', title: '{{product.title}}'});
{% endfor %}
window.__PRODUCTS__ = products;
</script>
This will expose a collection that we set into the window so we can grab it in React once React is mounted. You of course could exclude this particular bit but I had a need for it so I thought I would share how I handled the situation.
Next let’s get some custom data into one of our product pages. (Keep in mind you will need a custom type in Prismic with a UID that has the same ID as your Shopify product ID. Heres a snippet from our product.liquid
file, we’re also passing the ID so we can pass the prop into React.
<div class="react--load">
<div id="Product" data-id="{{product.id}}"></div>
</div>
Here’s an updated app.js file with our product component being mounted:
Keep in mind we don’t have the luxury of proper routing because of the limited control of the Shopify environment, but this is still fairly manageable in my opinion.
Now let’s take a look at our product component (I’ve removed a lot of my actual code just for brevity).
I’ve passed the ID in from the liquid template, and am calling Prismic with that same ID (mapped to the UID field). I then return some custom images/copy that’s being managed in Prismic.
Taking it even further?
One aspect that I didn’t touch on are webhooks, this project didn’t allow me enough time to properly dive into this, but setting up a microservice that you point a Prismic webhook too could allow you to push your Prismic updates directly into shopify, allowing you to create pages/update products depending on the type of content you are editing/updating in Prismic. This is obviously a much more advanced use case. I’ll do my best to get a microservice repo that talks to Prismic in the future and I’ll be sure to write about it.