Shopify is a fantastic ecommerce platform. That said, amazing shopping experiences often require some degree of customization that the platform doesn't offer out of the gate. For example, a company selling vehicle tires may want to help customers find the correct rims for those tires. Not all tires fit all rims, so there has to be some logic somewhere that understands which products can be recommended with which other products.
Shopify isn’t an auto parts specific ecommerce platform, so it doesn’t have the concept of tires or rims, or tools to really pair products at all. With a Gadget application though, we can extend the Shopify data model to support new ideas like “product pairings”, and build an interface for a merchant to manage this data. We can then access the data from our Gadget app to drive a storefront widget that recommends related products, increasing basket size and sales for merchants.
We’d like to produce a storefront widget for the product description page in a Shopify storefront that lists a set of other products, known to be compatible with this one. This suggests that for each product, we need to be able to fetch a list of other products paired with that product. This kind of association between different rows of data is well supported in Gadget using a Relationship field. Relationships in Gadget can be used to capture data models like “a blog has many images, and has many comments”, or “every order belongs to a customer”.
In our case, we’re relating the Shopify Product model back to itself where one product row is paired with another Shopify Product row. And, since one product can have many different paired products, we use the HasMany Through relationship type in Gadget. This is an advanced relationship type that models a many-to-many relationship using a new intermediate model which has one record per unique combination of related models on either side. In this case, we’d pair product #123 and product #456 by creating a new Product Pairing record pointing to both #123 and #456.
To create this relationship, we set up a new, Gadget-owned model called Product Pairing, and add two outgoing Belongs To relationships to it, both to the Shopify Product Model. We can then create our Has Many Through relationship on the Shopify Product model pointing back to itself, using the Product Pairing model as the intermediate model. For more information on Has Many Through relationships, see the Gadget Guides.
The easiest way to show customers the paired products for a given product is using Shopify’s existing theme system. That way, we inherit all the merchant’s styling, and can re-use any existing theme snippets for displaying. Many Shopify themes have a related products snippet built in (that doesn’t offer the merchant any control over which products are paired with each other) which we can reuse.
Data access for Gadget is usually done by making calls to your Gadget application’s GraphQL API, but in this case, Liquid doesn’t support making calls. Instead, we must write our data back to Shopify as a metafield.
We can add a code snippet to our Product Pairing model’s behaviour that automatically syncs the list of paired products back to Shopify every time a pairing is created or deleted, keeping the two systems in agreement.
With this metafield saved to Shopify, we can then reference it in our liquid theme:
For many Shopify shop owners, it’s important that they be able to update their own site, without having to bother their agency or developer to make small changes. So, Gadget makes it easy to build a merchant-facing front end for data administration! We’ve put together an example of a React frontend for this app in our examples repo here, and soon, Gadget’s built in UI builder will make this even easier.
Gadget provides a simple, fast way to build custom extensions to Shopify. No time is spent wiring up webhooks, deploying new servers, debugging OAuth, or discovering fun new “quirks” of the Shopify API. Instead, we can immediately start building solutions to a real merchant problem with Gadget’s expressive primitives, and deliver something that meets their needs quickly.
Astute readers may have noticed that the Product Pairing model is directional. If a Product Pairing record exists with #123 as Product A, and #456 as Product B, it means #456 is paired with #123, but not vice versa. Has Many Through relationships work in this directional manner so you can model things like Twitter relationships -- if user A follows user B, it doesn’t mean that user B is now following user A also. In the case of some e-commerce use cases though, like rims and tires, it does make sense that if a tire works with a rim, the rim works with the tire also. Gadget allows us to add business logic to our application to capture this complexity. Instead of the merchant needing to create product pairings from both A to B and from B to A, we can use Gadget behaviour to automatically create the inverse pairing for them if it doesn’t exist already.