Plugin SDK > Migrating from legacy plugins

Migrating from legacy plugins

A completely revamped plugin SDK was released in November 2021. Plugins leveraging the legacy SDK will continue to work indefinitely, but are much more limited in their possibilities, as they can only manage what in the new SKD are called manual field extensions. All the other extension points are not available.

Legacy SDK docs

If you're looking for the Legacy SDK documentation, it is still available here.

If you are interested in migrating to the new SDK, please note the following points:

Global configuration parameters

Global parameters no longer need to be declared in the package.json, but are configurable through the config-screen hooks.

The data storage format is now also completely custom, as well as the interface that is shown to end users.

Manual extensions

The old options:

  • "Type of plugin" (field editor, field add-on or sidebar widget), and

  • "Types of field" (specifying where it's possible to use the legacy plugin)

do not have to be declared in the package.json anymore, but are configurable through the manualFieldExtensions hook. The old "sidebar widget" plugin type is nothing but an additional asSidebarPanel option you can pass to the new ManualFieldExtension type:

import { connect, Field, InitCtx } from 'datocms-plugins-sdk';
connect({
manualFieldExtensions(ctx: InitCtx) {
return [
{
id: 'sidebarWidget',
name: 'My sidebar widget',
type: 'editor',
fieldTypes: ['integer'],
asSidebarPanel: true,
},
];
},
renderFieldExtension(id, ctx) {
// ...
},
});

Instance configuration options

Instance parameters no longer need to be declared in the package.json, but are now completely arbitrary, as well as the interface that is shown to end users. Take a look at this part of the documentation.

plugin.xxx methods and properties

All methods and information previously available through plugin.xxx calls is now available through the ctx argument of the renderFieldExtension hook.

Migrating appearance on associated fields

Since new plugins can expose multiple manual field extensions, you need to implement an onBoot hook to properly set the fieldExtensionId attribute on each field that was previously hooked with the plugin.

Example to migrate old field editors or sidebar widgets
connect({
// plugin exposes a `myExtension` manual field extension
manualFieldExtensions(ctx: InitCtx) {
return [
{
id: 'myExtension',
name: 'Foo bar',
type: 'editor',
fieldTypes: ['integer'],
},
];
},
async onBoot(ctx: OnBootCtx) {
// if we already performed the migration, skip
if (ctx.plugin.attributes.parameters.migratedFromLegacyPlugin) {
return;
}
// if the current user cannot edit fields' settings, skip
if (!ctx.currentRole.meta.final_permissions.can_edit_schema) {
return;
}
// get all the fields currently associated to the plugin...
const fields = await ctx.loadFieldsUsingPlugin();
// ... and for each of them...
await Promise.all(
fields.map(async (field) => {
// set the fieldExtensionId to be the new one
await ctx.updateFieldAppearance(field.id, [{
operation: 'updateEditor',
newFieldExtensionId: 'myExtension',
}]);
}),
);
// save in configuration the fact that we already performed the migration
ctx.updatePluginParameters({
...ctx.plugin.attributes.parameters,
migratedFromLegacyPlugin: true,
});
},
});
Example to migrate old field addons
connect({
// plugin exposes a `myExtension` manual field extension
manualFieldExtensions(ctx: InitCtx) {
return [
{
id: 'myExtension',
name: 'Foo bar',
type: 'addon',
fieldTypes: ['integer'],
},
];
},
async onBoot(ctx: OnBootCtx) {
// if we already performed the migration, skip
if (ctx.plugin.attributes.parameters.migratedFromLegacyPlugin) {
return;
}
// if the current user cannot edit fields' settings, skip
if (!ctx.currentRole.meta.final_permissions.can_edit_schema) {
return;
}
// get all the fields currently associated to the plugin...
const fields = await ctx.loadFieldsUsingPlugin();
// ... and for each of them...
await Promise.all(
fields.map(async (field) => {
const { appearance } = field.attributes;
const changes: FieldAppearanceChange[] = [];
// find where our plugin is used...
appearance.addons.forEach((addon, index) => {
// set the fieldExtensionId to be the new one
changes.push({
operation: 'updateAddon',
index,
newFieldExtensionId: 'myExtension',
});
});
await ctx.updateFieldAppearance(field.id, changes);
}),
);
// save in configuration the fact that we already performed the migration
ctx.updatePluginParameters({
...ctx.plugin.attributes.parameters,
migratedFromLegacyPlugin: true,
});
},
});