> 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 “Top Blog Posts” Dashboard Page With the CLI ## Article: Tutorial | Create a “Top Blog Posts” Dashboard Page With the CLI ## Article Link: https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md ## Article Content: # Tutorial | Creating a “Top Blog Posts” Dashboard Page Using the Wix CLI One of the ways that 3rd-party developers can extend the Wix ecosystem is by creating apps that appear in the site owner’s dashboard. These apps can work with data from the site they’re installed on, such as the Content Management System (CMS), data, and business solution data (like CRM). This tutorial explains how to create a dashboard page that displays a site’s most liked and most viewed blog posts. We use the following technologies to create the app: - [Wix CLI](https://dev.wix.com/docs/wix-cli/guides/about-the-wix-cli.md): Used to create, test, and deploy the app. - [JavaScript SDK](https://dev.wix.com/docs/build-apps/develop-your-app/api-integrations/java-script-sdk.md): Used to retrieve blog post data from the site. - [Wix Design System](https://www.wix-pages.com/wix-design-system/?path=/story/getting-started--about): Used to display data on the dashboard page. The end result will look like this: ![App preview](https://wixmp-833713b177cebf373f611808.wixmp.com/images/332fa2568993b4234d4876b25e716e8a.png) We use the following steps to build the “Top Blog Posts” dashboard page: 1. [Initialize the app](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-1--initialize-the-app) 1. [Run a local development server](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-2--run-a-local-development-server) 1. [Add permissions](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-3--add-permissions) 1. [Set up Wix Blog](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-4--set-up-wix-blog) 1. [Develop the app](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-5--develop-the-app) 1. [Display the top posts in the dashboard](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-6--display-the-top-posts-in-the-dashboard) 1. [Test the app](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-7--test-the-app) 1. [Build and deploy the app](https://dev.wix.com/docs/build-apps/get-started/tutorials/tutorial-create-a-top-blog-posts-dashboard-page-with-the-cli.md#step-8--build-and-deploy-the-app) ## Before you begin Before getting started, make sure that: - You install [Node.js](https://nodejs.org/en/download/) (v20.11.0 or higher). - You install [npm](https://www.npmjs.com/package/npm) or [yarn](https://www.npmjs.com/package/yarn) - 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 | Initialize the app We use the Wix CLI to initialize our "Top Blog Posts" app. In the process of initializing our app, the Wix CLI automatically: - Creates a new app in the [Custom Apps page](https://dev.wix.com/docs/build-apps/develop-your-app/app-dashboard-setup/about-the-app-dashboard.md) of your Wix Studio workspace. - Sets up a new folder for your app in your local file system. The folder includes: - A `src` folder containing initial boilerplate code for an app with a dashboard page. - A `package.js` file containing your app dependencies. - Creates a local Git repository for your app. - Prompts you to set up a development site for testing your app. **To initialize the app:** 1. Open a terminal and navigate to the folder where you want to create your app. 1. Run the following command using npm or yarn: ```bash npm create @wix/app@latest ``` 1. Select **Create a new Wix App**. 1. Select **Create a basic app**. 1. Enter a name for your app. Let’s name our app **Top Blog Posts**. 1. Back in the terminal, press **Enter** to select the default folder name (`top-blog-posts`) for your app in your local file system. You now have a new app in the [Custom Apps page](https://dev.wix.com/docs/build-apps/develop-your-app/app-dashboard-setup/about-the-app-dashboard.md), a new folder in your local file system, and a local Git repository for developing and testing your app. ## Step 2 | Run a local development server Now that you’ve initialized your app, you can run a local development server to see the app in action, and view local changes as you develop your app. The local development environment runs the app and its initial boilerplate code on the development site that you chose in the previous step. To run a local development server for your app: 1. Navigate to your newly-created folder for your app. ```bash cd top-blog-posts ``` 1. Run the following command: ```bash npm run dev ``` 1. The CLI prompts you to choose a development site (test site), which you’ll use throughout this tutorial to run and test your app. You can choose an existing Wix site as your development site, or create a new one. Let’s **Create a new Development Site**. The newly created development site is automatically named something like **Dev Site 5x2043**, and can be found in your Wix account’s list of sites. 1. Follow the prompt to open the development site on your default browser. If the browser doesn’t open, [install your app on your test site](https://dev.wix.com/docs/build-apps/launch-your-app/app-distribution/test-your-app-on-a-premium-site.md) manually and skip the next step. 1. Click **Agree & Add** to install your app on your development site. 1. Click the **Dashboard** link in the terminal. Your development site’s dashboard opens, and you can see your newly-created app’s dashboard page in the left sidebar. We add the content of our app’s dashboard page in the next step. ![Dashboard page](https://wixmp-833713b177cebf373f611808.wixmp.com/images/ad76381ae3b8c70632914ff5bb353334.png) Your app is now running on your development site. As you develop your app, any changes made to your app’s code are reflected in real time on your development site. ## Step 3 | Add permissions In this step, we'll show how to add permissions for the app. We will use the `queryPosts()` and `getPostMetrics()` functions in the [Wix SDK’s Blog API](https://dev.wix.com/docs/api-reference/business-solutions/blog/introduction.md) to get a list of all posts and post metrics. Then we'll use React code to display the most liked and viewed posts on our dashboard page. To use the [`queryPosts()`](https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/query-posts.md) and [`getPostMetrics()`](https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/get-post-metrics.md) functions, we need to give our app permission in the app's dashboard. Let’s first look for the permission that we need in the Permission Scopes section of the `queryPosts()` function’s page. ![Permissions](https://wixmp-833713b177cebf373f611808.wixmp.com/images/ee0225677c3346f48e88068cd84429fd.png) The Permission Scopes section reads that we must have one of the permission scopes on the list. In our example, we choose the **Manage Blog** permission scope. The same is for `getPostMetrics()`. Let's choose the **Manage Blog** permission scope. > **Note:** You can find the permission scopes you need for each API in the individual function’s page in the [JavaScript SDK documentation](https://dev.wix.com/docs/sdk.md). To add permissions for the app to request upon installation: 1. Go to your app's dashboard. 1. Click **Permissions** in the left sidebar. 1. For each permission scope: 1. Click **Add Permissions**. 1. Enter the permission scope's name in the **Search by name or ID** field. 1. Check the permission scope's checkbox under **Choose Permission Scopes**. 1. Click **Save**. When a site owner installs the app, Wix prompts them to grant the necessary permissions. ## Step 4 | Set up Wix Blog Before you can start coding, you need to set up Wix Blog on your site and app: 1. Install the [Wix Blog](https://www.wix.com/app-market/wix-blog?searchLocation=home) app on your test site. You can create some new blog posts, or use the sample ones provided by Wix. > **Note**: Make sure to add Wix Blog in both the Dashboard and the Editor. 1. Once you install the app, publish the site and “like” one of the posts. You can find the blog at `https://{your-site-url}/blog`. 1. In your test site dashboard, select **Apps > Manage Apps** from the sidebar. 1. Delete your app from the site. 1. Open your app’s dashboard. 1. Select **Test Your App > Dashboard**. Select your test site in the **Site Selector**. Follow the prompts to reinstall the app and approve the new permissions. > **Note**: You'll be prompted to create an extension before testing the app. Ignore this prompt and click **Test Your App**. ## Step 5 | Develop the app Next, we will use the JavaScript SDK to retrieve blog data from the test site. ### Create a code file for your SDK code Before starting to write code for the SDK, set up a file for your code. The code for this project uses the SDK's [`blog`](https://dev.wix.com/docs/api-reference/business-solutions/blog/introduction.md) and [`dashboard`](https://dev.wix.com/docs/sdk/host-modules/dashboard/introduction.md) modules. The `dashboard` module is preinstalled by the CLI, but you'll need to install the `blog` module manually. 1. Create a file named `blog-utils.js` in the `src > extensions > dashboard > pages` directory of your app’s repo. 1. In your IDE terminal, run the following command: ```js npm install @wix/blog ``` ### Retrieve blog data Next, use the blog module in the SDK to retrieve the data you need. 1. Import the `posts` submodule from the `@wix/blog` package into your file. 1. Create an `async` function called `getTopBlogPosts`. 1. Use the [`queryPosts()`](https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/query-posts.md) function to find the posts with the most likes and views. The query allows you to sort the posts in descending order based on likes and views. Call this function twice, once for likes and once for views. 1. Extract the first item IDs from the result and save them as `mostLiked` and `mostViewed` variables. 1. Use the [`getPostMetrics()`](https://dev.wix.com/docs/api-reference/business-solutions/blog/posts-stats/get-post-metrics.md) function to retrieve the post metrics by passing the ID of the post. These metrics include likes and views. Save these metrics as `mostLikedMetrics` and `mostViewedMetrics` variables. 1. Your function should return an object with two keys, `mostViewed` and `mostLiked`. The value for each key should be an object containing the post data and the likes and views respectively of the highest-ranking posts. Your final `blog-utils.js` file should look like this: ```js import { posts } from '@wix/blog'; export async function getTopBlogPosts() { const mostLikedPosts = await posts.queryPosts().descending('metrics.likes').find(); const mostViewedPosts = await posts.queryPosts().descending('metrics.views').find(); const mostLiked = mostLikedPosts.items[0]; const mostViewed = mostViewedPosts.items[0]; const mostLikedMetrics = await posts.getPostMetrics(mostLiked._id); const mostViewedMetrics = await posts.getPostMetrics(mostViewed._id) return { mostViewed: { post: mostViewed, views: mostViewedMetrics.metrics.views, }, mostLiked: { post: mostLiked, likes: mostLikedMetrics.metrics.likes, }, }; } ``` ## Step 6 | Display the top posts in the dashboard Now that we have the blog data, we can use the [Wix Design System](https://www.wix-pages.com/wix-design-system/?path=/story/getting-started--about) to display it on a dashboard page. The app framework created by the CLI includes the code for a sample dashboard page. We can use that code as the basis for a dashboard page. ### Set up the dashboard code files 1. Open the `my-page.tsx` file. 1. Delete all the import statements and paste in the following ones: ```js import { Button, Card, Heading, Text, Page, WixDesignSystemProvider, Box, Loader } from "@wix/design-system"; import "@wix/design-system/styles.global.css"; import * as Icons from "@wix/wix-ui-icons-common"; import React, { useEffect, useState } from "react"; import { navigate } from "@wix/dashboard"; import { getTopBlogPosts } from './blog-utils'; import { posts } from '@wix/blog'; ``` 1. In the return statement for the `Index()` component, delete everything in between the `` tags. When you’re done, your file should look like this: ```js import { Button, Card, Heading, Text, Page, WixDesignSystemProvider, Box, Loader, } from "@wix/design-system"; import "@wix/design-system/styles.global.css"; import * as Icons from "@wix/wix-ui-icons-common"; import React, { useEffect, useState } from "react"; import { navigate } from "@wix/dashboard"; import { getTopBlogPosts } from './blog-utils'; import { posts } from '@wix/blog'; export default function Index() { return ; } ``` ### Prepare blog data for display Next, get your blog data ready to display on your dashboard page. This code goes below the import statements on your `my-page.tsx` file: 1. Define the interfaces for viewed and liked blog posts. ```js interface ViewedBlogPost { post: posts.Post; views: number; } interface LikedBlogPost { post: posts.Post; likes: number; } ``` 1. In the `Index()` component use React hooks to access the data. ```ts const [mostViewed, setMostViewed] = useState(null); const [mostLiked, setMostLiked] = useState(null); const [mostViewedPublishedDate, setMostViewedPublishedDate] = useState(null); const [mostLikedPublishedDate, setMostLikedPublishedDate] = useState(null); useEffect(() => { async function fetchBlogPosts() { try { const { mostViewed, mostLiked } = await getTopBlogPosts(); console.log("mostViewed", mostViewed); setMostViewed(mostViewed); setMostLiked(mostLiked); setMostViewedPublishedDate( new Date(mostViewed.post.lastPublishedDate).toDateString() ); setMostLikedPublishedDate( new Date(mostLiked.post.lastPublishedDate).toDateString() ); } catch (error) { console.log("Failed to fetch blog post data.", error); } } fetchBlogPosts(); }, []); ``` 1. Add a loader that displays while data are loading. ```js if (!mostViewed || !mostLiked) { return ( ); } ``` ### Create the page structure Next, add React components from the [Wix Design System](https://www.wix-pages.com/wix-design-system/?path=/story/getting-started--about) to create the page structure. 1. Add nested components between the `` tags in the return statement for the `Index()` component. Structure your components to match the following diagram. Wrap `` components in `
` tags so that they each display on a different line. ![Outline boxes](https://wixmp-833713b177cebf373f611808.wixmp.com/images/8331ef273852e1522f5c50805be3a22d.png) 1. Add the following variables to the opening tag of the `Box` component to ensure the cards inside it display correctly: ```js gap="5px" direction="vertical" ``` When you’re done, your `Index()` component should look like this: ```js export default function Index() { return (
); } ``` ### Add content to the page Add static text, dynamic text, and other content to your Design System components. In some cases, text is added between the component’s opening and closing tags. In other cases, the text is passed into the component as a variable. 1. Pass these variables to the `Heading` components inside the `Card.Header` components: ```js size="medium" as="h2" ``` 1. Pass these variables to the `Heading` components inside the `Car.Content` components: ```js size="small" as="h3" ``` 1. Add an `onClick` event handler to the `Button` component in the page header actions bar. Set the variable to this function: ```js () => navigate('social-blog'). ``` When you’re done, your `Index()` function should look like this: ```js export default function Index() { return ( } onClick={() => navigate("social-blog")} > Edit Your Blog } /> Most Viewed } /> Title: {mostViewed.post.title} Excerpt: {mostViewed.post.excerpt}
Last published: {mostViewedPublishedDate}
Views: {mostViewed.views}
Most Liked } /> Title: {mostLiked.post.title} Excerpt: {mostLiked.post.excerpt}
Last published: {mostLikedPublishedDate}
Likes: {mostLiked.likes}
); } ``` ## Step 7 | Test the app Now that the app’s code is ready, you can test it locally using the Wix CLI. The finished code sample should look like this: ```ts import { Button, Card, Heading, Text, Page, WixDesignSystemProvider, Box, Loader, } from "@wix/design-system"; import "@wix/design-system/styles.global.css"; import * as Icons from "@wix/wix-ui-icons-common"; import React, { useEffect, useState } from "react"; import { navigate } from "@wix/dashboard"; import { getTopBlogPosts } from './blog-utils'; import { posts } from '@wix/blog'; interface ViewedBlogPost { post: posts.Post; views: number; } interface LikedBlogPost { post: posts.Post; likes: number; } export default function Index() { const [mostViewed, setMostViewed] = useState(null); const [mostLiked, setMostLiked] = useState(null); const [mostViewedPublishedDate, setMostViewedPublishedDate] = useState(null); const [mostLikedPublishedDate, setMostLikedPublishedDate] = useState(null); useEffect(() => { async function fetchBlogPosts() { try { const { mostViewed, mostLiked } = await getTopBlogPosts(); console.log("mostViewed", mostViewed); setMostViewed(mostViewed); setMostLiked(mostLiked); setMostViewedPublishedDate( new Date(mostViewed.post.lastPublishedDate).toDateString() ); setMostLikedPublishedDate( new Date(mostLiked.post.lastPublishedDate).toDateString() ); } catch (error) { console.log("Failed to fetch blog post data.", error); } } fetchBlogPosts(); }, []); if (!mostViewed || !mostLiked) { return ( ); } return ( } onClick={() => navigate("social-blog")} > Edit Your Blog } /> Most Viewed } /> Title: {mostViewed.post.title} Excerpt: {mostViewed.post.excerpt}
Last published: {mostViewedPublishedDate}
Views: {mostViewed.views}
Most Liked } /> Title: {mostLiked.post.title} Excerpt: {mostLiked.post.excerpt}
Last published: {mostLikedPublishedDate}
Likes: {mostLiked.likes}
); } ``` To test your app, do the following: 1. Run a local development server for your app. Your app’s dashboard page will now look like this: ![App preview](https://wixmp-833713b177cebf373f611808.wixmp.com/images/332fa2568993b4234d4876b25e716e8a.png) 1. Click the button to show top blog posts. 1. If things don’t look right, open your browser’s developer tools and check for errors in the console. ## Step 8 | Build and deploy the app After testing your app and seeing that it works as expected, you can: - [Create a public preview of your app](https://dev.wix.com/docs/build-apps/manage-your-app/versioning/about-app-versioning.md), - [Build your app](https://dev.wix.com/docs/build-apps/launch-your-app/app-distribution/about-app-distribution.md) - [Deploy your app](https://dev.wix.com/docs/build-apps/manage-your-app/versioning/release-a-new-app-version.md).