> Portal Navigation:
>
> - Append `.md` to any URL under `https://dev.wix.com/docs/` to get its markdown version.
> - Pages are either content pages (article or reference text) or menu pages (a list of links to child pages).
> - To get a menu page, truncate any URL to a parent path and append `.md` (e.g. `https://dev.wix.com/docs/sdk.md`, `https://dev.wix.com/docs/sdk/core-modules.md`).
> - Top-level index of all portals: https://dev.wix.com/docs/llms.txt
> - Full concatenated docs: https://dev.wix.com/docs/llms-full.txt
## Resource: Tutorial | Create a Product Widget with Blocks & CLI
## Article: Creating a Product Widget
## Article Link: https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-product-widget-with-blocks-cli.md
## Article Content:
# Tutorial: Build a Featured Product Widget with Blocks and the CLI
**Editor compatibility**
Wix Blocks apps aren't supported in the Wix Harmony editor. Existing Blocks apps remain available for purchase on the Wix App Market for Wix Editor and Wix Studio sites. To learn more, see [About Wix Harmony and Blocks](https://dev.wix.com/docs/build-apps/develop-your-app/frameworks/wix-blocks/about-wix-harmony-and-blocks.md).
**Important:** This tutorial describes the Blocks-CLI integration, which only works with the Wix CLI for Apps. We're introducing a [unified Wix CLI](https://dev.wix.com/docs/wix-cli/guides/about-the-wix-cli.md), which we recommend for developing apps and headless projects. The unified Wix CLI doesn't support this integration.
This tutorial walks you through creating a Wix app that displays a featured product widget using the `@wix/stores` SDK module. Here is an image of how the widget looks on a site:

