corrivate / magento2-layout-bricks

corrivate/magento2-layout-bricks

Use layout bricks in Magento, inspired by Laravel anonymous Blade components

  • Lau Bannenberg
magento2-module Compatibility: 2.4.7-2.4.9 Code Quality: Fail Tests: N/A Security: Pass MIT

Are you the maintainer of corrivate?

Packagento pulls corrivate's Composer packages from the public registry so buyers can find them here.

Claim the namespace to take ownership, publish new releases directly, and start charging for premium versions.

Claim this namespace →

Layout Bricks for Magento

Latest Version on Packagist
MIT Licensed

All in all you're just another brick in the layout

composer require corrivate/magento2-layout-bricks

Modern frontend frameworks embrace reusable components, like buttons, input fields, and cards. And they style them with utility CSS like Tailwind. It's fine to pile a dozen classes on that primary button, because you only have to build it once.

Magento doesn't come with this out of the box. Many templates are huge and if you talk about UI components people make the sign of the cross XML at you.

This package is a way to make things better. To use small anonymous components without hassle. It's heavily inspired by Laravel's anonymous blade components. In Magento, our unit of frontend template is a block. An anonymous block is a brick.

An example phtml template

<?php declare(strict_types=1);
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Corrivate\LayoutBricks\Model\Mason $mason */
?>

<form method="post" action="/newsletter/subscribe">
<?= $mason('cms.block', props: ['block_id' => 'newsletter-explanation']) ?>

<?= $mason('ExampleCorp_ExampleModule::theme/input/text.phtml', [
    'required', 
    'class' => 'rounded-md text-stone-800 bg-stone-100', 
    'placeholder' => '[email protected]'
]) ?>

<?= $mason('btn-primary', attributes: ['type' => 'submit'], props: ['label' => __('Save')]) ?>
</form>

How does it work?

The $mason object is globally injected into every .phtml template. It has just one method, __invoke(), to cause it to output as a string a fully rendered child block. So it's essentially a compact, ergonomic way of doing this:

<?= $block
    ->getLayout()
    ->createBlock(\Magento\Framework\View\Element\Template::class)
    ->setTemplate($template) 
?>

This is already nice, because we are now still using Magento's templating engine:

  • We can call small templates without using a ton of boilerplate. It's now realistic to make a template for something as small as a single button. So we can re-use the same button look and feel throughout the entire website. This is really helpful if the button actually has a LOT of utility CSS classes. Hi Tailwind.
  • We can make a library of base components as a reusable module.
  • We still have the opportunity to use Magento's theme overrides. We can change the way buttons look in a website or single store. But because we're re-using the button template everywhere, we can change it in one place and have the change happen everywhere.

But there's more:

  • You can set default HTML attributes (such as classes) on a component, and inject additional ones based on the context. They will be merged, with new properties overriding default ones.
  • You can inject props into a component, supplying them with data.

For example, consider the cms.block brick:

<?= $mason('cms.block', 
        attributes: ['class' => 'border-2 border-stone-400 rounded-lg'], 
        props: ['block_id' => 'text-block']) 
?>

This will render the CMS block with ID 'text-block', but surround it in a div with a gray round border.

Aliases

Aliases in detail

You can place bricks in two ways:

  • Fully cite the Magento template path:
<?= $mason('Corrivate_LayoutBricks::cms/block.phtml', props: ['block_id' => 'test-block']) ?>
  • Create an alias for it, so you can refer to it more shortly:
<?= $mason('cms.block', props: ['block_id' => 'test-block']) ?>

Aliases in detail

Attributes

Attributes in detail

The $mason objects invoke method accepts an array of attributes. For example:

<?= $mason('input.text', attributes: [
    'required', 
    'disabled' => false, 
    'class' => 'text-black', 
    'placeholder' => 'your input please', 
    'name' => 'user_comment'
]) ?>

In the brick template, this will be available as a BrickAttributesBag which could for example have the following default attributes/values:

<input <?= $attributes->default([
    'class' => 
    'bg-white', 
    'disabled' => true, 
    'type' => 'text'
]) ?> />

This would result in the following HTML after the defaults and your custom input is merged:

<input class="bg-white text-black" 
       type="text" 
       required 
       placeholder="your input please" 
       name="user_comment"/>

Attributes in detail

Props

Props in detail

