Categories


Archives


Recent Posts


Categories


Magento 2: Adding Frontend Asset Files Programmatically

astorm

Frustrated by Magento? Then you’ll love Commerce Bug, the must have debugging extension for anyone using Magento. Whether you’re just starting out or you’re a seasoned pro, Commerce Bug will save you and your team hours everyday. Grab a copy and start working with Magento instead of against it.

Updated for Magento 2! No Frills Magento Layout is the only Magento front end book you'll ever need. Get your copy today!

These methods aren’t, as of 2.01, marked as @api safe so they may go away. That said, they’re pretty integral to how the layout works so I feel like they have a good shot of sticking around.

If you want to add a frontend asset to your page layout programmatically and not render the <link/>/<script/> tags yourself, you’ll want to use the asset repository and the asset grouped collection

MagentoFrameworkViewAssetRepository $assetRepository
MagentoFrameworkViewAssetGroupedCollection $assetCollection

Specifically, use the asset repository to create an asset

$identifier = 'css/somefile.css';
$asset      = $assetRepository->createAsset($identifier)    

and then add the asset to the grouped collection

$assetCollection->add($asset);

Unfortunately, you can’t use this technique from a block’s _prepareLayout statement. Magento 2 renders a page in the following method

#File: vendor/magento/framework/View/Result/Page.php 
protected function render(ResponseInterface $response)
{
    $this->pageConfig->publicBuild();
    if ($this->getPageLayout()) {
        $config = $this->getConfig();
        $this->addDefaultBodyClasses();
        $addBlock = $this->getLayout()->getBlock('head.additional'); // todo
        $requireJs = $this->getLayout()->getBlock('require.js');
        $this->assign([
            'requireJs' => $requireJs ? $requireJs->toHtml() : null,
            'headContent' => $this->pageConfigRenderer->renderHeadContent(),
            'headAdditional' => $addBlock ? $addBlock->toHtml() : null,
            'htmlAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_HTML),
            'headAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_HEAD),
            'bodyAttributes' => $this->pageConfigRenderer->renderElementAttributes($config::ELEMENT_TYPE_BODY),
            'loaderIcon' => $this->getViewFileUrl('images/loader-2.gif'),
        ]);

        $output = $this->getLayout()->getOutput();
        $this->assign('layoutContent', $output);
        $output = $this->renderPage();
        $this->translateInline->processResponseBody($output);
        $response->appendBody($output);
    } else {
        parent::render($response);
    }
    return $this;
}       

The frontend assets are rendered by the following method call

$this->pageConfigRenderer->renderHeadContent()    

However, block rendering (and _prepareLayout) doesn’t happen until this method call

$output = $this->getLayout()->getOutput();    

So any thoughts of creating blocks that carry their frontend assets with them is out the window.

Copyright © Alan Storm 1975 – 2019 All Rights Reserved

Originally Posted: 21st January 2016