Skip to main content

Building a Shoppable Posts mini

What will you learn?

In this guide, you'll learn how to do the following:

  • Create a mini from a template.
  • Set up an extension.
  • Accept data from an entry point.
  • Render a list of posts.

Prerequisites

This guide assumes that you have your test store set up and that you have already been onboarded to the Minis Platform.

Step 1: Use the Shoppable Posts template to create your mini

The CLI provides some templates for common use cases for a mini. That includes a template for mini that displays a list of images and products related to each image. We call this template "Shoppable Posts".

npm init @shopify/shop-mini@latest

Follow the prompts and choose the Shoppable Posts template when asked.

Step 2: Set up your mini's extension

When you created your mini, you would have been prompted to create an extension. If you chose to create an extension, you may proceed to the next step. If you didn't, you can run the shop-minis create-extension command to create one. We'll choose the Link extension at the Product Page - Before Variants Picker target for this example.

npx shop-minis create-extension

The Link extension comes with a basic query input.graphql that fetches the product's title. This data will be passed into the mini.

Step 3: Reading data from the extension

In your mini you can see the template code using the useMinisParams() hook to get an extensionData object which contains data that the extension has fetched.

const {extensionData} = useMinisParams<MyExtensionDataType>()

The useMinisParams hook above is assigned a stub type to gives typing to extensionData. We can replace it with the type generated from the extension's input query.

import {ProductVariantsRenderBeforeQueryData} from './targets/shop.product.variants.render-before/input.graphql'

// ...

const {extensionData} = useMinisParams<ProductVariantsRenderBeforeQueryData>()

Now we can access the shop's ID from the query.

Step 3: Fetch image URLs from a product metafield

Before we continue with this step, please follow the guide on metafields first. This step assumes that your products have a metafield with the key of images and the type list.url.

Let's update our extension's query to fetch URLs of images related to the product.

query ProductVariantsRenderBefore {
product {
id
title
images: metafield(namespace: "app--12345--foo", key: "images") {
value
}
}
}

Now lets start the mini dev server.

npm start

Navigate to the product screen to load your Link extension and press on it to open the mini. We'll see that the extensionData now contains a stringified array of image URLs from the metafield.

Step 4: Rendering a list of posts

In the template code we can see usage of a ShoppablePosts component. The component is using data from a fixture variable shoppablePostsFixture.

Now that we are able to query custom data from the product metafield, we can explore the shape of shoppablePostsFixture to see what data we have to provide to the component. We can add more metafields if needed.

Eventually, we should be able to replace shoppablePostsFixture with data from the query and / or other sources.

Step 5: Customizing your Shopable Posts mini

You can customize the look and feel of your Shoppable Posts mini by using the ShoppablePosts component's props. You can find the full list of props here: ShoppablePostsCustomisationProps.

Example

// ...
<ShoppablePosts
items={shoppablePosts}
shopId={shopId}
fetchMoreByShopId={fetchMoreByShopId}
renderMedia={({item}) => <CustomCarouselPost images={[imageStack(item.image.url)]} />}
/>
// ...

Feed screen of a Shoppable Posts Mini with custom UI

// ...
<ShoppablePosts
items={shoppablePosts}
shopId={shopId}
fetchMoreByShopId={fetchMoreByShopId}
renderItem={({item}) => (
<View>
<Image
source={{uri: item.image.url}}
style={{width: '100%', height: 500}}
resizeMode="cover"
/>
<Pressable
onPress={() => setShouldShow(!shouldShow)}
style={{
height: 20,
width: 20,
borderRadius: 20,
position: 'absolute',
backgroundColor: '#c3c3c3',
borderWidth: 1,
borderColor: '#ffffff',
top: 280,
left: 100,
}}
>
{shouldShow ? (
<View
style={{
position: 'absolute',
top: 10,
left: 20,
width: 200,
height: 200,
}}
>
<ProductLink
product={FIXTURE_PRODUCT}
shopId={shopId}
/>
</View>
) : null}
</Pressable>
</View>
)}
/>
// ...

Feed screen of a Shoppable Posts Mini with custom UI


Feed screen of a Shoppable Posts Mini with custom UI

// ...
<ShoppablePosts
items={shoppablePosts}
shopId={shopId}
fetchMoreByShopId={fetchMoreByShopId}
renderHeader={() => null}
/>
// ...

Feed screen of a Shoppable Posts Mini with custom UI

// ...
<ShoppablePosts
items={shoppablePosts}
shopId={shopId}
fetchMoreByShopId={fetchMoreByShopId}
renderMediaFooter={({item}) => (
<Box flexDirection="column" margin="gutter">
<Text variant="bodySmall">{item.description}</Text>
<DisplayDate date={item.displayDate} />
</Box>
)}
/>
// ...

Feed screen of a Shoppable Posts Mini with custom UI

We look forward to seeing what you build!