9. Plone integration with Volto blocks – Volto Add-ons Development

9. Plone integration with Volto blocks#

When developing for Volto websites, don't neglect the server-side, Plone. Beyond the regular endpoints and expanders that plone.restapi offers, there's a few dedicated features that can improve the quality of Volto-powered websites.

9.1. Block transformations#

The main feature that applies to Volto blocks is called the "blocks transformers". They are adaptors that can be registered per block type. They can alter the output on serialization (when the fetching information from Plone), as well as on deserialization (when information arrives in Plone, from the client).

@implementer(IBlockFieldDeserializationTransformer)
@adapter(IBlocks, IBrowserRequest)
class DatabaseQueryDeserializeTransformer(object):
    order = 100
    block_type = 'database_listing'

    def __init__(self, context, request):
        self.context = context
        self.request = request

    def __call__(self, value):
        value["items"] = db.query(value)    # pseudo code
        return value

Then register it as a subscription adapter:

<subscriber factory=".blocks.DatabaseQueryDeserializeTransformer"
  provides="plone.restapi.interfaces.IBlockFieldDeserializationTransformer"/>

Note that you'll probably want to also register the reverse.

9.2. Smart fields#

It is possible to register a generic block transformer that applies to all block types. By doing so we can process block information consistently for all blocks, providing us with the "smart fields" concept.

A "smart field" is a convention: "all block fields named url will be transformed on serialization/deserialization, to store them with a resolveuid".

9.3. Searchable text from blocks#

@implementer(IBlockSearchableText)
@adapter(IBlocks, IBrowserRequest)
class ImageSearchableText(object):
    def __init__(self, context, request):
        self.context = context
        self.request = request

    def __call__(self, block_value):
        return block_value['alt_text']

This adapter needs to be registered as a named adapter, where the name is the same as the block type (its @type property from the block value).

<adapter name="image" factory=".indexers.ImageBlockSearchableText" />

Examples of potential smart fields:

  • _v_* blocks, to provide volatile data from the backend

  • blob, which would deserialize base64-encoded binary data to an attachment store, then serialize back as a simple download link

Note

These smart fields don't exist right now. But it would be great if they did exist.