#Getting Started
The MercuryCMS Addon System is a powerful platform that gives you access to all of Mercury's features and allows you to extend it with your own Screens, Collections, Components, and functionality.
Before you get started, you should know how Addons work and interact with MercuryCMS.
- Addons are installed via package files
- MercuryCMS provisions a directory for the Addon's code, file storage, and a database
- The Addon Package has a manifest that tells MercuryCMS about the Addon such as the name and what processes it will run
- MercuryCMS launches the Addon's processes which must continually run alongside MercuryCMS
- Addons are servers that talk to MercuryCMS and provide an API for MercuryCMS to talk to
- Addons also serve their provided Screens (such as their settings) as HTML/CSS/JS
- Addons provide their own API for their Screens to talk to
If this seems a bit complicated, don't worry, it's actually a very simple and flexible way to add functionality to Mercury.
#Demo Addon
To make things easy, we'll use the static-cms-addon
npm package to write a simple demo Addon. This will gloss over a lot of details which are explained later in the rest of the Addon Development documentation.
First, let's make a new directory and a single file called addon.json
.
{
"name": "demo",
"displayName": "Demo",
"description": "A quick demo addon",
"author": "Allister Aligerum",
"version": "1.0.0",
"dependencies": [
{"type": "node", "path": "/"}
],
"settingsPath": "/settings",
"processes": {
"main": {
"type": "node",
"main": "/index.js",
"ports": 1,
"interface": true
}
}
}
This manifest file tells MercuryCMS everything it needs to know about our Addon:
- The name of the Addon (which must only contain lowercase characters, numbers, and dashes) and its display name (used in the Addon list)
- MercuryCMS should install the Addon's dependencies by running
npm install
in the root of this directory when the Addon is installed - The Settings button should navigate to
/addons/demo/settings
(which will be an interface Screen our Addon will provide that we'll make in a moment) - MercuryCMS should navigate to our Addon's installation directory and run
node index.js
to start the Addon - That process that it starts will require 1 port to talk to MercuryCMS and will provide the Addon's interface Screens the user can see
#Dependencies
The only dependency this Addon will have is the static-cms-addon
npm package. We can run npm init
and then npm i @mercury-cms/static-cms-addon
.
#Make the Addon Server
Now let's make an index.js
file. This file will be run when MercuryCMS starts our Addon. Here, we will start an Express server to serve our Addon's interface screens and provide an API to communicate with MercuryCMS.
// index.js
import cms from 'static-cms-addon'
let app = cms.createServer()
app.use(cms.static('public'))
app.listen(cms.getPort(), () => {
console.log(`Demo Addon running on port ${cms.getPort()}`)
})
This will serve html
files from the public
directory, which we haven't created yet, So let's do that. Create a public
directory, then another directory called settings
inside of that, and put an index.html
file in it.
<!-- public/settings/index.html --->
<html>
<head>
<title>Demo</title>
</head>
<body>
<p>This is our Settings Screen!</p>
</body>
</html>
Once our Addon is installed, any page routes the user tries to access from the interface that start with /addons/demo
will be proxied to our Addon's server. In this case, when they install the Addon and click the Settings button, Mercury will send them to /addons/demo/settings
which will be routed to /settings
at our Express server. That will serve this HTML document.
#Packaging The Addon
Now let's package this Addon and install it. Let's make a file called build.js
and run it. This will package our Addon into a single file that can be installed into MercuryCMS.
// build.js
import cms from 'static-cms-addon'
cms.packageAddon()
This will create a file in the parent directory of your Addon's source code called demo-1-0-0.addon.zip
. Now we can go to the Addons screen and install it. Once it's running, you can click the Settings button to see the Settings page we created.
#Saving and Loading Settings
Now let's make our settings screen actually store the Addon's settings. We'll need to store the settings in the database MercuryCMS provides us. Update/create the following files:
<!-- public/settings/index.html --->
<html>
<head>
<title>Demo</title>
<link rel="stylesheet" href="/api/addon/style.css">
<link rel="stylesheet" href="settings/style.css">
</head>
<body>
<div class="settings-page">
<div class="app-card">
<p>This is our Settings Screen!</p>
<div class="site-input-group">
<div class="label">License Key</div>
<input class="site-input" id="license-input">
</div>
<div class="buttons">
<div class="app-button" onclick="handleSave()">Save</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js"></script>
<script src="/api/addon/script.js"></script>
<script src="settings/script.js" type="module"></script>
</body>
</html>
/* public/settings/style.css */
.settings-page {
padding: 16px;
}
.settings-page .app-card .buttons {
margin-top: 8px;
}
// public/settings/script.js
let response = await axios.get(`${cms.getUrl()}/api/settings`)
document.getElementById('license-input').value = response.data.settings.licenseKey
window.handleSave = async function () {
let licenseKey = document.getElementById('license-input').value
await axios.put(`${cms.getUrl()}/api/settings`, {licenseKey})
cms.queueNotification({body: 'License Key saved'})
}
// index.js
import cms from 'static-cms-addon'
// init settings
if (!await cms.database.collection('settings').findOne()) {
await cms.database.collection('settings').insertOne({
licenseKey: '',
})
}
// add sidebar
await cms.setSidebarItems([
{icon: 'star', name: 'Demo', path: '/settings'},
])
// create server
let app = cms.createServer()
app.use(cms.static('public'))
// get settings for frontend
app.get('/api/settings', async (req, res) => {
let settings = await cms.database.collection('settings').findOne()
res.send({settings})
})
// update settings from frontend
app.put('/api/settings', async (req, res) => {
await cms.database.collection('settings').updateOne({}, {$set: {licenseKey: req.fields.licenseKey}})
res.send()
})
// start the server
app.listen(cms.getPort(), () => {
console.log(`Demo Addon running on port ${cms.getPort()}`)
})
You can now build and install this Addon and you have a functioning demo that looks like a native part of MercuryCMS. Here are some notes about what the Addon is now doing:
settings/index.html
includes/api/addon/style.css
which is a stylesheet MercuryCMS provides to allow you to make native-looking interfaces that respects the user's theme preference and Dark Mode settingssettings/index.html
includes/api/addon/script.js
which is a script file that provides acms
object you can use to get the URL to talk to your Addon's APIsettings/index.html
is includingstyle.css
andscript.js
which is being provided by the Addon's serversettings/script.js
is populating the input field with the saved setting, saving the new setting to the API provided by the Addon, and showing a notification using thecms
object provided by the/api/addon/script.js
scriptindex.js
is now providing a sidebar itemindex.js
initializes settings in the database if they don't exist and allows the frontend to retrieve them and update them
From here, you can dig into the rest of the documentation. The Addon System provides a lot of powerful tools you can use to integrate with all of the features MercuryCMS provides. Have fun!