Extending BCMS with custom Plugins

The most powerful way to extend BCMS functionality is by using BCMS Plugins. Plugins are applications that run inside of the CMS with UI and back end components.

With plugins, you can display any kind of data from BCMS, in any way you want. For example, you can display form submissions, different kinds of charts, craft your own content authoring flow - and display it all inside BCMS.


Creating a Plugin

To create a plugin project, follow these steps:

  1. Open a terminal and navigate to the directory where you want to create the project
  2. Use the BCMS CLI to run bcms --plugin create and provide a name for the project
bcms --plugin create my-plugin
  1. Once the CLI completes, you can open the project in your favorite code editor
  2. Run docker-compose up to start the BCMS with the plugin mounted
  3. Navigate to localhost:8080 in your browser
  4. In the navigation, expand the Plugins section to view the newly created plugin.
BCMS Plugin

That's it! You can now start building your plugin and take advantage of the powerful extensibility of BCMS.


Project Structure

The project contains multiple directories and files, but the most important ones for plugin development are ui and back end.

  • The back end directory contains the back end code for the plugin. Here, you will write your custom REST endpoints and server-side logic. To install back end dependencies, navigate to the root of the project and run npm install --save PACKAGE_NAME.
  • The ui directory contains the front end code for the plugin. This is where you will write your UI elements, call APIs, and present data to the user. If you need additional dependencies, navigate to the ui directory and run npm install --save PACKAGE_NAME.

Additionally, you can customize the plugin name by modifying the bcms-plugin.config.json file


Plugin back end

Both BCMS and BCMS Plugins use Purple Cheetah for the back end. This means that you will use Purple Cheetah to create controllers and middleware. When you create a new plugin project, it will include example code for a simple To-do plugin to help you get started quickly.

Creating an Endpoint

To create an endpoint, follow these steps:

  1. Create a controller/middleware object in the back end directory. For example, create a hello-world.ts file with the following code:

backend/hello-world.ts

import {
  createController,
  createControllerMethod,
} from '@becomes/purple-cheetah';

export const HelloWorldController = createController({
  name: 'Hello world',
  path: '/hello',
  methods() {
    return {
      helloWorld: createControllerMethod<void, { message: string }>({
        path: '/world',
        type: 'get',
        async handler() {
          return {
            message: 'Hello world!',
          };
        },
      }),
    };
  },
});
  1. To make this controller available, the only thing left to do is to add it to BCMS Plugin handler:

backend/main.ts

import { createBcmsPlugin } from '@becomes/cms-backend/plugin';
import { HelloWorldController } from './hello-world';
import { TodoController } from './todo';

export default createBcmsPlugin({
  name: 'bcms-plugin---name',
  controllers: [
    TodoController,
    HelloWorldController, // <-- This is your controller
  ],
});
  1. Restart the BCMS Plugin by running docker-compose up again.
  2. You can now send a request to this controller, and you'll get this:
GET http://localhost:8080/api/plugin/bcms-plugin---name/hello/world

-----------------------

HTTP/1.1 200 OK
Server: nginx
Date: Thu, 23 Mar 2023 11:51:45 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 26
Connection: close
X-Powered-By: Express
Access-Control-Allow-Origin: *
ETag: W/"1a-T7vCLEZV7pLSyUzkr9XBdG32YU8"

{
  "message": "Hello world!"
}

That's it! You have successfully created and registered a new endpoint in your BCMS Plugin.

If you want to restrict access to the endpoint, you can use BCMSRouteProtection to create endpoint protection using JWT authentication.

import type { BCMSRouteProtectionJwtResult } from '@becomes/cms-backend/types';
import { BCMSRouteProtection } from '@becomes/cms-backend/util';
import {
  createController,
  createControllerMethod,
} from '@becomes/purple-cheetah';
import {
  JWTPermissionName,
  JWTRoleName,
} from '@becomes/purple-cheetah-mod-jwt/types';

export const HelloWorldController = createController({
  name: 'Hello world',
  path: '/hello',
  methods() {
    return {
      helloWorld: createControllerMethod<
        BCMSRouteProtectionJwtResult,
        { message: string }
      >({
        path: '/world',
        type: 'get',
        // Endpoint protection using JWT authentication
        // --------------------------------------------
        preRequestHandler: BCMSRouteProtection.createJwtPreRequestHandler(
          [JWTRoleName.ADMIN, JWTRoleName.USER],
          JWTPermissionName.READ
        ),
        async handler() {
          return {
            message: 'Hello world!',
          };
        },
      }),
    };
  },
});

After this modification if you try to send the request from above again, you will get:

HTTP/1.1 401 Unauthorized
Server: nginx
Date: Thu, 23 Mar 2023 12:03:20 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 35
Connection: close
X-Powered-By: Express
Access-Control-Allow-Origin: *
ETag: W/"23-P6T7nIGEhyt+0WRId7BsUh87luo"

{
  "message": "Token is `undefined`."
}

Plugin front end

You can find the front end code for the plugin in the ui directory. The BCMS UI uses Vue 3 and .tsx syntax. The plugin starter kit includes everything you need to get started. It's recommended to follow the code from the starter kit to help speed up the process.

Developers can access the SDK via window.bcms.sdk.*. This makes it easy to access the back end API.


Deploying a plugin

When you are ready to deploy your plugin to the CMS, follow these steps:

  • Run npm run bundle to bundle the back end and front end code and create a plugin package.
  • Run npm run deploy to deploy the bundled plugin to the CMS. It may take a few moments for the changes to appear in the CMS.