anomaly/demo_block-extension
A demo block extension for the Anomaly CMS that provides a sample block type showing how to build, register, and render custom blocks in Streams-powered pages. A handy reference for developers creating their own block extensions.
Prerequisites. You need a Streams Platform / PyroCMS application with the anomaly/blocks-module installed and enabled. This package is an extension for the Blocks module — it does nothing on its own and won't register a block type unless the Blocks module is present.
Install (from source, not Packagist). Since this is a demo repo, add it as a VCS repository rather than assuming a Packagist entry:
"repositories": [
{ "type": "vcs", "url": "https://github.com/anomalylabs/demo_block-extension" }
]
Then install:
composer require anomaly/demo_block-extension
php artisan addon:install anomaly/demo_block-extension
If you'd rather not touch vendor/, clone into your project's addons/ directory, add a path repository, and run composer dump-autoload.
Where to look first. Open these three files in order:
src/DemoBlockExtension.php — the whole addon lives here. Note the class extends the Blocks module's BlockExtension and defines the $view, the addon $slug, and often a form() method describing the fields the block exposes.resources/views/ — the Blade file the block renders through. This is where the field values become markup.resources/lang/en/addon.php — the name/description strings shown in the Blocks admin UI.First use case: use it as a scaffold. Don't treat this as a feature. Copy the directory into your own addon path, rename the namespace, slug, and view namespace, and you have a working custom block type in about ten minutes. It's the canonical starting point for "my client needs a testimonial/CTA/pricing block."
Copy-and-rename is the intended workflow. Everything is keyed off a small set of strings that must agree:
| Thing | Example value |
|---|---|
| Composer name | anomaly/demo_block-extension |
| Addon slug | anomaly/demo_block-extension |
| PSR-4 namespace | Anomaly\DemoBlockExtension\ |
| Extension class | DemoBlockExtension |
| Directory | demo_block-extension/ |
| View namespace | anomaly.extension.demo_block::... |
Change all six together or the addon silently fails to appear.
Defining fields on the block. Most of your day-to-day work happens in the extension's form() method, using Streams field types (text, textarea, select, image, relationship, repeater, etc.):
protected function form(FormBuilder $builder)
{
$builder->setFields([
'heading' => ['type' => 'text', 'required' => true],
'body' => ['type' => 'textarea'],
'image' => ['type' => 'files'],
]);
}
Then in the view, read them off the block:
<h2>{{ $block->heading }}</h2>
{!! $block->body !!}
Transform in the extension, render in the view. If the raw field data is awkward (a files relation, an array from a repeater, a select key that needs a label), compute a clean value in block()/the extension class rather than looping inside Blade. Keeps the template readable and testable.
Reuse across areas. Once installed, one block type can be placed in multiple block groups (header, footer, sidebar) via the Blocks admin. There's no per-page code to touch — content editors compose pages. That's the main integration win.
Localize labels. Add field.php and button.php to resources/lang/en/ alongside addon.php, so labels in the admin form come from translations rather than hardcoded strings. It's cheap now, painful to retrofit.
Compose with other addons. Blocks are often paired with the pages and types modules — a block type used in a page type's layout area is the most common pattern in real builds.
composer dump-autoload and php artisan addon:reinstall anomaly/demo_block-extension after any composer/namespace change.php artisan cache:clear, php artisan view:clear, php artisan addon:reinstall <slug>. A "view not found" error almost always means a stale view namespace, not a missing file.demo_block-extension on disk, demo_block in the view namespace, demo_block-extension in composer. The extension slug uses the underscore form; the addon slug uses the dash form.anomaly.extension.demo_block::viewname — the :: separator is required. Dropping it resolves against the app, not the addon.vendor/. Composer will overwrite it. Clone/copy into addons/ and register a path repository.BlockExtension location) and in the admin UI registration. Read the composer.json constraints before assuming an older tutorial applies.form(), or hook block() to post-process data. Anything beyond that — custom front-end rendering logic, API output — belongs in your theme or a dedicated presenter, keeping the block dumb.How can I help you explore Laravel packages today?