Plugins
You can use the Madoc Bundler (opens in a new tab) to get started creating plugins for Madoc. This will allow you to create custom pages, override existing pages, and add blocks to pages. You can also use the Example Madoc Plugin (opens in a new tab) as a reference.
Installation
Install the package.
$ yarn add @madoc.io/bundler
Add some Madoc metadata to your package.json
:
{
"madoc": {
"id": "[ UUID v4 ]",
"name": "[ Name of your plugin ]",
"description": "[ Short description of what your plugin does ]"
}
}
Make sure you have the repository
and name
fields set in your package.json
.
Usage
Note you will need a local version (opens in a new tab) of Madoc running
Sample rollup.config.js
with React/Typescript:
import typescript from 'rollup-plugin-typescript2';
import resolve from '@rollup/plugin-node-resolve';
import compiler from '@ampproject/rollup-plugin-closure-compiler';
const isProduction = process.env.NODE_ENV === 'production';
export default {
input: 'src/index.ts',
output: [
{
dir: 'dist',
format: 'umd',
globals: {
react: 'React',
},
},
],
external: ['react'],
plugins: [
typescript({ target: 'es5' }),
resolve({ browser: true }),
isProduction && compiler(),
].filter(Boolean),
};
You can add scripts to your package.json
{
"scripts": {
"start": "madoc-bundler --watch",
"build": "NODE_ENV=production madoc-bundler"
}
}
and run them with:
$ npm run start
or
$ yarn start
When you run this, you will be prompted to provide the URL of your Madoc instance. You can set this in an environment variable:
MADOC_ENDPOINT=http://localhost:8888;
MADOC_SITE=default;
You will then be taken to your madoc site where you can install your plugin. Once you've done this, any changes you make will be reflected on madoc (with a page refresh). This includes server-side rendering.
Plugins are applied per-site.
Getting started
There are 3 hooks into Madoc implemented at the moment.
- hookRoutes
- hookComponents
- hookBlocks
hookRoutes
This hook allows you to create custom pages in Madoc. Simply return a list of routes you'd like added, and they will be added to the end of the router. The router used is React router (opens in a new tab). Definitions follow their format. Components are just React components.
// src/index.js
export function hookRoutes() {
return [
{
path: '/my-plugin/some-page',
component: TestPluginPage,
exact: true,
},
]
}
Server rendering
To render data on the server, you can use the Madoc.serverRendererFor
helper:
import { serverRendererFor } from '@madoc.io/types';
function TestPluginPage({ loader }) {
// A helper is injected for data loading. This desugars to: Madoc.useData(TestPluginPage);
// This uses React Query under the hook.
// Documentation: https://react-query-v2.tanstack.com/docs/guides/queries
const { data, isLoading } = loader.useData();
if (isLoading || !data) {
return <div>loading...</div>
}
// Use data here.
return <div />
}
serverRendererFor(TestPluginPage, {
getKey: (params, query, pathname) => {
// params from from your route. So /my-plugin/:test would yield {"test": "..."} in params
// query is the query string
// pathname is the full pathname on madoc (does not contain the site slug /s/default .. )
// The full key returned should be unique based on the params and query. This will be used for caching.
// The first part can be generic (e.g. ['load-page', { pageId: '1234' } ])
// Checkout https://react-query-v2.tanstack.com/docs/guides/queries#array-keys for more details.
return ['key-name', { page: query.page }];
},
getData: async (key, vars, api, pathname) => {
// Key is the first part of your key above ('key-name')
// vars is the second part of your key ({ page: 0 })
// API is the full madoc API, same one used to build all current components.
// Get data can return anything. It _should_ be a promise.
return api.getCollections(vars.page);
},
})
hookComponents
You can use hookComponents
to override existing pages on Madoc.
The component is a React component, and has the same API available and server rendering as hookRoutes
// src/index.js
export function hookComponents() {
return {
AllCollections: ListCollectionsReplacement,
}
}
Full list of components can be found here (opens in a new tab).
You can access data loaders used on these pages through included hooks
hookBlocks
Madoc has a concept of a page block. Details can be found here (opens in a new tab).
// src/index.js
export function hookBlocks() {
return {
MyTestBlock
};
}
They are small React components that can be placed on various pages, configured and reordered as editorial content. Depending on where a block is contextually on the site, it may have access to resources on the page (collections, manifest, canvases etc.).
Example block:
import React from 'react';
import { blockConfigFor } from '@madoc.io/types';
export const MyTestBlock = ({ text }) => {
return <div>Display some configurable text: {text}</div>;
};
blockConfigFor(MyTestBlock, {
type: 'MyPlugin.MyTestBlock',
label: 'My test block',
defaultProps: {
text: '',
},
editor: {
text: 'text-field',
},
requiredContext: [],
anyContext: [],
});
With this definition, users will be able to place instances of your block on Madoc pages. They will be shown a form where they can configure the props (text in this example).