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.
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.
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.
To build this project, you need to: 1. Download and install Node.js (version 14 is recommended by Strapi). 2. Have npm (version 6 only) or yarn to run the CLI installation scripts. 3. Have a basic knowledge of JavaScript and Vue.js.
In this phase, we will build the Strapi backend APIs to kickstart our 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 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.
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.
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 on Create new collection type
. Fill in Book
as the display name. Click on continue
to create a new collection.
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.
Finish
button and then Save
the collection.
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 the Book
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.
For this tutorial, we need to make two routes accessible to:
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 on Roles
. In the new prompt that shows up, click on Public
A card would show beneath, you can click on the Book
permission and tick the find
and findOne
boxes. Save the roles afterward.
https://localhost/api/books
and getting a published article by ID is accessible at https://localhost/api/books/:id
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.
This plugin can be installed via the terminal:
npm install @webbio/strapi-plugin-scheduler
#OR
yarn add @webbio/strapi-plugin-scheduler
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
1 module.exports = ({ env }) => ({
2 scheduler: {
3 enabled: true,
4 config: {
5 model: "scheduler",
6 },
7 },
8 });
9
Create a cronTasks
variable to require the Scheduler
plugin in your ./config/server.js
so the server.js
file should contain the following snippets.
1 const cronTasks = require("@webbio/strapi-plugin-scheduler/cron-task");
2
3 module.exports = ({ env }) => ({
4 host: env('HOST', '0.0.0.0'),
5 port: env.int('PORT', 1337),
6 cron: {
7 enabled: true,
8 tasks: cronTasks,
9 },
10 });
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.
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.
npm install -g @vue/cli
# OR
yarn global add @vue/cli
vue create book-store-frontend
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. 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.
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:
1 import { createStore } from "vuex";
2 import axios from "axios";
3 export default createStore({
4 state: {
5 bookStore: [],
6 },
7 getters: {
8 getBookStore: (state) => state.bookStore,
9 },
10 mutations: {
11 setAllBooks: (state, payload) => (state.bookStore = payload),
12 },
13 actions: {
14 getAllBooks: ({ commit }) => {
15 try {
16 axios.get(`http://localhost:1337/api/books?populate=*`)
17 .then((res) => {
18 commit("setAllBooks", res.data.data);
19 });
20 } catch (e) {
21 console.log("error", e);
22 }
23 },
24 },
25 modules: {},
26 });
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;
1 <template>
2 <div class="row">
3 <div class="cols" v-for="book in getBookStore" :key="book.key">
4 <router-link :to="{ name: 'BookDetails', params: { id: book.id } }">
5 <img
6 :src="`http://localhost:1337${book.attributes.Image.data.attributes.url}`"
7 />
8 <h3>{{ book.attributes.Name }}</h3>
9 <h5>
10 By :
11 {{ book.attributes.Author }}
12 </h5>
13 <h5>
14 Published at: <br />
15 {{ book.attributes.publishedAt }}
16 </h5>
17 </router-link>
18 </div>
19 </div>
20 </template>
21 <script>
22 import { mapGetters, mapActions } from "vuex";
23 export default {
24 name: "BookStore",
25 data() {
26 return {
27 bookStore: [],
28 };
29 },
30 mounted() {
31 this.getAllBooks();
32 },
33 computed: {
34 ...mapGetters(["getBookStore"]),
35 },
36 methods: {
37 ...mapActions(["getAllBooks"]),
38 },
39 };
40 </script>
41 <style scoped>
42 .row {
43 margin: 0px 10px;
44 display: flex;
45 text-align: justify;
46 }
47 .cols {
48 margin: 10px;
49 width: 15vw;
50 box-shadow: 4px 4px 4px #ae9f9f;
51 }
52 img {
53 width: 100%;
54 height: 150px;
55 }
56 a {
57 text-decoration: none;
58 color: #201c1c;
59 }
60 p {
61 font-size: 15px;
62 text-align: left;
63 }
64 h3,
65 h5 {
66 margin: 10px 10px;
67 }
68 </style>
In the BookDetails.vue
file, paste the following code snippets;
1 <template>
2 <div class="books">
3 <div class="card">
4 <div class="card-desc">
5 <img :src="`http://localhost:1337${image}`" />
6 <div>
7 <h3>{{ bookById.Name }}</h3>
8 <h5>By: {{ bookById.Author }}</h5>
9 <h5>Published at: {{ bookById.publishedAt }}</h5>
10 </div>
11 <p>{{ bookById.Description }}</p>
12 </div>
13 </div>
14 </div>
15 </template>
16 <script>
17 import axios from "axios";
18 export default {
19 name: "BookDetails",
20 data() {
21 return {
22 image: [],
23 bookById: [],
24 };
25 },
26 async mounted() {
27 const id = this.$route.params.id;
28 await axios
29 .get(`http://localhost:1337/api/books/${id}?populate=*`)
30 .then((response) => {
31 this.bookById = response.data.data.attributes;
32 this.image = this.bookById.Image.data.attributes.url;
33 });
34 },
35 };
36 </script>
37 <style scoped>
38 .card {
39 max-width: 80vw;
40 margin: auto;
41 }
42 .card-title {
43 display: flex;
44 justify-content: space-around;
45 }
46 img {
47 width: 20vw;
48 height: 20vw;
49 }
50 h3 {
51 font-size: 20px;
52 color: #000;
53 }
54 h5 {
55 font-size: 15px;
56 font-style: italic;
57 color: #716c69;
58 margin: 5px !important;
59 }
60 p {
61 font-size: 19px;
62 color: #000;
63 width: 50vw;
64 padding-top: 20px;
65 margin: auto;
66 text-align: justify;
67 }
68 button {
69 padding: 15px;
70 background: blue;
71 border: none;
72 color: #fff;
73 width: 100%;
74 }
75 .card-desc {
76 margin: 0px 50px;
77 }
78 .title,
79 .author {
80 padding: 5px;
81 }
82 </style>
In the /router/index.js
file, the code snippets to properly route our application should be similar to the snippets below:
1 import { createRouter, createWebHistory } from "vue-router";
2 const routes = [
3 {
4 path: "/",
5 name: "BookStore",
6 component: () => import("../views/BookView.vue"),
7 },
8 {
9 path: "/book/:id",
10 name: "BookDetails",
11 component: () => import("../views/BookDetails.vue"),
12 },
13 ];
14 const router = createRouter({
15 mode: "history",
16 history: createWebHistory(process.env.BASE_URL),
17 routes,
18 });
19 export default router;
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.
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
.
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
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.
Backend Developer 👩💻 | Technical Writer ✍️