CMS Plugins
To create a custom plugin for the CMS provider, you need to define each of the methods in the CMS plugin interface. Each interface can be found under its respective directory within the CMS Provider source code.
Review the X.types.ts
file in each directory for the plugin interface. The type you are looking for is XPlugin
, for example, ContentPlugin
; don't be confused with the other types in this file, such as UseXPlugin
. This interface will tell you what parameters the plugin needs to handle and what interface or methods the plugin needs to return.
The CMS provider currently accepts the following plugins:
- Content
- ContentSearch
- Menu
- Redirects
- Routes
- Tag
- User
Example: Content Plugin
Overview
Let's create a content plugin. Here is the interface for the ContentPlugin
:
export type ContentPlugin = (
config: Config,
id: string,
path?: string,
options?: Record<string, unknown>,
) => Promise<Content>;
The content plugin method takes four parameters: two required and two optional.
config
: The plugin configuration. This object is passed in at the time of registering the plugin (see Register the plugin).id
: The ID of the content to load.path
(optional): The path alias of the content to load.options
(optional): Options to expose to the user for further customization.
Important Considerations Regarding Plugin Parameters
- Use wildcard parameters sparingly: Flexible props like
options
should be used with caution. - Gesso Compatibility: If you plan to port your plugin to Gesso, avoid using wildcard parameters altogether.
- Alternatives to new parameters and options: Before using
options
, consider these alternatives:- Project Configuration: Can the data be set as a project-level configuration?
- Plugin Logic: Can the data be retrieved within the plugin itself (e.g., via API request or additional logic)?
- Consult for New Parameters: If you require data that cannot be obtained through the existing parameters or the alternatives mentioned above, please reach out to us on Slack in the #gesso-support channel to discuss adding a new parameter to the interface.
- Custom Plugin Impact: If you are building a fully custom plugin specifically for your project, you can use
options
. However, remember that custom logic built aroundoptions
might make it harder to switch out or add plugins in the future.
The plugin is an async method (returning a promise) that resolves to Content
. This tells you the structure of the data your plugin needs to return.
Let's take a look at the Content
interface:
export interface Content {
id: string;
title: string;
status?: boolean;
author?: string;
data: {
[key: string]: unknown;
};
}
The response of the content plugin must follow this shape:
id
(required): The ID of the content returned.title
(required): The title of the content returned.status
(optional): The status of the content if it exists.author
(optional): The author of the content if it exists.data
(optional): Any additional data on the content.
The four fields (id
, title
, status
, and author
) are standard fields that all content should contain. The last field (data
) is for any unknown data. This data cannot be standardized across plugins.
Important Considerations Regarding Plugin Responses
- Coupling and Flexibility: Plugins that heavily rely on the
data
prop for core functionality become tightly coupled to the specific structure they define within it. This can hinder future updates or modifications to other Gesso packages, such as the design system. - Intended Usage: The
data
prop should primarily be used for displaying project-specific information that doesn't require standardization across plugins (e.g., an additional subtitle). Avoid building core plugin logic around thedata
prop. - Standardization: If you identify data fields within
data
that could be beneficial across multiple plugins (e.g.,publishedDate
,tags
), consider adding them as explicit properties to the Gesso interface.
Let's put this together to create a basic Content plugin.
Create the plugin
// Import the interfaces
import { Content, ContentPlugin } from '@acromedia/gesso-cms';
// Define and export the plugin.
export const content: ContentPlugin = async (
config,
id,
path?,
options?,
) => {
// Make a request to get the data.
// Return your data.
return {
id: '1',
title: 'Sample Content',
status: true,
author: 'Dwight Schrute',
data: {
example: 'some data',
},
};
};
Now export your plugin from your module's entry file (typically index.ts
):
export * from './Content/Content.tsx';
Register the plugin
With your plugin created, you can now register it with your provider. On your frontend, create a file to register the plugins:
// customProvider.ts
import { useCMS as CMS } from '@acromedia/gesso-cms';
import plugins from '@acromedia/your-plugin';
const config = {
// Insert any configurations you require.
};
// Register your plugins with the CMS provider.
export const cms = CMS(plugins, config);
You can now import your methods from this file where needed:
// Client-side method
import { useContent } from 'path/to/customProvider';
// Server-side method
import { getContent } from 'path/to/customProvider';