---
myst:
html_meta:
"description": "Writing a block transform"
"property=og:description": "Writing a block transform"
"property=og:title": "Writing a block transform"
"keywords": "Volto, Plone, REST API, plone.restapi, Volto blocks, Serialization, Block Transformers"
---
# Writing a block transform
Practical experience has shown that it is useful to transform, server-side, the value of block fields on inbound (deserialization) and also outbound (serialization) operations.
For example, HTML field values are cleaned up using `portal_transforms`.
Or paths in image blocks are transformed to use `resolveuid`.
It is possible to influence the transformation of block values per block type.
For example, to tweak the value stored in an image type block, we can create a new subscriber as follows:
```python
@implementer(IBlockFieldDeserializationTransformer)
@adapter(IBlocks, IBrowserRequest)
class ImageBlockDeserializeTransformer(object):
order = 100
block_type = 'image'
def __init__(self, context, request):
self.context = context
self.request = request
def __call__(self, value):
portal = getMultiAdapter(
(self.context, self.request), name="plone_portal_state"
).portal()
url = value.get('url', '')
deserialized_url = path2uid(
context=self.context, portal=portal,
href=url
)
value["url"] = deserialized_url
return value
```
Then register it as a subscription adapter:
```xml
```
This would replace the `url` value to use `resolveuid` instead of hard coding the image path.
The `block_type` attribute needs to match the `@type` field of the block value.
The `order` attribute is used in sorting the subscribers for the same field.
A lower number has higher precedence, that is, it is executed first.
On the serialization path, a block value can be tweaked with a similar transformer
For example, on an imaginary database listing block type:
```python
@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) # pseudocode
return value
```
Then register it as a subscription adapter:
```xml
```
## Generic block transformers and smart fields
You can create a block transformer that applies to all blocks by using `None` as the value for `block_type`.
The `order` field still applies, though.
The generic block transformers enable us to create **smart block fields**, which are handled differently.
For example, any internal link stored as `url` or `href` in a block value is converted (and stored) as a `resolveuid`-based URL, then resolved back to a full URL on block serialization.
Another **smart field** is the `searchableText` field in a block value.
It needs to be a plain text value, and it will be used in the `SearchableText` value for the context item.
If you need to store "subblocks" in a block value, you should use the `blocks` smart field (or `data.blocks`).
Doing so integrates those blocks with the transformers.