{"id":27870,"date":"2022-11-22T11:20:11","date_gmt":"2022-11-22T11:20:11","guid":{"rendered":"http:\/\/e-commerce-sites-wt-cloudinary-widgets-and-netlify"},"modified":"2022-11-22T11:20:11","modified_gmt":"2022-11-22T11:20:11","slug":"e-commerce-sites-wt-cloudinary-widgets-and-netlify","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/","title":{"rendered":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>The power of compelling images increases the likelihood that a potential customer will make a purchase. When interactive, images provide a more profound experience for the customer, making them almost as tangible as the product themselves. Using <a href=\"https:\/\/www.sanity.io\/docs\/getting-started-with-sanity-cli\">Sanity<\/a>, <a href=\"https:\/\/cloudinary.com\/\">Cloudinary<\/a> and <a href=\"https:\/\/docs.netlify.com\/cli\/get-started\/\">Netlify<\/a>  I will show you how to set up your own interactive product media gallery with minimal effort.<\/p>\n<p>In this tutorial, we will build the product Gallery management feature for an e-commerce web application using the Cloudinary Product Widget.<\/p>\n<h2>Sandbox<\/h2>\n<p>The completed project is on <a href=\"https:\/\/codesandbox.io\/s\/sanity-netlify-cloudinary-ecomm-r2pfgf\">CodeSandbox<\/a>. Fork it and run with it.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/sanity-netlify-cloudinary-ecomm-r2pfgf?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"sanity-netlify-cloudinary-ecomm\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Prerequisites<\/h2>\n<p>Knowledge of React, Next.js, Sanity CLI, Netlify edge functions and a <a href=\"https:\/\/cloudinary.com\/console\">Cloudinary account<\/a> is required to get the most out of this article.<\/p>\n<h2>Getting Started<\/h2>\n<p>Create a Next.js project by running the command below in your terminal.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx create-next-app product-gallery\n<\/code><\/span><\/pre>\n<p>Next, add the project dependencies using the following command:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">install<\/span> <span class=\"hljs-selector-tag\">axios<\/span> <span class=\"hljs-keyword\">@sanity<\/span>\/client @sanity\/image-url netlify-cli dotenv -g\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Next, navigate into the project directory.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">cd product-gallery\n<\/code><\/span><\/pre>\n<p>Then, run the command below to start the application.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">ntl dev\n<\/code><\/span><\/pre>\n<p>This should start our Next.js application on port <code>8888<\/code>.<\/p>\n<blockquote>\n<p>Note: You need to have the Netlify CLI installed to run <code>ntl<\/code> commands.<\/p>\n<\/blockquote>\n<h2>Reading data from Sanity<\/h2>\n<p>Our product data will be coming from a Sanity CMS project we\u2019ve previously created. You can pull in data for products from wherever you want, a REST endpoint, your database, or from a JSON file. Whatever works best for you.<\/p>\n<p>Let\u2019s initialize a new Sanity instance for our project. Create a <code>\/lib\/sanity.js<\/code> file and update it with the snippet below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ sanity.js<\/span>\n<span class=\"hljs-keyword\">import<\/span> sanityClient <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@sanity\/client\"<\/span>;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">const<\/span> client = sanityClient({\n  <span class=\"hljs-attr\">projectId<\/span>: <span class=\"hljs-string\">\"&#91;Project ID]\"<\/span>,\n  <span class=\"hljs-attr\">dataset<\/span>: <span class=\"hljs-string\">\"production\"<\/span>,\n  <span class=\"hljs-attr\">useCdn<\/span>: <span class=\"hljs-literal\">true<\/span>,\n});\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we setup a new sanity client by passing it our <code>projectId<\/code> and <code>dataset<\/code>. We have now established a connection with Sanity to read data.<\/p>\n<h2>Fetching Products from Sanity<\/h2>\n<p>We are going to use Netlify functions to interface with our Sanity instance and fetch our products.\nTo do that, let\u2019s setup a simple Netlify function to fetch our data. Create a <code>functions\/product.js<\/code> file from the root directory and update it with this snippet:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ src\/functions\/product.js<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> sanityClient = <span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"@sanity\/client\"<\/span>);\n<span class=\"hljs-keyword\">require<\/span>(<span class=\"hljs-string\">\"dotenv\"<\/span>).config();\n\nexports.handler = async (event) =&gt; {\n    <span class=\"hljs-keyword\">const<\/span> client = sanityClient({\n    projectId: process.env.PROJECTID,\n    dataset: <span class=\"hljs-string\">\"process.env.DATASET,\n    useCdn: true,\n    token: process.env.TOKEN,\n    apiVersion: \"<\/span><span class=\"hljs-number\">2022<\/span><span class=\"hljs-number\">-08<\/span><span class=\"hljs-number\">-10<\/span><span class=\"hljs-string\">\"\n    });\n    try {\n        const products = await client.fetch(\n        `*&#91;_type == \"<\/span>product<span class=\"hljs-string\">\" &amp;&amp; \"<\/span>chocolate<span class=\"hljs-string\">\" in tags]`\n        );\n        const res = await products;\n        return {\n        statusCode: 200,\n        body: JSON.stringify(res)\n        };\n    } catch (error) {\n        console.log(error);\n    }\n};\n\n<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we used a GROQ query to fetch all products from Sanity with a <code>chocolate<\/code> tag and send it back as a response. As a result, if you visited our project at <code>localhost:8888\/.netlify\/functions\/product<\/code> you should get a response containing all our products from Sanity.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_AFB9C9677D2EE21DAA815DF57768E602531EBA2342841B827702BCA097A57668_1663760158818_CleanShot+2022-09-21+at+13.35.452x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1448\"\/><\/p>\n<p>Now that we are successfully fetching our product data from Sanity, it only makes sense that we display them on the homepage for users to see. To do that, let\u2019s update our <code>pages\/index.js<\/code> file to call our Netlify function and display the response (our products):<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ index.js<\/span>\n<span class=\"hljs-keyword\">import<\/span> imageUrlBuilder <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"@sanity\/image-url\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> builder = imageUrlBuilder(client);\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">IndexPage<\/span>(<span class=\"hljs-params\">{ products }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.container}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.main}<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.grid}<\/span>&gt;<\/span>\n          {products.map((product) =&gt; {\n            const { defaultProductVariant = {} } = product;\n            const { images } = defaultProductVariant;\n            return (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{product._id}<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{<\/span>`\/<span class=\"hljs-attr\">product<\/span>\/${<span class=\"hljs-attr\">product._id<\/span>}`}&gt;<\/span>\n                  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span>\n                    <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.card}<\/span>\n                    <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{builder.image(images&#91;0]).width(300)}<\/span>\n                    <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">\"images\"<\/span>\n                  \/&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n                <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h3<\/span>&gt;<\/span>{product.title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h3<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            );\n          })}\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n}\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getStaticProps<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> products = <span class=\"hljs-keyword\">await<\/span> axios.get(\n    <span class=\"hljs-string\">\"http:\/\/localhost:8888\/.netlify\/functions\/products\"<\/span>\n  );\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      <span class=\"hljs-attr\">products<\/span>: products.data,\n    },\n  };\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>With that, if we reload the homepage on the browser, we should now see our products from Sanity rendered for the users to see.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_AFB9C9677D2EE21DAA815DF57768E602531EBA2342841B827702BCA097A57668_1663760409384_CleanShot+2022-09-21+at+13.40.022x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1511\"\/><\/p>\n<h2>Adding Dynamic Product Details Pages<\/h2>\n<p>Now that we have our products displayed, we want to implement dynamic pages so that when you click on a product, we open a product details page where you can see more information about the product.<\/p>\n<p>We\u2019ll follow the standard Next.js approach of using getStaticPaths to generate the dynamic paths and build the pages on demand with our data. We\u2019ll use the <a href=\"https:\/\/cloudinary.com\/documentation\/product_gallery\">Cloudinary Product Gallery widget<\/a> to display more images of the products. Create a <code>p``ages\/p``roduct\/[id].js<\/code> file and add the following snippet:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ product\/&#91;id].js<\/span>\n<span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">product<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"hljs-comment\">\/\/ Cloudinary product widget goes here <\/span>\n    )\n}\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> product;\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getStaticPaths<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> products = <span class=\"hljs-keyword\">await<\/span> axios.get(\n        <span class=\"hljs-string\">\"http:\/\/localhost:8888\/.netlify\/functions\/products\"<\/span>\n    );\n    <span class=\"hljs-keyword\">const<\/span> paths = products.data &amp;&amp; products.data.map(<span class=\"hljs-function\">(<span class=\"hljs-params\">prod<\/span>) =&gt;<\/span> ({\n        <span class=\"hljs-attr\">params<\/span>: { <span class=\"hljs-attr\">id<\/span>: prod._id }\n    }));\n    <span class=\"hljs-keyword\">return<\/span> {\n        <span class=\"hljs-attr\">paths<\/span>: paths,\n        <span class=\"hljs-attr\">fallback<\/span>: <span class=\"hljs-literal\">false<\/span>\n    };\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we export the <code>getStaticPath``()<\/code> function to make requests to our Netlify function and generate all our products via the paths we\u2019ve specified.  Then, we loop through the products and assigned <code>id<\/code> to <code>params.id<\/code> to match the product ID.<\/p>\n<p>Next, update the file and pass the paths we want to generate to the getStaticProps() function and pass the generated product to our homepage:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ product\/&#91;id].js<\/span>\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getStaticProps<\/span>(<span class=\"hljs-params\">{ params }<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> products = <span class=\"hljs-keyword\">await<\/span> axios.get(\n    <span class=\"hljs-string\">\"http:\/\/localhost:8888\/.netlify\/functions\/products\"<\/span>\n  );\n  <span class=\"hljs-keyword\">const<\/span> product =\n    products.data &amp;&amp; products.data.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">prod<\/span>) =&gt;<\/span> params.id === prod._id);\n  <span class=\"hljs-keyword\">return<\/span> {\n    <span class=\"hljs-attr\">props<\/span>: {\n      product,\n    },\n  };\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>With this, we can pass the generated product to our <code>IndexPage()<\/code> component for rendering. However, we don\u2019t just want to render it. We want to use the Cloudinary Product Gallery Widget to display all the different images of the product.<\/p>\n<h2>Setting up Cloudinary Product Gallery Widget<\/h2>\n<p>The Cloudinary gallery widget relies on the <a href=\"https:\/\/cloudinary.com\/documentation\/advanced_url_delivery_options#client_side_asset_lists\">Client-side asset lists<\/a> feature to retrieve the list of images (or videos) with specified tags. To ensure that this feature is available on your Cloudinary account, you must ensure that the <strong>Resource list<\/strong> option is enabled. By default, the list delivery type is restricted. To enable it, open the <strong>Security settings<\/strong> in your console and clear <strong>the Resource lis****t<\/strong> item under <strong>Restricted media types<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_328E562781B5C7F9F1ABA671B4D24FEC069B74C76DB567A8A7B5C2F3612EF92D_1661183764090_resource-list.png\" alt=\"User-uploaded image: resource-list.png\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1920\" height=\"934\"\/><\/p>\n<h2>Add Gallery Context<\/h2>\n<p>The functionality for the gallery widget is delivered via CDN and instantiated in the <code>index.js<\/code> file. However, we need access to the instantiated object elsewhere in our application to update the Widget on successful upload.<\/p>\n<p>To avoid prop drilling, we\u2019ll use React <a href=\"https:\/\/reactjs.org\/docs\/context.html\">Context<\/a> to pass this object to any component where it may be required. Create a <code>\/context\/GalleryContext.js<\/code> file in the root directory and set it up like so:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> { createContext } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n<span class=\"hljs-keyword\">const<\/span> GalleryContext = createContext(<span class=\"hljs-literal\">null<\/span>);\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> GalleryContext;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>With our context in place, we can instantiate the widget and update the context value.<\/p>\n<h2>Instantiate Gallery Widget<\/h2>\n<p>To instantiate the gallery widget we will use <a href=\"https:\/\/nextjs.org\/docs\/advanced-features\/custom-document\">Next\u2019s Custom <code>Document<\/code><\/a> to update the <code>&lt;html&gt;<\/code> tags used to render a Page.<\/p>\n<p>To override the default <code>Document<\/code>, create the file <code>pages\/_document.js<\/code> as shown below:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">import<\/span> Document, { Html, Head, Main, NextScript } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"next\/document\"<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyDocument<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">Document<\/span> <\/span>{\n  render() {\n    <span class=\"hljs-keyword\">return<\/span> (\n      <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Html<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Head<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>\n            <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">\"https:\/\/product-gallery.cloudinary.com\/all.js\"<\/span>\n            <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\/javascript\"<\/span>\n            <span class=\"hljs-attr\">strategy<\/span>=<span class=\"hljs-string\">\"beforeInteractive\"<\/span>\n          &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Main<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NextScript<\/span> \/&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">body<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Html<\/span>&gt;<\/span><\/span>\n    );\n  }\n}\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> MyDocument;\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The snippet above is the default <code>Document<\/code> added by Next.js that allows custom attributes as props. We\u2019re using it to embed our JavaScript file which incorporates all the product gallery functionality.<\/p>\n<p>Next, update your <code>products\/[id].js<\/code> file to match the following snippet:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ product\/&#91;id].js<\/span>\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-keyword\">const<\/span> product = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ product }<\/span>) =&gt;<\/span> {\n  useEffect(<span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n    <span class=\"hljs-keyword\">const<\/span> productGallery = cloudinary.galleryWidget(\n      {\n        <span class=\"hljs-attr\">container<\/span>: <span class=\"hljs-string\">\"#gallery\"<\/span>,\n        <span class=\"hljs-attr\">cloudName<\/span>: <span class=\"hljs-string\">\"cloudName\"<\/span>,\n        <span class=\"hljs-attr\">mediaAssets<\/span>: &#91;{ <span class=\"hljs-attr\">tag<\/span>: <span class=\"hljs-string\">`<span class=\"hljs-subst\">${product&#91;<span class=\"hljs-number\">0<\/span>].tags&#91;<span class=\"hljs-number\">0<\/span>]}<\/span>`<\/span>, <span class=\"hljs-attr\">mediaType<\/span>: <span class=\"hljs-string\">\"image\"<\/span> }],\n      },\n      &#91;]\n    );\n    productGallery.render();\n  });\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.wrapper}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"gallery\"<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.product}<\/span>&gt;<\/span>{product&#91;0].title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>{product&#91;0].description}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.price}<\/span>&gt;<\/span>$ 20 <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{styles.btn}<\/span>&gt;<\/span>Add to Cart<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n  );\n};\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> product;\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here, we initialize the Product Gallery Widget with the <code>cloudinary.galleryWidge``t()<\/code> method call and pass the initialization options, including the cloud name and the tags of the media assets we wish to retrieve. We also specify a key named <code>container<\/code> to be the <code>div<\/code> element where the gallery will be rendered.<\/p>\n<p>With these, we can now view the individual product and its variants. The final result will look like the GIF shown below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_AFB9C9677D2EE21DAA815DF57768E602531EBA2342841B827702BCA097A57668_1663763948283_CleanShot+2022-09-21+at+14.38.19.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"506\"\/><\/p>\n<h2>Conclusion<\/h2>\n<p>In this tutorial, we went over the process of reading e-commerce product data from Sanity using Netlify functions and rendering multiple product variant images in a product display page using the Cloudinary Product Gallery Widget. We rendered only images in this project, however, the widget can also render videos, 360 spin sets and 3D models.<\/p>\n<p><strong>Resources you may find helpful:<\/strong><\/p>\n<ul>\n<li>\n<a href=\"https:\/\/cloudinary.com\/documentation\/product_gallery\">Cloudinary Product Gallery<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/www.sanity.io\/docs\/getting-started-with-sanity-cli\">Getting started with Sanity CLI<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/docs.netlify.com\/cli\/get-started\/\">Getting started with Netlify CLI<\/a>\n<\/li>\n<\/ul>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27871,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,385,212,371],"class_list":["post-27870","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-netlify","tag-next-js","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Ecommerce Sites with Cloudinary Widgets &amp; Netlify<\/title>\n<meta name=\"description\" content=\"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Ecommerce Sites with Cloudinary Widgets &amp; Netlify\" \/>\n<meta property=\"og:description\" content=\"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-11-22T11:20:11+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Ecommerce Sites with Cloudinary Widgets &amp; Netlify\",\"datePublished\":\"2022-11-22T11:20:11+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\"},\"wordCount\":7,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Netlify\",\"Next.js\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\",\"name\":\"Ecommerce Sites with Cloudinary Widgets &amp; Netlify\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA\",\"datePublished\":\"2022-11-22T11:20:11+00:00\",\"description\":\"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA\",\"width\":5140,\"height\":3855},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Ecommerce Sites with Cloudinary Widgets &amp; Netlify\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify","description":"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/","og_locale":"en_US","og_type":"article","og_title":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify","og_description":"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-11-22T11:20:11+00:00","twitter_card":"summary_large_image","twitter_image":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/"},"author":{"name":"","@id":""},"headline":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify","datePublished":"2022-11-22T11:20:11+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/"},"wordCount":7,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","keywords":["Guest Post","Netlify","Next.js","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/","name":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","datePublished":"2022-11-22T11:20:11+00:00","description":"Learn how to quickly create e-commerce sites with Sanity, Netlify functions, Next.js and the Cloudinary Product Gallery Widget.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","width":5140,"height":3855},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/e-commerce-sites-wt-cloudinary-widgets-and-netlify\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Ecommerce Sites with Cloudinary Widgets &amp; Netlify"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681922354\/Web_Assets\/blog\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4\/02b5a47ccebcd035343673ba5045109a315c6396-5140x3855-1_27871534d4.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27870","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27870"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27870\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27871"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27870"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27870"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27870"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}