A Beginner's Guide to Strapi Plugin Development
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. Strapi has an official web plugin marketplace, The Strapi Market, 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.
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 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:
- Download and install Node.js (version 14 is recommended by Strapi).
- Have npm (version 6 only) or yarn to run the CLI installation scripts.
- 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, the fastest way to do this is to install it via the Strapi Command Line Interface(CLI).
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 localhost:1337/admin on your browser. Else, you can run the following command on your terminal to start the admin panel on your browser.
npm run develop
# OR
yarn run develop
A new tab would be opened to register your new admin.
You can fill out the form and click on the button to submit. Afterward, you will be directed to the admin dashboard.
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:
On the left-hand side of the panel, click on the
Collection-Type Builder
and then onCreate new collection type
. Fill inBook
as the display name. Click oncontinue
to create a new collection.This prompts a new modal where you can select the fields for your collection type. Select
Text
and fill inName
at the Text field. Click onAdd another field
and selectText
for theDescription
andAuthor
fields. SelectMedia
for theimage
field.- After adding all the required fields, click on the
Finish
button and thenSave
the collection.
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:
On the left-hand side of the panel, click on the
Content Manager
and then on theBook
collection.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.
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.
We need to enable permissions and roles in the admin panel by following these steps:
On the sidebar menu, click on
Settings
and then onRoles
. In the new prompt that shows up, click onPublic
A card would show beneath, you can click on the
Book
permission and tick thefind
andfindOne
boxes. Save the roles afterward.- 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 athttps://localhost/api/books/:id
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. 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:
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
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.
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.
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, 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.
Navigate to a directory and Install the Vue.js package using the command:
npm install -g @vue/cli # OR yarn global add @vue/cli
Create a new project using the command:
vue create book-store-frontend
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
, andLint/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.cd book-store-frontend npm run serve #OR yarn run serve
The URL localhost:8080 should open your Vue.js application in your browser.
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.
npm install axios
Firstly, paste the following code snippets in the ./store/index.js
file:
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;
<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;
<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:
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:
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.
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 and backend implementation from Github.