Magento 2 Theme Development Part 4

Welcome to Magento 2 Theme Development Part 4. Continuing on from development changes to our custom theme, we’ll be looking at adding a new container to the page templates.

Back to Part 3.

In Magento 1 versions, you had structural blocks that defined the structure of the page. The main blocks involved included header, footer, content, left and right.

These blocks were then rendered using $this->getChildHtml() in the page templates.

// app/design/frontend/base/default/template/page/1column.phtml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $this->getLang() ?>" lang="<?php echo $this->getLang() ?>">
<head>
<?php echo $this->getChildHtml('head') ?>
</head>
<body<?php echo $this->getBodyClass()?' class="'.$this->getBodyClass().'"':'' ?>>
<?php echo $this->getChildHtml('after_body_start') ?>
<div class="wrapper">
    <?php echo $this->getChildHtml('global_notices') ?>
    <div class="page">
        <?php echo $this->getChildHtml('header') ?>
        <div class="main-container col1-layout">
            <div class="main">
                <?php echo $this->getChildHtml('breadcrumbs') ?>
                <div class="col-main">
                    <?php echo $this->getChildHtml('global_messages') ?>
                    <?php echo $this->getChildHtml('content') ?>
                </div>
            </div>
        </div>
        <?php echo $this->getChildHtml('footer') ?>
        <?php echo $this->getChildHtml('global_cookie_notice') ?>
        <?php echo $this->getChildHtml('before_body_end') ?>
    </div>
</div>
<?php echo $this->getAbsoluteFooter() ?>
</body>
</html<

In Magento 2, these structural blocks are called containers. You can see containers being defined within the 1column.xml layout file of the Magento_Theme module.

// vendor/magento/module-theme/view/frontend/page_layout/1column.xml

<?xml version="1.0"?>
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
    <update handle="empty"/>
    <referenceContainer name="page.wrapper">
        <container name="header.container" as="header_container" label="Page Header Container" htmlTag="header" htmlClass="page-header" before="main.content"/>
        <container name="page.top" as="page_top" label="After Page Header" after="header.container"/>
        <container name="footer-container" as="footer" before="before.body.end" label="Page Footer Container" htmlTag="footer" htmlClass="page-footer"/>
    </referenceContainer>
</layout>

As you can see, containers are defined using the <container> node. If we wanted to add a container to all pages that would render before the footer container, there are a few steps we would need to take.

Firstly, open up the layout/default.xml within your custom theme directory and define a container. The container being defined should reside a page.wrapper reference (similar to how the containers are defined within the module.xml file above).

 // app/design/frontend/Siphor/custom/Magento_Theme/layout/default.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>

        ....

        <referenceContainer name="page.wrapper">
            <container name="custom.container" as="customContainer" label="Customer Container" htmlTag="div" before="footer.container" htmlClass="custom-container" />
        </referenceContainer>
    </body>
</page>

Note the before="footer.container" ensures that our custom container renders before the footer container.

Refreshing your Magento store would result in no changes to the website as the custom container does not currently contain any child blocks within it.

You can now add a <referenceContainer> node within your layout file and define a block to be rendered on the web page.

For example, we can copy the newsletter block that gets defined within the footer.

// app/design/frontend/Siphor/custom/Magento_Theme/layout/default.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>

        ....

        <referenceContainer name="page.wrapper">
            <container name="custom.container" as="someContainer" label="Some Container" htmlTag="div" before="footer.container" htmlClass="some-container" />
        </referenceContainer>

        <referenceContainer name="custom.container">
            <block class="Magento\Newsletter\Block\Subscribe" name="customcontainer.form.subscribe" as="custom_subscribe" before="-" template="subscribe.phtml"/>
        </referenceContainer>
    </body>
</page>

You should have two newsletter forms rendered on your Magento store.

Magento 2 Theme Development Part 4

The one rendered above the footer within the custom container can be styled to suit your needs.

If you want to remove the newsletter template defined in the footer, you can do so by adding a remove attribute to the form.subscribe referenceBlock. form.subscribe is the name of the block Magento gives the default newsletter block defined.

// app/design/frontend/Siphor/custom/Magento_Theme/layout/default.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        
        ....

        <referenceContainer name="page.wrapper">
            <container name="custom.container" as="someContainer" label="Some Container" htmlTag="div" before="footer.container" htmlClass="some-container" />
        </referenceContainer>

        <referenceContainer name="custom.container">
            <block class="Magento\Newsletter\Block\Subscribe" name="customcontainer.form.subscribe" as="custom_subscribe" before="-" template="subscribe.phtml"/>
        </referenceContainer>

        <referenceBlock name="form.subscribe" remove="true"/>
    </body>
</page>

Note: This article is based on Magento CE version 2.1.