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)]} />}
/>
// ...
// ...
<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>
)}
/>
// ...
// ...
<ShoppablePosts
items={shoppablePosts}
shopId={shopId}
fetchMoreByShopId={fetchMoreByShopId}
renderHeader={() => null}
/>
// ...
// ...
<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>
)}
/>
// ...
We look forward to seeing what you build!