umanit/block-collection-bundle
A Symfony bundle from Umanit for defining, grouping, and rendering reusable content blocks as collections, making it easier to assemble flexible page sections and manage block-based content without bespoke glue code.
Install the bundle with Composer and register it in config/bundles.php:
composer require umanit/block-collection-bundle
// config/bundles.php
return [
// ...
Umanit\BlockCollectionBundle\UmanitBlockCollectionBundle::class => ['all' => true],
];
Because this package only ships blocks (not the underlying block/page engine), you almost always need its companion infrastructure installed first — typically umanit/block-bundle and/or umanit/twig-page-bundle. Check composer.json of the package for its require block; that tells you which host system the blocks are designed to plug into.
Where to look first:
src/Block/ — this is the catalog of available block types (text, image, video, quote, button, gallery, etc.). This directory is the product.src/Resources/views/ — the Twig templates that render each block. Read these to understand the expected data shape of every block.src/Resources/config/ — service definitions and any block tags/registrations.src/Form/ — the admin form types used to edit block content.First use case: once the bundle is enabled and migrations for the block entities are run (bin/phpunit-style smoke test: bin/console doctrine:schema:validate), create a page (or whatever your host block system calls a container) and attach a TextBlock + ImageBlock to it in the admin. Render it in a Twig template using the host bundle's renderer, e.g. {{ page|render_blocks }} or a render_block(block) Twig function — confirm the exact helper by grepping the host bundle's Twig extension.
Treat blocks as composable content primitives. The intended workflow is: an editor builds a page out of N blocks in the admin, and the frontend renders each block through its own template. Your job is rarely to modify the blocks themselves but to:
Adding a custom block that fits the collection. Extend whatever AbstractBlock the package exposes (look in src/Block/ for the base class — the concrete blocks extend it), implement the required getters, and tag the service so the block is auto-discovered:
namespace App\Block;
use Umanit\BlockCollectionBundle\Block\AbstractBlock;
class CtaBlock extends AbstractBlock
{
public function getTemplate(): string
{
return 'block/cta.html.twig';
}
}
Register it as a service (autowiring usually picks it up) and add the tag the compiler pass expects — grep BlockCollectionBundle for addTag( or CompilerPass to confirm the tag name before wiring it.
Template overriding. Symfony's bundle override path is the cleanest integration point. Copy src/Resources/views/block/foo.html.twig into templates/bundles/UmanitBlockCollectionBundle/block/foo.html.twig and adjust it. This is preferred over editing vendor code and survives composer update.
Integration with admin. Most Umanit blocks ship a Symfony form type. If you use EasyAdmin or Sonata, expose each block type as a sub-form via CollectionType with an entry_type per block class; if you use the companion umanit/twig-page-bundle, the admin wiring is already done and you only deal with templates.
Rendering pattern. Blocks should render themselves — template + entity. Avoid putting block-specific if branches in your page template; instead, let the block expose a getTemplate() and delegate to the renderer. This keeps adding new blocks a zero-diff operation in page templates.
Testing pattern. Since the package has almost no test coverage of its own, write a small functional test per block you rely on:
public function testTextBlockRenders(): void
{
$block = (new TextBlock())->setContent('<p>hi</p>');
$html = $this->renderBlock($block);
self::assertStringContainsString('<p>hi</p>', $html);
}
This is your guardrail against upstream template changes across minor releases.
git log and CHANGELOG.md are more reliable than the docs.umanit/block-bundle is installed and configured — a large fraction of issues are actually integration gaps, not bugs.bin/console doctrine:migrations:diff and inspect the generated migration before applying — an un-migrated block table throws confusing "no such table" errors at render time, not at boot.bin/console debug:container --tag=<block_tag> to verify the compiler pass is still tagging them.bin/console cache:clear — not just a browser refresh.umanit_block_collection (or similar) translation domain. If labels show raw keys in the admin, either enable the translations or add your own translations/UmanitBlockCollectionBundle.*.yaml.App\Block\ and override getTemplate() rather than editing vendor/umanit/.... Upstream is essentially unmaintained relative to a typical dependency, so you want your customizations isolated."umanit/block-collection-bundle": "1.x" or the exact release) and commit composer.lock. Do not rely on ^ ranges for a package with this little external usage.umanit.block_collection.registry or similar — check Resources/config/services.yaml), the AbstractBlock::getTemplate() method, and the block renderer Twig extension. These three are where 95% of customizations happen.How can I help you explore Laravel packages today?