Props are used to pass data to the brick. For example, if you were making a brick to render a "product card", you'd pass the product that needs to be displayed:

<?= $mason('product-cart', props: ['product' => $product]) ?>

In the brick template, the props are available through the $props variable, which is automatically present:

<?php declare(strict_types=1);
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Corrivate\LayoutBricks\Model\BrickAttributesBag $attributes */
/** @var \Corrivate\LayoutBricks\Model\BrickPropsBag $props */
?>

<div class="border-2 border-color-stone-600 rounded-md">
    <?= $props['product']->getSku() ?>
</div>

The $props variable is not an array, but it implements ArrayAccess to give access to its contents.

The $props variable also has a $props->default([]) method so you can supply default (scalar) props. You can always override those default from the parent template.

The $props object also has a $props->expect([]) method which allows you to specify expected props and their data types so you can opt into greater type safety.

Props in detail

Escaper

Using $escaper to filter raw output of data from the DB or user input is important to protect against various attacks. Official documentation about this.

However, the output from $mason() is the output of another block that already produces HTML. So the call to $mason() should NOT be escaped, but inside the PHTML template implementing your brick, you should use it normally.

Empty PHTML brick template

Just copy paste this into a file and start designing:

<?php declare(strict_types=1);
/** @var \Magento\Framework\View\Element\Template $block */
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Corrivate\LayoutBricks\Model\BrickAttributesBag $attributes */
/** @var \Corrivate\LayoutBricks\Model\BrickPropsBag $props */

// For Hyva users:
/** @var \Hyva\Theme\Model\ViewModelRegistry $viewModels */

$props->default([
    // you can supply default scalar values for your props
])->expect([
    // specify propName => type for your props
]);
?>


<div <?= $attributes->default(['class' => '']) ?>>

</div>

Corrivate

(en.wiktionary.org)

Etymology

From Latin corrivatus, past participle of corrivare ("to corrivate").

Verb

corrivate (third-person singular simple present corrivates, present participle corrivating, simple past and past participle corrivated)

(obsolete) To cause to flow together, as water drawn from several streams.

CHANGELOG

0.1.3

Fixed

typo

0.1.2

Added

  • PHP 8.4 and 8.5 support
Versions
Version Stability QA Status Compatibility Released
0.1.3 stable Fail Magento 2.4.7-2.4.9 Details 2026-07-01 13:59:01
0.1.2 stable Not tested Not yet tested Details 2026-07-01 13:57:26
v0.1.1 stable Not tested Not yet tested Details 2024-09-18 14:39:26
v0.1.0 stable Not tested Not yet tested Details 2024-09-15 22:15:53
v0.0.3 stable Not tested Not yet tested Details 2024-09-15 22:15:53
v0.0.2 stable Not tested Not yet tested Details 2024-09-14 20:19:27
v0.0.1 stable Not tested Not yet tested Details 2024-09-12 05:55:59

Requires 3

Package Constraint
magento/framework *
magento/module-cms *
php ~7.4.0||~8.0.0||~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0

Requires-dev 3

Package Constraint
bitexpert/phpstan-magento ^0.32.0
phpstan/extension-installer ^1.4
phpstan/phpstan ^1.12

Compatibility

Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.

Compatibility matrix (Magento × PHP)
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Pass Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Code Quality

Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge. A phpcs finding can't make a module incompatible.

Static analysis

Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.

Static analysis results
Tool Status Findings Summary
PHPCS Fail 82 4 errors, 78 warnings (ruleset: Magento2), 22 auto-fixable with phpcbf
PHPMD Warning 5 5 rule violations (UnusedPrivateField:5)
Cpd Pass 0
Composer validate Info 3 valid; 3 advisory notes (composer validate --strict)

PHPStan

Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases.

PHPStan results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 Pass Pass
2.4.8 Pass Pass
2.4.9 Pass Pass

Tests

Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.

Unit tests

Unit tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Integration tests

Integration tests results by Magento and PHP version
Magento PHP 8.2 PHP 8.3 PHP 8.4 PHP 8.5
2.4.7 N/A N/A
2.4.8 N/A N/A
2.4.9 N/A N/A

Security

Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.

Security results
Tool Status Findings Summary
Composer audit Pass 0
Malware scan Pass 0
License
MIT
Authors

More from corrivate

View vendor
Make it pay

Turn an existing module into recurring revenue.

If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.