Related Items Block
Renders the current page's related items relation field (default relatedItems) as a list, reusing the listing machinery — each related item is rendered with a configurable item type (variation).
Live example
Listing
The listing block allows the display of various listings of content. Editors can configure a number of criteria for listing content (e.g. all news from 2022 with the keyword 'research').
Maps
The maps block can have embeded a Map (Google Maps, OpenMaps, etc).
Developer Reference
Schema
Pass this object inside the blocks option when calling initBridge() to register this block type with the admin UI. See Custom Blocks for the full setup guide.
{
"relatedItemsListing": {
"id": "relatedItemsListing",
"title": "Related Items",
"blockSchema": {
"fieldsets": [
{
"id": "default",
"title": "Default",
"fields": [
"relationField",
"variation",
"fieldMapping"
]
}
],
"properties": {
"relationField": {
"title": "Relation field",
"widget": "schemaFieldSelect",
"fieldType": "relation"
},
"variation": {
"title": "Item Type",
"widget": "blockTypeSelect",
"filterConvertibleFrom": "@default",
"default": "summary"
}
}
},
"schemaEnhancer": {
"inheritSchemaFrom": {
"typeField": "variation",
"mappingField": "fieldMapping",
"defaultsField": "itemDefaults"
}
}
}
}JSON Block Data
Example JSON as stored in the Plone content API. This is the data structure your component will receive in the block prop.
{
"@type": "relatedItemsListing",
"variation": "summary",
"relationField": "relatedItems"
}Rendering
How this block renders in your frontend. Add its handling to your renderer, or — for list-style blocks — register a fetcher and reuse your list rendering.
This block has no bespoke renderer — register the fetcher below, then render its items exactly like any list block. See the Listing example for the render component in React, Vue and Svelte, Listings for how expansion works, and Custom Blocks for registering a block type. Only the fetcher below is block-specific.
export function relatedItemsFetcher({ apiUrl, contextPath }) {
return async function fetchItems(block, { start, size }) {
const field = block.relationField || 'relatedItems';
const content = await (await fetch(`${apiUrl}${contextPath}/++api++`, { headers: authHeaders() })).json();
const all = Array.isArray(content[field]) ? content[field] : [];
return { items: all.slice(start, start + size), total: all.length };
};
}// 1. Register the fetcher when you init the bridge (keyed by block @type)
initBridge(origin, { blocks, fetchItems: { relatedItemsListing: relatedItemsFetcher({ apiUrl, contextPath }) } });
// 2. Render — identical to any list block
const { items } = await expandListingBlocks([blockId], {
blocks: { [blockId]: block },
fetchItems: { relatedItemsListing: relatedItemsFetcher({ apiUrl, contextPath }) },
itemTypeField: 'variation',
});
items.forEach((item) => renderBlock(item)); // your normal per-block renderer