## Before you begin
Before getting started, make sure that:
+ You have [Node.js](https://nodejs.org/en/) (version 20.11.0 or higher).
+ You’re logged into your Wix Studio account. If you don’t already have one, [sign up for a Wix Studio account](https://manage.wix.com/account/custom-apps).
## Step 1 | Set up your environment
First, let's set up a development site, create the app and add the app to the site.
### Create a Site
To create a development site:
1. Go to the [eCommerce templates](https://www.wix.com/studio/templates/ecommerce) page.
1. Select a site template and click **Edit**. This creates your own copy of the site.
2. Publish the site.
### Create an App
To create your app:
1. Open your terminal.
1. Run:
```bash
nvm use 20.11.0
npm create @wix/app@latest
```
1. When asked what you would like to do, select **Create a new Wix App**.
1. When asked how you would like to create your new app, select **Create a basic app**.
1. Enter a name for your app.
1. Enter a project folder name.
1. Wait as the CLI creates the files for your project.
1. Navigate to the project folder:
```bash
cd
```
1. Run the generate command:
```bash
npm run generate
```
This will display a list of extensions that you can add to your app.
1. Select **Site Widget**.
1. When asked which framework to use, select **Blocks**.
1. When asked if you'd like to install dependencies, type **Y**.
1. After the CLI finishes installing dependencies, install the the Wix Stores package:
```bash
npm install '@wix/stores'
```
> **Note:** You can ignore the warnings in your terminal.
### Install your app on a Development Site
1. Run the following command to start up a local development server:
```bash
npm run dev
```
1. When asked to select a Development Site, select **Pick an existing site**.
1. Select the site you just created.
1. Press **Enter** to install your app on the site.
1. Click **Agree & Add** in the browser that opened.
1. Go back to your terminal and type **B** to open the Blocks editor.
## Step 2 | Design your widget in the Blocks Editor
Now you are in the Blocks Editor, where you'll design your widget.
1. Click **Create Extension** > **Widget**.
1. Search for the **Featured Item** widget.
1. Select the widget and click **Add Widget**.

4. Delete the first widget, **Widget1**, by clicking the three dots next to its name in the **Widgets** menu.
5. Click **Sync** and then **Sync Changes** to confirm. This syncs your app's UI to your local code files.

## Step 3 | Add your widget to the site
1. In the CLI, type **E** to open the site in the Editor of your Development Site. Once the site opens, your app is added to the site.
1. Click **+ Add Elements** > **App Widgets**.
1. Click on the **Featured Item** widget to add it to the canvas.

The widget is now located on the page and uses the site theme to match look and feel of the site.
## Step 4 | Implement the widget logic
In this step, you’ll define the widget logic, which presents data according to the product ID.
### Define the widget API in `api.ts`
Define a property in the widget API, to hold the product ID.
1. Open the `src` folder of your project.
1. Go to the file: `site/widgets/blocks/featured-item/api.ts`
1. Delete the default event, `load`.
1. Delete the default function, `myPublicFunction()`.
1. Change the property name of the property in the `props` array from `name` to `productId`.
1. Save the file.
Your code should look like this:
```ts
import { defineAPI, WidgetPropertyType } from '@wix/blocks';
export default defineAPI({
props: {
productId: {
type: WidgetPropertyType.STRING,
},
},
events: {},
functions: {},
});
```
### Use the property to present data in the `widget.ts`
The `widget.ts` in the same folder is where you add your widget's business logic. You'll use the property you defined in the `api.ts` to present the data of the selected product.
1. Import the SDK `stores` module:
```ts
import { products } from '@wix/stores';
```
2. Define a helper function `updateProduct` inside the `defineWidget()` callback that fetches product data using the widget's `productId` property and updates the title, subtitle, and image elements accordingly.
```ts
const updateProduct = async () => {
const { product } = await products.getProduct($widget.props.productId);
$w('#title').text = product?.name!;
$w('#subtitle').text = product?.description!;
$w('#imageX1').src = product?.media?.mainMedia?.image?.url!;
};
```
> **Note:** The `?` and `!` are used because the stores API can also return `undefined`.
3. Replace the boilerplate code of the `onReady()` and `onPropsChange()` functions. Paste the following code instead, to call the `updateProduct()` function. Make sure that all these functions are within the `defineWidget()` function.
```ts
$w.onReady(async () => {
await updateProduct();
});
```
```ts
$widget.onPropsChanged(async (oldProps, newProps) => {
await updateProduct();
});
```
4. Delete the boilerplate function, `myPublicFunction`, from the return statement.
5. Save the file.
## Step 5 | Design the Settings Panel
The **Featured Item** widget that you added to the app comes with a default settings panel. Let's modify this panel.
1. Go back to your open **Blocks** editor.
1. Click the **Editor Experience**  icon.
1. Click **Custom Panels**. You can see that the **Featured Item** widget has one custom panel, named **Settings**.
1. Delete the toggle and text elements.
1. Click **+ Add Elements** and add a dropdown element.

1. Click the **Settings** icon and change the **Field title** to **Choose product** (or any other title you want).
1. Click **Sync** to update your UI to your code files.
## Step 6 | Add the panel logic in the **`panel.ts`**
Let's implement the Settings panel logic. The panel gets the list of products and maps them to the dropdown. When the dropdown selection changes, the panel sets the property in the widget API.
When the panel opens, it presents the product that was set in the widget API property. If no property was set, the panel presents the first product in the list.
1. Go to: `site/widgets/blocks/featured-item/panels/settings/panel.ts`
1. Add the following import:
```ts
import { products } from '@wix/stores';
```
3. Replace the `onReady()` function with this code, which gets the Stores product and sets it to the widget’s `productId` property.
```ts
$w.onReady(async () => {
const { items } = await products.queryProducts({});
$w("#panelDropdown1").options = items.map((item: any) => ({
label: item.name,
value: item._id,
}));
$w("#panelDropdown1").value =
(await widget.getProp("productId")) ?? items[0]._id;
$w("#panelDropdown1").onChange(async (event: any) => {
await widget.setProp("productId", $w("#panelDropdown1").value);
});
});
```
4. Save the file.
## Step 7 | Add a price element to the widget
Back in the Blocks editor, let's add a text element to present the product price. To do this, you'll need to add a paragraph to the widget's stack.
1. Go back to the **Featured Item** widget in the **App Interface**.
1. Right click on the widget stack, which brings together the **Item Title**, the description and the button.
1. Click **Quick Add**.
1. Click **Paragraph**.

### Make some design changes
1. Change the content of the paragraph you just added to be a price. For example, **75$**.
1. Make sure that the paragraph is placed in the third row of the stack (use the **Move up** and **Move down** errors if needed.)
1. Align the paragraph to the left.
1. Change the font size to 16.
1. Reduce the size of the stack gaps.
1. Change the button text to **More Info**.
Your finished widget should look like this:

> **Note:** The design changes are not necessary for the app to function.
### Rename the ID of the element you added
Let's rename the new element, so that you can refer to it in your code.
1. Make sure the text element is selected.
1. Click the **Layers** icon.
1. Click the three dots next to the `#text1` element.
1. Click **Rename** and rename the element to `price`.
1. Click **Sync**.

### Add the price to the `updateProduct()` function
Let's update the `updateProduct()` function in the `widget.ts`.
1. Add this line under the other lines in the function.
```ts
$w('#price').text = product?.priceData?.formatted?.price!;
```
1. Save the file.
## Step 8 | Test Your Widget
It's time to test the widget in the editor and see the product information update when the panel changes.
1. Go back to the editor to see the new price element (you can type **E** if you closed it).
1. Click the widget's **Settings** action button.
1. Select various products from the dropdown and see that the widget information updates as expected.
## Step 9 | Add a button click behavior
Let's add the logic for the button to lead the user to the product page.
1. Press `Ctrl + C` in the terminal, to stop the development server.
1. Run:
```bash
npm install '@wix/site-location'
```
> **Note:** You can ignore the warnings.
3. In the `widget.ts` file, add:
```ts
import { location } from '@wix/site-location';
```
4. In the `updateProduct()` function, add:
```ts
$w('#exploreButton').onClick(() => {
location.to(product?.productPageUrl?.path!);
});
```
5. Save the file.
You'll be able to test the button on a live site after releasing a version of the app.
## Step 10 | Release the app to create a version
Now that you're done developing your app, you can create a version.
1. Run:
```bash
npm run build
npm run release
```
1. Run dev again:
```bash
npm run dev
```
1. Click **S** to open the site.
1. Go to the widget.
1. Click the button — it should navigate to the product page.
Congratulations, you’ve created and connected a fully functional, data-powered featured product widget using Blocks and the CLI!