Create a Webiny Headless CMS address field plugin
What you'll learn
- How to create a new content model field plugin
- How a plugin stores and retrieves data
#
OverviewA detailed and more in-depth explanation and how-to for a Webiny Headless CMS field plugins. As an example, in this tutorial you will create a new field plugin that uses Google Maps API to retrieve a location or an address. In this tutorial we assume that you know how Webiny plugins work.
Tutorial example files are located in our example repository.
#
Tutorial narrativeYou need a field that gives you a functionality to search for an address via Google Maps API. When you select the address you want, from the list the Google Maps API provided, it is set to the form data. Also, you do not want to index that field, and you want to encrypt it before saving into the storage.
#
The placement of the pluginsBy all means, you can create plugins where ever you want - but try to stick to some structure.
You have api
and apps
directories, so put your plugins in those, according to a plugin type.
Our suggestion would be something like this:
[UI]
plugins folder -apps/admin/code/src/plugins/headlessCMS/fields/address/
[API]
plugins folder -api/code/headlessCMS/src/fields/address/
Your field type is a name of the directory containing all the plugins for that type. Remember, there are multiple types of plugins for a single field type in both UI and API side.
Files we are creating are:
addressFieldPlugin.ts
- API field definitionaddressFieldStoragePlugin.ts
- API storage modificationsaddressFieldIndexPlugin.ts
- API indexing modificationsaddressFieldPlugin.tsx
- UI field definition and display when creating a modeladdressFieldRendererPlugin.tsx
- UI display of the field when creating or updating the entry
info
For quick info on required plugins check our How-to Guide: Create a Webiny Headless CMS field plugin.
#
UI plugins#
Definition pluginFirst we need to create a field definition plugin. The base for the plugin is:
And in the createField()
function we return the field data:
Note that renderer name is left blank so code automatically determines which renderer to use. You can put the name of the renderer, but for our tutorial we leave it blank and use it later.
#
Renderer pluginNow we can create the second UI plugin, a renderer for the field we just created. A base for the renderer plugin is:
Remember that we left the renderer.name
property blank when we created the field? Now in the canUse()
function you put the condition that determines if that particular renderer is for a given field:
In the render()
function you put what is actually displayed when the field rendering is called. We can create a onSelect()
function that actually triggers the field change - bind.onChange()
.
#
API plugins#
Definition pluginNow let's go solve the API plugins. First we need to create a plugin of type CmsContentModelField
.
This is the base of that plugin:
#
Read definitionsIn the read definition, for the read and preview API, we can have a user-friendly GraphQL field:
And the resolver for that field:
Since we do not want the field to be filtered, we do not need to define createGetFilters
or createListFilters
.
#
Manage definitionsThe manage side of the API can be exactly the same as the read one, but in our case it is a bit different. Since we save plain JSON value, this part is quite simple:
#
Indexing pluginNow we have everything required to create and save the field. Next thing we need is to prevent the indexing of the field. By default, if a field is not searchable it is removed from the index. But for this tutorial we can create our own plugin. This is the base of that plugin:
In toIndex
we must remove the field from values
and put it into non-indexable rawValues
object:
And in fromIndex
we must revert that action:
This plugin now does what we want - disables the field indexing. Of course, we could pack the field with jsonpack
or compress it in the toIndex
method to take less space. The choice is all yours, just remember to revert what ever action you do.
#
Storage pluginAll we have left to write is the plugin for storage. As we said, we want to encrypt the data for the storage. You can what ever library you want, it is all up to you. For this tutorial we can use some custom encrypt
and decrypt
functions. The base of the plugin looks like this:
First, we encrypt the data. Our suggestion is to encrypt the data and return an object with encrypted value and method of encryption:
Of course if you want to just return the encrypted value, feel free, the choice is yours.
And then comes the decryption. Because we expect our value to have some structure, it is easy to check if decryption is necessary. Or if we need to throw an error due to something we expect is not there.
You should now have a functioning field, apart the AddressSearch
component and encrypt
/decrypt
functions - it is up to you to created them.
#
Last stepsRemember that you need to import the plugins.
Default import file location for API is api/code/headlessCMS/src/index.ts
and for UI it is apps/admin/code/src/plugins/headlessCms.ts
.
If you changed that, import in these locations.
danger
Do not forget to rebuild, redeploy and rerun your application.
... and
... or