Strapi Plugin Development Explained
Tags: cms, javascript, tutorial, webdev
Published: 2022-07-11 06:36:13

---
canonical_url: https://strapi.io/blog/a-beginner-s-guide-to-strapi-plugin-development?utm_campaign=Strapi%20Blog&utm_source=devto&utm_medium=blog
---

_Learn what a Strapi plugin is and how the Strapi scheduler plugin in an online book store application using Vue.js and Strapi._

**Author: Mary Okosun**


[Strapi is an open-source and headless content management system ( CMS ) that gives developers the freedom to use their favorite tools and frameworks during development](https://strapi.io/). Strapi has an official web plugin marketplace, [The Strapi Market](https://market.strapi.io/), which contains more than sixty (60) plugins to choose from.


## What is a Strapi Plugin and Why Create a Plugin?

Plugins, also referred to as add-ons, are software available to give extra functionalities to our application. They have been known to help developers customize their applications in regards to styles and easy accessibility.

Strapi plugins were developed to power up your Strapi app with industry-leading software and also easily add custom features. They can be installed from the Marketplace or as npm packages. [You can either create your plugins or extend the existing ones.](https://docs.strapi.io/developer-docs/latest/development/plugins-extension.html#extending-a-plugin-s-content-types)

## Goal
This tutorial aims to give an approach to what a Strapi plugin is, and how to get started with Strapi plugin development as a beginner. You will learn how to create an online book store application using Vue.js and Strapi and how the Strapi [scheduler plugin](https://strapi.io/blog/new-community-plugin-content-scheduling) can be used to schedule books being added and also removed from our application.  

At the end of this tutorial, you should know how to get started with Strapi plugin development and how to install and use plugins from the Strapi Market to power up your application.

## Prerequisites 

To build this project, you need to:
1. Download and install [Node.js](https://nodejs.org/en/) (version 14 is recommended by Strapi).
2. Have [npm](https://docs.npmjs.com/cli/v6/commands/npm-install) (version 6 only) or [yarn](https://yarnpkg.com/getting-started/install) to run the CLI installation scripts.
3. Have a basic knowledge of JavaScript and Vue.js.


## Building the Strapi Backend APIs
In this phase, we will build the Strapi backend APIs to kickstart our project.
### Step 1: Scaffolding a Strapi Project

We will be running our Strapi project locally. Although we have multiple ways to start a new Strapi project like the [starter CLI](https://strapi.io/blog/announcing-the-strapi-starter-cli), the fastest way to do this is to install it via the Strapi Command Line Interface(CLI).
```bash
    npx create-strapi-app book-store-backend --quickstart
    #OR
    yarn create-strapi-app book-store-backend --quickstart
```
The command above will scaffold a new Strapi project in the directory you specified. It should automatically open http://localhost:1337/admin/ on your browser. Else, you can run the following command on your terminal to start the admin panel on your browser.

```bash
    npm run develop
    # OR
    yarn run develop
```
A new tab would be opened to register your new admin. 

![Strapi Admin Panel](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653391973710_Screenshot+2022-05-20+at+8.39.22+PM.png)


You can fill out the form and click on the button to submit. Afterward, you will be directed to the admin dashboard.

![Strapi Admin Dashboard](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653563856281_Screenshot+2022-05-20+at+8.40.13+PM.png)



### Step 2: Build the Bookstore Collection

We will create a new collection type that will store the details of each book to be added. We would need a collection type called `book`. This collection type would have details like `name`, `author`, `description`, and `image`.

We would follow these steps to create our collection type:

1. On the left-hand side of the panel, click on the `Collection-Type Builder` and then on `Create new collection type`. Fill in `Book` as the display name. Click on `continue` to create a new collection.

2. This prompts a new modal where you can select the fields for your collection type.  Select `Text` and fill in `Name` at the Text field. Click on `Add another field` and select `Text` for the `Description` and `Author` fields. Select `Media` for the `image` field.
3. After adding all the required fields, click on the `Finish` button and then `Save` the collection.
![Strapi Collection Types](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653843622053_Image.png)

### Step 3: Populate the  Bookstore Content

We will create content for the collection type we just created. We need to follow these steps to populate our collection:

1. On the left-hand side of the panel, click on the `Content Manager` and then on the `Book` collection. 

2. This prompts a modal where you can click on  `Create new entry` and fill in the content for the various fields. You can save these contents and publish them afterward.
![Strapi Create an entry layout](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653564610612_Screenshot+2022-05-26+at+12.26.54+PM.png)



### Step 4: Testing Your API

For this tutorial, we need to make two routes accessible to:
- Get all published articles, and 
- Get a published article by ID. 

After creating the book collection successfully, you need to allow public access because if we try to access the API URL with our public client, it would return a 403 forbidden error.

![Postman GET endpoint(403)](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653564813819_Screenshot+2022-05-26+at+12.32.59+PM.png)


We need to  enable permissions and roles in the admin panel by following these steps:

1. On the sidebar menu, click on `Settings` and then on `Roles`. In the new prompt that shows up, click on `Public`

2. A card would show beneath, you can click on the `Book` permission and tick the `find` and `findOne` boxes. Save the roles afterward.
3. You can test out your API as retrieving all books is now accessible at `https://localhost/api/books` and getting a published article by ID is accessible at `https://localhost/api/books/:id`
![Postman GET endpoint(200)](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653567493818_Screenshot+2022-05-26+at+1.17.55+PM.png)

## Getting Started with Scheduler Plugin

[The Scheduler is a Strapi plugin that allows Strapi CMS users the ability to publish and depublish any content type in the future.](https://market.strapi.io/plugins/@webbio-strapi-plugin-scheduler) It gives you the freedom to schedule a publish or unpublish date for your contents through some basic configurations to your backend files.

### Installation

This plugin can be installed via the terminal: 
```bash
    npm install @webbio/strapi-plugin-scheduler
    #OR
    yarn add @webbio/strapi-plugin-scheduler
```

### Configuration

After installing, you need to create a new `plugin.js` file in your `config` folder. You need to include the following code snippets in your `./config/plugin.js`

```js
    module.exports = ({ env }) => ({
       scheduler: {
        enabled: true,
        config: {
          model: "scheduler",
        },
      },
      });
      
```
Create a  `cronTasks` variable to require the `Scheduler`  plugin in your `./config/server.js` so the `server.js` file should contain the following snippets.

```js
    const cronTasks = require("@webbio/strapi-plugin-scheduler/cron-task");
    
    module.exports = ({ env }) => ({
      host: env('HOST', '0.0.0.0'),
      port: env.int('PORT', 1337),
      cron: {
        enabled: true,
        tasks: cronTasks,
      },
    });
```
You can stop your server and run the application again using `npm run develop`. You will see some information added to the right sidebar. This new section allows you to choose a date and time to publish or unpublish your article.

![Strapi Content Manager](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653568911170_Screenshot+2022-05-26+at+1.39.42+PM.png)

## Building the Bookstore Frontend App

Now that we have built our backend services and have the scheduler plugin configured, we will move on to creating our frontend to consume our APIs with Vue.js.

According to the [documentation](https://vuejs.org/guide/introduction.html), Vue.js is a JavaScript framework for building user interfaces. It builds on top of standard HTML, CSS, and JavaScript, and provides a declarative and component-based programming model that helps you efficiently develop user interfaces, be it simple or complex.

To create a new Vue.js project, follow these steps to get started. 

1. Navigate to a directory and Install the Vue.js package using the command:
```bash
    npm install -g @vue/cli
    # OR
    yarn global add @vue/cli 
```

2. Create a new project using the command:
```bash
    vue create book-store-frontend
```

3. You will be prompted to pick a preset. We would select "Manually select features" to pick the features we need. We would select  `Vuex`, `Router`, and `Lint/Formatter`. Vuex is a state management library for Vue applications, Router allows to change the URL without reloading the page, and Lint/Formatter properly formats the codes. After successfully creating your project, we would navigate to the folder directory and run our application.
```bash
    cd book-store-frontend
    npm run serve
    #OR
    yarn run serve
```
The URL http://localhost:8080/ should open your Vue.js application in your browser.

![Vue layout](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653570230595_Screenshot+2022-05-26+at+2.03.21+PM.png)


## Dependency Installation

We need to install some dependencies such as `axios`. **Axios** is the package dependency that will be used to make the call to the Strapi backend APIs. 
```bash
    npm install axios
```
Firstly, paste the following code snippets in the `./store/index.js` file:
```js
    import { createStore } from "vuex";
    import axios from "axios";
    export default createStore({
      state: {
        bookStore: [],
      },
      getters: {
        getBookStore: (state) => state.bookStore,
      },
      mutations: {
        setAllBooks: (state, payload) => (state.bookStore = payload),
      },
      actions: {
        getAllBooks: ({ commit }) => {
          try {
            axios.get(`http://localhost:1337/api/books?populate=*`)
              .then((res) => {
              commit("setAllBooks", res.data.data);
            });
          } catch (e) {
            console.log("error", e);
          }
        },
      },
      modules: {},
    });
```    

Afterward, in the `views` folder, delete the `AboutView.vue` and `HomeView.vue` files and create a `BookView.vue`  and `BookDetails.vue` files.

In the `BookView.vue` file, paste the following code;

```js
    <template>
      <div class="row">
        <div class="cols" v-for="book in getBookStore" :key="book.key">
          <router-link :to="{ name: 'BookDetails', params: { id: book.id } }">
            <img
              :src="`http://localhost:1337${book.attributes.Image.data.attributes.url}`"
            />
            <h3>{{ book.attributes.Name }}</h3>
            <h5>
              By :
              {{ book.attributes.Author }}
            </h5>
            <h5>
              Published at: <br />
              {{ book.attributes.publishedAt }}
            </h5>
          </router-link>
        </div>
      </div>
    </template>
    <script>
    import { mapGetters, mapActions } from "vuex";
    export default {
      name: "BookStore",
      data() {
        return {
          bookStore: [],
        };
      },
      mounted() {
        this.getAllBooks();
      },
      computed: {
        ...mapGetters(["getBookStore"]),
      },
      methods: {
        ...mapActions(["getAllBooks"]),
      },
    };
    </script>
    <style scoped>
    .row {
      margin: 0px 10px;
      display: flex;
      text-align: justify;
    }
    .cols {
      margin: 10px;
      width: 15vw;
      box-shadow: 4px 4px 4px #ae9f9f;
    }
    img {
      width: 100%;
      height: 150px;
    }
    a {
      text-decoration: none;
      color: #201c1c;
    }
    p {
      font-size: 15px;
      text-align: left;
    }
    h3,
    h5 {
      margin: 10px 10px;
    }
    </style>
```    
    
In the `BookDetails.vue` file, paste the following code snippets;
```js
    <template>
      <div class="books">
        <div class="card">
          <div class="card-desc">
            <img :src="`http://localhost:1337${image}`" />
            <div>
              <h3>{{ bookById.Name }}</h3>
              <h5>By: {{ bookById.Author }}</h5>
              <h5>Published at: {{ bookById.publishedAt }}</h5>
            </div>
            <p>{{ bookById.Description }}</p>
          </div>
        </div>
      </div>
    </template>
    <script>
    import axios from "axios";
    export default {
      name: "BookDetails",
      data() {
        return {
          image: [],
          bookById: [],
        };
      },
      async mounted() {
        const id = this.$route.params.id;
        await axios
          .get(`http://localhost:1337/api/books/${id}?populate=*`)
          .then((response) => {
            this.bookById = response.data.data.attributes;
            this.image = this.bookById.Image.data.attributes.url;
          });
      },
    };
    </script>
    <style scoped>
    .card {
      max-width: 80vw;
      margin: auto;
    }
    .card-title {
      display: flex;
      justify-content: space-around;
    }
    img {
      width: 20vw;
      height: 20vw;
    }
    h3 {
      font-size: 20px;
      color: #000;
    }
    h5 {
      font-size: 15px;
      font-style: italic;
      color: #716c69;
      margin: 5px !important;
    }
    p {
      font-size: 19px;
      color: #000;
      width: 50vw;
      padding-top: 20px;
      margin: auto;
      text-align: justify;
    }
    button {
      padding: 15px;
      background: blue;
      border: none;
      color: #fff;
      width: 100%;
    }
    .card-desc {
      margin: 0px 50px;
    }
    .title,
    .author {
      padding: 5px;
    }
    </style>
```    

In the `/router/index.js` file, the code snippets to properly route our application should be similar to the snippets below:

```js
    import { createRouter, createWebHistory } from "vue-router";
    const routes = [
      {
        path: "/",
        name: "BookStore",
        component: () => import("../views/BookView.vue"),
      },
      {
        path: "/book/:id",
        name: "BookDetails",
        component: () => import("../views/BookDetails.vue"),
      },
    ];
    const router = createRouter({
      mode: "history",
      history: createWebHistory(process.env.BASE_URL),
      routes,
    });
    export default router;
```    
## Testing the Application

Now refresh your browser, and you should see something similar to this page:

![Frontend Implementation](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653910140459_Screenshot+2022-05-30+at+12.28.28+PM.png)

When you click on the individual book card, the `get published article by ID` API would be called and a response would be returned for the book id.

![Get book by ID frontend Implementation](https://paper-attachments.dropbox.com/s_FA433A94C11F9AC81352A78C08AC649F89276D4CCDF95A27BFE1CFCA385F461D_1653910286925_Screenshot+2022-05-30+at+12.27.05+PM.png)


Now, we have a working frontend and backend implementation. In the following steps, we would be scheduling our books to be published and de-published at a specific time in the future.

Note that you cannot schedule an already published content to be published, instead schedule it to be de-published. So we would create a new content draft to be published and schedule a date to de-publish one of the published contents we have in our application.

### Set a Publish Time

To schedule a publish time, follow the same process to create new content for your collection. After saving the content, choose a publish date and time. Afterward, click on the `Set publish time` button. You would get a confirmation notification that `Post has been scheduled`.

### Set an Unpublish Time

To schedule an unpublish time, click on `Content Type` and then `Book`. Select the entry you would want to de-publish and choose the date and time. Afterward, click on the `Set depublish time` button. You would get a confirmation notification that `Post has been scheduled`

## Conclusion
In this tutorial, we learned what a Strapi plugin is, why you should use a plugin, and how to create an online book store application with Vue.js as the frontend framework and Strapi as the Backend. We demonstrated how the scheduler plugin can be used to schedule books being published and de-published from our application.

You can download the source code for the [frontend](https://github.com/Marienoir/Strapi-Book-Store-Frontend) and [backend](https://github.com/Marienoir/Strapi-Book-Store-Backend) implementation from Github.