Join Bryant as he tackles creation of a product information management system to manage and distribute product data to e-commerce channels. He has one hour to build the data model, add some data, and create an integration to automatically push products to Shopify.
Speaker 0: Hi. Welcome back to the next episode of 100 Apps 100 Hours where we build some of your favorite apps or die trying in 1 hour or less. So, I am your host, Brian Gillespie, a developer advocate at Directus. And, today we have PIM, which I've only started learning about in the last few months in detail. So PIM stands for product information management, sort of like a CMS for your products.
But the main problem that you solve with PIM is, having a single source of truth for all of your product data. Imagine that you've got different ecommerce channels like a Shopify store or you're selling on the Amazon Marketplace or walmart.com. Being able to manage all those different products and all the variations and all the colors and images and everything that goes along with selling those products in one place instead of managing it in 3 different places or 5 different places is tremendously valuable. So there's a couple of other tools out there in the space. Pimcore is the name of one of them, SalesLair and Plytix are a few of the ones that I took a look at.
And when it comes to PIN, before we dive in to actually building this, let's just take a look at at one of these solutions. So we've got a single source of truth where we find some screenshots. Can we find some screenshots? Kind of combines, all of my products, all of my assets, and you can generate things like catalogs or product sheets and sync this product data to those individual channels, which is the the biggest part or the, to me, where the real value is. I manage all of this in one place and sync it elsewhere.
So we are going to build APEM in 1 hour or less. Right? If you've caught some of the episodes other episodes you already know the rules of the game in that there are 60 minutes to plan and build no more no less, and the other rules are there are no rules use whatever you have at your disposal which I will take plenty of advantage of in this specific episode. Alright, so with that let's open up our timer over here on the left and we'll get started. So the first thing that I like to do anytime I'm building an app is just a little bit of planning.
So what's the functionality? What does our data model potentially look like on the back end? I like to work back end first just because it's so much nicer building a front end if I need 1 in, with actual live data. So what are the features or the functionality that we need out of a PIM? We need to be able to store all of our, store and manage our product data.
Store and manage, all product assets, images, video, spec sheets, etcetera. Let's make this a nice list. I'm a recovering designer. I can't ever get that out of me. And then we need to be able to store and manage, we need to control product variations.
Product variations like color and size, you know, other things like that. Then we want to be able to sync that data with other, with ecommerce. So let's call that Shopify in this case. And, you know, maybe even have a simple product catalog, where we could show off those products. Good enough.
That looks like a pretty good set of base functionality for a PIM. We've got the single source of truth for that. Now let's dive into what our specific data model might look like. So we've got our products, and I'll do the lowercase version here. No fill.
We could keep this purple color though. I like that. Alright, so we've got our products, we've got variants of those products, so maybe product variants. I can imagine this is like the specific color, size, g10, things like that. We got a name, assets, other data.
Very lovely. What else are we going to have? Probably some categories for our products. Categories or collections. Maybe those are even recursive.
What else do we have? We have assets, which our actual back end that we're using today, Directus, will take care of for us. What else is gonna be inside our data model? This looks like a pretty good start. Right?
So let's actually dive in. We're about 3 minutes into it. Hate to spend too much time planning. Alright. So we will log into our back end, Directus, today.
I've got a blank instance set up. This is using the cloud service. So this is actually running on Directus cloud and not locally because we do wanna sync this data, and, I don't wanna really struggle with cores issues or anything else, in local development trying to communicate with Shopify or other systems. So you can see I've got a blank instance, and it might be helpful just to leave this up side by side. Keep an eye on the clock.
So I've got my blank instance of Directus. What I love about it is how easy it is to go in and build out our data model. So let's just start by creating a new collection. We've got Products and we're gonna give this a generated UUID for the primary key field. We'll add in a status, a date created, user updated, just some of the system fields, that are, like, built in utilities, basically.
You know, we wanna keep track of what user updated, who, and when, just so we've got that information. Alright. So as far as products, we've, what, got a name for the product. We probably have a SKU number, SKU number, SKU part number. You know, you could have a couple of different items here.
We've certainly got a description of the product, which we'll use our WYSIWYG editor inside Directus for. That way we can embed rich content. Sounds great. What else are we gonna have on the individual product? You know, a like, the price information may live on the the product variance there, so I'll keep it there.
We're gonna have assets for this specific product as well. So I can go in and we'll create a new field and we'll use the relational files interface here which will actually create a junction table in our SQL database for us. So we'll do the product let's call this product Assets. Sounds great. And I could go into the advanced editor just to see what is happening behind the scenes.
So we've got one collection called Products. We've got a related collection called Directus Files that is a built in system collection within Directus and then it automatically creates this junction table for us. Now if I wanted to adjust the name of the fields or control what this actual collection is named, I could turn off autofill and make that available. You know, and maybe I do want to add the concerning field or the reverse field to our products and we'll do a sort field just so I could control the primary images. Everything else looks great.
We'll just save this, and now we've got some product data, right, or a product model where we can start uploading our data. Hey, this is a shirt and the SKU number is 1234. This is the best shirt ever. And we could even go in and upload an asset. We're probably gonna do a little bit of copyright infringement here.
Just copy the image URL. We can upload this and I can do that by URL. Cannot fetch file from URL. Okay. Service unavailable.
So I guess I'm going to have to download this image and then we'll just upload. So we get a pretty good idea of our basic functionality here. So now we've got our assets, and let's say I did want to browse this like a potential catalog. I can go into Directus, I could change this to the card view from our information sidebar and then I would just adjust my image source here. It looks like we don't support many to many fields there.
So maybe we go back in and add a, like, a featured image. Featured image. Great. Alright. So this is just a single image that we want.
So we'll go into that specific product, and I could pick this same image from the database. Alright. Great. So now we've got the featured image, we've got a name for the product, we've got our SKU number, and I can even go in and control how the image is cropped or not. So great.
Now we've kind of got this, catalog looking module happening. Let's go in and finish fleshing out our data model. So I'll just clean this up a little bit. We've got our product variance and we'll use the generated UUID. Same thing, I will go in and add all these separate fields.
Maybe we do have a sort field on the variant in case one variant takes priority over the other. Yeah. Kinda hit or miss. Alright. So we've got, our product variants.
What we are going to do is create a many to one relationship back to our parent product. So this will be the product, and we're gonna choose the products collection. And this is a mini to one relationship. So I'm gonna go into the advanced field settings here. We'll just create a new, a one to many on the other side of the equation back on our products table for product variance.
So now what I've done, in effect, is link these two collections or these two tables in our database together so that we can query and keep track of them. So now let's do what do we want to add for our other variant data, you know, so we've got color, that's just a string, we've got, size, etcetera. Great. We want to control a price here. You know, maybe we got that g ten, you know, unique identifier.
What is that? The global trade identification number? Something like that. Let's go in and add a decimal. Actually, that'd be that'd be a float.
And then we'll do maybe just 2 decimal places. Let's call this price. Great. Alright. So now we've got some items on our variants.
Let's go back and actually look at how this works. So I go back into our product and we can see we've got our variants here and if I wanted to create a new variant, I can. Let's call this red, we'll call it small. The GTIN is 666 and the price for this is $25. We could go in and create another variant.
This is red, this is medium, you know, 777, and the price is $16. Whatever. I can go in and actually set up our like what fields are displayed here. This doesn't look very great just to see the UUIDs. So let's sort that out, right.
And we'll make this just a little bit bigger as well. Alright, so we go back into our data model, we go to our product variants, we look for our interface and we have this, control over do we want a list, do we want a table. Let's use the table in this case and we will add our color, size, maybe we'll do GTIN and price combinations. Now you also may have, like a variant that has a different image as well. So we could potentially add that as well.
We'll just keep it simple for now and for the related fields, let's show the color. We'll add just like a little label for it so we know what it is, we'll add the size and we'll add size here. So let's see how that looks inside our PIM and great. Now we can see here's the different variants, there's the pricing, which, you know, maybe we wanna format that a little more, but great. And we can click on those to edit that information all that we need.
Alright, now let's build out our categories, right? This is the only thing remaining on our data model. We want to build out categories for our different products. So we have a category, we'll use the generated UUID again, and not sure we need like a status on these, but maybe we do wanna sort and cool. Alright, so we've got a category name.
Probably a short description for category. You know, we keep kinda splitting hairs which you on what detail you you need for something like this. If we look at, let's let's look at something like Pimcore. What what do they have available on their website? This looks really kinda messy to me.
So we've got, different objects. We've got media. You know, I don't really know for certain how others set up their data model for this, but to me this is how I would do it. Now I could go in and have something like another classification for this. We could use, like, tags as a different type of taxonomy, a different way to organize the data.
But I also have, you know, probably subcategories and parent categories. So Directus makes doing a recursive relationship like that very, very easy, where I can go in and do a many to 1 or a one to many relationship. So I'll just do one to many. We'll call this the, these are gonna be subcategories. Let's just do let's call let's do it the reverse.
So this will be the parent category. We'll use the categories collection. So we're creating a relationship, a recursive relationship, and we're gonna do the subcategories. So we've got parent category which will be a single parent, then we have subcategories. Great.
So what effect does that give us? Right? If I go into categories so let's create a new category we'll call it apparel. This is, let's call it actually, well, like outerwear or something like that. Great.
Hoodies, jackets, and such. And we don't have a parent category or a subcategory yet, so let's just create a subcategory like hoodies. Hoodies. Great. We'll save that and now we can see we've got subcategories and, you know, potentially nest these.
If I go back to our product, now we want to create a relationship with that category. So in this case, typically, a product may only have a single category. I I've seen some of these systems that will have, like, smart collections, which I think is a a really neat way to model it. And I think even Shopify, so I've got a a Shopify store set up here. Let's let's just take a look at how they handle it.
If this can be in a multiple categories or no? So it looks just like a single category. You can set up different collections for it. So we'll keep this to be a mini to 1. So we've got a category and our related collection will be categories.
And for our display template, maybe we just want to show the name of that category. Now, one of the other things I can do is control the interface to how the related values are displayed, just to make sure this looks how we want. So now if I go into our product, we can select the category hoodies or outerwear specifically. Great. Cool.
Now, let's say what functionality, let's go back here. I always get ahead of myself. So now we've got a way to store and manage all of our product data. We've got a way to store all of our product assets, right? So I could go in and upload.
Let's say I've got a PDF here. I could go in and upload this PDF. If I've got a spreadsheet, I could certainly do that as well. You know, I've got a CSV or whatever data that I've got, I can upload that and store it within this product. But, you know, what fun is it having these products in isolation?
We wanna be able to use these specific products. So out of the box, because we've set up this data model, we know the structure and everything, Directus gives us the ability to well, it just gives us REST and GraphQL APIs. So I could go in and do something like this where we've got items. Products. I'm getting an error message because I haven't set up permissions, but let's imagine we wanted to allow anybody to access this product information.
I can go to our setup, We'll go to access control and we'll go to our public role, which just controls what information is publicly available. And because none of this is secret at this point, let's go in and try it now. So if I hit refresh, we go to our products, we can see our product data. So there's the shirt, there's the SKU number, there's the description, we've got a featured image, UUID, And when it comes to our variants, we can't I can't see that information. That sucks.
How do we fix this? I can actually do something like this, which is one of my favorite features inside Directus that I can query the related collections or the related fields from a single API call. So it's very GraphQL like even though this is REST based, and I, you know, there's a GraphQL API. I'm not a super huge fan. You may be.
No sweat. So I could do something. We'll give, like, we'll use a wildcard here for all the root level fields. And then let's go in and do something like this where we have product variance and then we'll get all of the brute level fields for that. So as soon as I do that, now you can see I start to see that data that we want.
And maybe I don't need all of this. Maybe we just need the ID product_variance dot color. I could get a little more sophisticated and copy paste dot size dot price dot g10. Alright. And now that will only return the data that I'm interested in which is nice prevents over fetching keeps things really fast when we are sending a lot of data over the network.
Alright. So we've got the ability to store and manage all of our product assets. Let's control our product variations. How do we sync this data with an ecommerce system? Right?
We're managing all of this in a single location. Maybe I've got Shopify, which is what we're gonna use. Maybe I've got an Amazon storefront setup. Maybe we've got 3 or 4 other things going on. Right?
So how do we sync this information this data over? So I'm gonna go to our store and this is just the the Shopify demo store that I've set up. None of these products or anything that I created. Right? It looks like this is set up for snowboarding, which I tried once or twice, wasn't very good at it.
But I'm gonna go into the settings of this and we're gonna try to find how to, get access to the API here. Let's look and see domains. Maybe it's here inside the apps. Okay. So we'll look for develop apps.
We're gonna create an app that can connect with this storefront. Let's just take a look at it and see what it actually looks like on the front end. We got a password protection right now. We're gonna call this the Directus Shopify sync, maybe? We'll create this app inside the Shopify store.
Alright. So it looks like the next thing that we'll need to do, we're probably gonna be using the admin API because we're not building a shopping experience. We're trying to send product data to Shopify, so that we can have that experience inside Shopify. So let's configure our access scopes. It's probably gonna be around products.
And I'm not sure exactly which one of these I need. Product listings, product feeds, viewer manage products, let's go with that. We see the webhook subscriptions. We'll come back to webhooks. Let's just save that.
What else do we need? We need some actual credentials. So we need an access token, a way to get that data. Use your client secret to verify incoming webhooks. Let's go ahead and install this app.
This will give this app access to our storefront data. And we're only gonna reveal this token once and boom, we don't need it any longer. Not sure exactly how to set up the webhooks. Is that part of this? Start using the admin API.
Do you have to create webhooks through the through the API? I don't know. If your app creates a webhook subscription oh, okay. So it looks like you do have to create webhooks using the API. Yeah.
Alright. We'll come back to that. No worries. Alright. So now I've got this product information inside our account, I want to send it over to Shopify.
How can I do that? Well, I could probably write some kind of custom app or I could just go in and use the flows, the the automation builder inside Directus. We're looking pretty good on time. We're at 36 minutes. So I'm just gonna make this full screen so we can dive in a little deeper.
Let's call this send products to Shopify. Now how are we gonna trigger this? There's multiple ways to set up triggers. So I could manually trigger this. I could set it up on a cron job, so a regular interval.
For now, I'm just gonna manually trigger this and we'll go we'll trigger this on our products section and maybe we'll require confirmation. Are you sure? Yes, we're sure. So the location here allows me to control where I can actually trigger this. So I'm just gonna trigger this on the collection page only.
No. I could do both, you know, I could potentially send one product or maybe I want to send all of the products. We'll just keep that set up. Alright. So now let's go in.
We'll save this flow and if we go back to our products page on the right hand side, I could see the option to send this to Shopify. So check an item. Are you sure? Yes, we'll run a flow. And if I go back to our flow, I refresh and I don't see my logs.
Where are the logs? I ran this flow. Where is it? Let's make it not require a selection. Not sure if something happened here.
What's what's going on? So we'll go to our flow. We'll hit send products to Shopify. Go to flows. Okay.
Now they're showing up and we can see kind of the data that is being triggered here. So just collections, products. Great. Cool. So now, how do we get this actual data, right?
We will go in and read the data. So let's just call it read products. That's gonna be the name of this operation. We're gonna select all the products from the collection products and then I could, like, filter this down if I wanted to. You know, maybe I I just leave it all for now.
We're gonna select all the IDs and save it. And then once we read that data, we want to send to Shopify. Great. We'll, actually use the webhook HTTP request. How are we going to send the data?
It's probably gonna be a post method. We're gonna go let's go back to Shopify really quickly. So we've got our storefront API documentation. Zoom in a little bit. Do we want the storefront?
I don't think we do. So many tabs. So we go to admin. Oh, developer tools, API libraries. Oh, boy.
Getting into the thick of it now. Let's go back to where's our actual store? Right. Explore, start using the admin API. Okay.
Very confusing documentation here. Alright. So we'll go to our REST API reference. We'll look for products is probably what we want. We want to create a product.
So there's what the product resource looks like. Here's our create a product, and there's our URL. So what does the base URL look like? Authentication. Okay.
So it looks like the URL structure here is the Shopify unique shop ID or the shop slug, I'm assuming. My shopify.com/admin/api/ apiversion/resource. So our base URL setup so if we go back, will look something like this. Let's just pick up this actual URL. 100 apps, 100 hours, nice slugified version.
Myshopifiedot com/ what was it? Real genius here. Okay. Let's go half screen. Myshopify.com/admin/api/ what?
2023 dash 10 dash products dot JSON. Okay. So there's our URL. Great. Now I've got that access token.
Authentication. Looks like we have to pass that as a header as well. So we'll go into direct us. We'll add some headers. Got content dash type.
That's gonna be application slash JSON. And then we've got x Shopify access token. And then we've got this special token that you're not gonna look at, you're not gonna read, you're not gonna try to use. Alright. So now we can send a request.
So we go down. We're looking for products again. We're gonna create a product inside Shopify. Alright. So what are the details we need for our products?
We got a product dot title, body HTML, that's our description. We've got a product vendor, that's one thing we forgot inside our pin that we could add. We've got the product status. So, let's go in and just do something really simple. We'll do products.
Okay. So there's our product. Then we're gonna have a title for the product, what's that gonna be? Let's take a step back here. I'm just gonna save this.
I need to see what actual data is coming from this call here before we get carried away. Create a new product. Can you create is there an endpoint for creating multiple products? That's what I'm interested in. Create a new product.
Retrieve a list of products. Looks like we're just going to be able to create a single product at a time. So we may have to break this apart and do 2 separate flows. Imagine that I had another product. We'll call it test product.
No. Let's not do that. Let's call it a hoodie. So it is hoodie 123. Let's go to unsplash maybe.
Do a hoodie. And this looks like a hoodie with a statement so we'll just copy paste that. Okay. We'll import the file from the URL. Boom.
We got a featured image. Put a description. Great. Alright. So now we get 2 products.
We're just gonna select these products. We're gonna send the well, what happens if we don't select? We could still run this flow. We'll We'll take a look. We'll send these products down to our flow.
And let's just look at the log. Right? So now I'm getting an array of products. Okay. And maybe we wanna do we're gonna break this apart because we're gonna have to send a single product to Shopify.
But before we do that, I want to format products. Right? So we'll take our product. We'll run the format function. So Directus allows you to run arbitrary JavaScript inside the flows, which is really nice for stuff like this.
We've got the data, so our products are gonna be constant products equals data dot read products. I think that's gonna be it. And then we have some formatting logic here. Right. Just thinking out loud.
So now I'm just gonna save this really quick. And one of the other things that I like to do when I'm working with these flows is just copy the data I'm getting back right here, and I'm gonna put it inside my code editor. I've got a starter project here just in case we needed it. So now I've got the data structure. And if I look at Shopify gosh.
We've got, like, 35 different tabs going on. That's the fun of doing these live is actually trying to figure out how to all how to keep it all sane on one screen. Admin, API. Alright. So we go to the admin API, Rest admin API.
So we go to our products. What things do we need to pass to our products at a most at a minimum just to actually create these products. So here we go. Here's a new draft product type of setup. Creates a new draft product.
And can we do let's just make this even more complicated. Right? We'll do like a split screen? Somebody still needs to teach me to properly arc. Alright.
So I've got Directus, got our product. Okay. We got like 30 things going on here. A lot of fun. Alright.
So, let's run a format script. We've got our data over here that is coming from our Directus database. Let's go in and add our logic here. We got products. Let's do Shopify products dot map.
Oh, no. Shopify products equals products dot map product. Yeah. Products. And then we'll return something.
We got our function there. And then at the end of this, we're gonna return Shopify products. So we're just gonna return the array of products we want from Shopify. Alright. So we got the products and then we're gonna return a title for the product which is gonna be the product dot what name.
We need a comma there. Then we've got the body_html, that's gonna be product dot description. We've got product dot vendor. We don't have that product dot type. We could fetch that, and then for now, let's just try this and see how far that actually gets us.
Product dot name. We're gonna return our Shopify products. Let's go back in and I'll just make this full screen. Do products. I will look for our sidebar.
Where are you sidebar? There you are, mister sidebar. We'll send the products to Shopify. Let's just test our flow and see what came out the other side. Right.
So this looks good. This is our format that we're gonna send to Shopify. I'm gonna take just my my headers that I've got here. Let's just stuff those in this, take my URL that we so carefully constructed. And, I'm just gonna leave that.
We're gonna create a new flow. So we're gonna go in and create Shopify product and this will be triggered from that other flow, so triggered by another flow. We'll leave the response body blank and here we're just gonna do the HTTP request that we just did. So I'm gonna paste in that. I've got my headers.
Still stuck on the clipboard somewhere. I'll edit raw value and now we've got that. And here, I think it is just going to be something like this where we do actually, hit save. We'll just disconnect this for now. Hit save.
Go back to our other flow and trigger that flow, and we'll just see what trigger Shopify, create. And Directus will create a key for you, you can also rename this key, but this key, all the data that gets generated in this operation gets appended to the flow underneath this specific key. Let's just take a quick peek at time. How are we doing? We've got 20 minutes left.
Great. And then we're just gonna trigger this flow. So we'll select the Shopify flow. It's okay to create these in parallel and then for our payload, we're gonna do simply this. We've got the double curly brackets.
We've got the data. No. What's the name of that operation? Format product. Is that what the key is?
We're just gonna use this key. So we're gonna trigger the flow and the data from that, format product, we're gonna pass that to that other flow. Alright. So fingers crossed, stay with me here, we are building cool stuff. So now we're gonna send these products to Shopify, running that flow.
And we can see here we triggered this. We got back null null, this is what we sent to that. And if we go to our other flow, where we're actually creating, we can see that this ran twice, which is the what we actually want. We wanna see the the payload that we got was the product. So we're just gonna pick up the trigger.
Payload and that's what we're gonna send. Great. Amazing. So, in our request body here, we're gonna do something like this where we've got, quotations, double curly bracket, trigger dot payload and trigger is, prefixed with a dollar sign just because it's a unique, special key to get the trigger data. And fingers crossed.
Right? Can we send this data to Shopify? Can we build a working PIM in an hour? Let's test it out. We're gonna run I I don't think it matters if I select these or not.
Let's go in. We'll see. We have our send products to Shopify. That ran. Hopefully triggered this other flow that we have.
We got a Shopify product. Bad request. By accessing the Shopify, you agree to parameters are missing or invalid. Okay. So we're missing some parameters.
Let's take a look at the actual data that we sent. Payload, got the product resource, body HTML, supports HTML formatting, product status dot draft, Shopify access token. It looks like the body is not defined. So, I think I goofed up and that and maybe we're just sending the trigger. Let's take a look.
Did I get it wrong? Do we just need to send the trigger? So, let's make this more fun. Right. Let's go to our Shopify store.
Alright. We're gonna close this guy. Alright. I'm on the products. I'm gonna hit refresh.
Dun dun duh. I don't I don't see any products in here. Alright. So, let's go back. Obviously, I goofed somewhere again.
And we're definitely in danger of running out of time here. We got a bad request, missing parameters. Okay. So there's the body, product title, product dot HTML. What are we missing?
100 apps, 100 hours. We've got our access token. We've got our content type. Required parameter. Did I spell something wrong?
This is always the danger of working against the clock like this. What is this issue going to be? Request body is product. Alright. So product title body HTML.
I don't see where this is going wrong. Shopify access token. Bad request. Let's take a look at our app. Do we have the wrong scopes or something?
Let's just try one quick tweak. Go back to our send products for our format product. Let's just leave out the title. Right. So we'll just comment this out.
Return Shopify products. Send products to Shopify, flows, bad request, product underscore. Is it the way that it is actually sending this data? Sometimes if we do something like this, where we got trigger. Boom boom, Ron.
Created. Boom. Alright. So dramatic reveal time. Dun dun dun.
We have sent this data to Shopify. Did we? Where do we go? Okay. So we've got a hoodie, we've got a shirt.
There they are. Boom. Now they are in our system. That is how it's done, ladies and gentlemen. Where where we at on time?
We got 13 minutes left. We have managed to sync product data. Let's let's just take this one step further if we can, and let's create a product with let's at least get the images over there. Right? So on our product resource, we've got a list of product images, create a new product image, create a product image using a source URL that will be downloaded to Shopify.
Okay. So it looks like you can you may be able to pass these, and I'll just go in and very briefly let's just delete these products. Delete these products. Can't be undone. Those are deleted.
Those are no longer in the system. Let's adjust our payload here. So we're gonna go back to the formatting option. We'll comment that back in. We can have that now and then on the Shopify side, we've got okay.
So we got a product dot images. This will be images and then we've got an array And then what? Array of objects, and then we just got a source attribute. So the source if we look at our code again, Right. We've got our featured image.
Let's just pluck that for now And, we're gonna do something like this where we've got the source is gonna be, HTTPS direct us app slash assets slash what was the name of that? Featured underscore image. Featured. Oop. Gotta do our little squirrellys featured image.
Close that off. Should be good. The last piece of the puzzle for this is going to be enabling permissions for the actual files inside Directus as well, Because Shopify needs to access that. So 2 ways I could do it. I can add an access token, when I'm sending that call to Shopify Or in this case, I'm just gonna go in and we'll keep this really simple.
Under direct as files, we'll do all access. And we're just going to send and cross our fingers hoping that this flow actually works. We could do the dramatic reveal inside Shopify. Right? I broke something trying to send the images over.
Where did you go? Where did you go? Alright. What broke? Right?
Clearly, we broke something. Great Shopify product. What do we send? Product title hoodie. Do we actually break something inside the I don't see my logs.
4 to 5 minutes ago, that's not correct. Run Shopify flows. Go into our flow. Less than a minute ago, featured image is not defined. Okay.
So we did not have one with a featured image, and that broke. What did I do wrong? Again, always fun on the clock. I guess you have to actually use product dot featured image. Right?
Featured image. That would make a ton of sense. Too much sense actually. Alright. Last time.
Send products to Shopify. Did it work? Let's test our flow. Create Shopify product. Created.
Good looking. Alright. So if we open up Shopify, we go to our products, we can see our hoodie. Here is our actual data, so there's the image that we've got, there's the shirt that we loaded up, and this is all coming from our pin, our back end, our single source of truth. So that is how it's done, ladies and gentlemen.
We are syncing with Shopify. Last on our list, can we get this in 8 minutes? I have no idea. We've got a simple product catalog. Now, I don't think we could do this in 8 minutes, but let's give it a shot, right?
We want to display all of our products on the front end of our website, so people can browse those. So because there are no rules, I am a huge fan of Tailwind UI and Tailwind CSS in general. They've got some great looking ecommerce components that we may just repurpose for this, like, here's a nice product list. And I've got a Nuxt starter application sitting here just ready to be used. So let's see if we can actually get this product information displayed and rendering on a product catalog in just a couple minutes.
Alright, so we're gonna just forget Shopify for now. Let's simplify. Alright. This looks pretty good. This is a with border grid.
We've got a view component here. We've got our products. Let's just copy this template. Alright, so we're gonna go to our index page. We probably got some script action that we'll do there.
For now, I'm gonna if we just copy their products. Right. Constant products. Not gonna look great, and they've got an icon. So we'll do the star.
Let's just omit the products ratings for now. Right? Just comment those up. Run this. If I look at local host, say now we've got got something cooking here.
K. And now, let's actually fetch these products from Directus. We wanna do this live. Right? Going to do what, we got our products.
Is it equal to await use directus? I've got a just a composable here to fetch this data using the rectus SDK. We're going to read items and that's gonna be products. And is this actually gonna be all we really need? Usually, when I am developing, I often tend to do stuff like this where I will just render out the data inside the browser just to make sure we're seeing we're getting the stuff that we need.
Item/products failed. Oh, wait. Use direct us, read items, products. Why is this not working correctly? Well, that would be because I didn't actually set up the directus URL properly.
We are at 5 minutes, so I'm gonna load my PIM URL here. That is my Directus base URL. The server token, probably not even needed in this setup, but, we'll just reload. Let's fire back up the dev server. Let's see if we can get this data rendering from Directus.
Boom. So there's our actual data. Right? We no longer need this. Let's uncomment.
And just looking at this data, we've got the v4productandproducts. We wanna render the product dot id, we'll have that information. The image source, because we can use Directus as an image provider it will transform assets for you. I'm just going to use the NUTS image tag which is already set up in this. We will use product dot featured image.
We'll just leave alt text blank for now because there is there's none. We haven't got that set up. We got product dothref. We don't have one of those currently, but we could do slash products slash what? Product dot ID.
That would be the probably the URL. We got a product dot name, we got a product dot price. What else? I wanna fix the template structure here and then maybe we want to render out, div. We'll do like a tailwindpros class and give this v html.
We'll render the product description. Input must be a string received undefined. So if there let's make sure oh, forgot the item there. Boom. So there we have it.
We have got our items rendered out. You know, we could continue fleshing this out with the help of Tailwind into a catalog. But now we have done several things, Right? Let's recap with our final two and a half minutes. We have created a PIM system that can store and manage all of our product data, store all of our product assets, control all of our product variations, we can sync that data with Shopify, and we can have a simple catalog.
But, Bryant, you forgot one thing, our translations for this data. What if I want to have it in French or German or, Canadian? Bad bad joke for all all of our Canadian followers. Apologies there. So with a minute 30, how can we set up, translations for this?
Right? How can I control other languages? So I'm gonna go into our products. The first thing I'm gonna do is just create a languages collection. We've got a language code.
Alright. We've got a title or name of the language. Alright. And let's create 2 languages. We have EN, US, English.
Are we gonna do it 55 seconds? Let's just say fr for fridge. I think that's the code. No idea. We'll go back to our product.
Let's go in and there's a special translations interface within Directus. Clock is ticking, Brian. So we got the code, we got the direction field, that would probably be right to left. Use current language, we'll save this And then inside our product translations, we would go in and do, name, We would do a description. And where we at on time?
10 seconds. Brian, can you do it? 10, 9, 8, 7. How do we add translations for this? We can do English name.
So close. We hit the 60 seconds. I'm just going to finish this or the 60 minutes. We can do the French translation here and save it. So, with Directus we can manage all of these different things.
We hit time there, that felt really good though. We can manage translations or multilingual content. Alright. So that was a fun one. Multilingual content.
Really enjoyed this one. Building a PIM in 60 minutes or less. There's obviously more to this, but my next steps would be to flesh out that sync engine a little bit, so that if we made updates inside Directus, I could send those over to Shopify. I could even use the Shopify webhooks in this case, if I made a change to that information in Shopify to sync it back into Directus. I would also probably go in and flesh out the translations interface just a little bit more.
So that I have all the necessary fields. You know, and I may even have specific fields that we want to add to Shopify versus something like Amazon. So we could go in and do, you know, some more different some different channels that we wanna send this data to. But for 60 minutes, amazing to see what you can actually build with Directus. Stay tuned for the next episode.
I'm sure we'll have a good one and you'll get to see me hack and slash and burn my way through another product.