Magento Render Layout

The main responsibilities of the Magento render layout method is to get the layout output, process this output and append the output to the body of the response. Let’s take a look at the method within the Mage_Core_Controller_Varien_Action class.

public function renderLayout($output='')
{
    $_profilerKey = self::PROFILER_KEY . '::' . $this->getFullActionName();

    if ($this->getFlag('', 'no-renderLayout')) {
        return;
    }

    if (Mage::app()->getFrontController()->getNoRender()) {
        return;
    }

    $this->_renderTitles();

    Varien_Profiler::start("$_profilerKey::layout_render");


    if (''!==$output) {
        $this->getLayout()->addOutputBlock($output);
    }

    Mage::dispatchEvent('controller_action_layout_render_before');
    Mage::dispatchEvent('controller_action_layout_render_before_'.$this->getFullActionName());

    #ob_implicit_flush();
    $this->getLayout()->setDirectOutput(false);

    $output = $this->getLayout()->getOutput();
    Mage::getSingleton('core/translate_inline')->processResponseBody($output);
    $this->getResponse()->appendBody($output);
    Varien_Profiler::stop("$_profilerKey::layout_render");

    return $this;
}

The first line of interest is the _renderTitles() method which sets the page title that can be added above the renderlayout() method in your controller file.

$this->loadLayout();
$this->_title("Some Test Title");
$this->renderLayout();

Within the _renderTitles() method, an if statement checks to see if the isLayoutLoaded flag is set to true and if the _titles array returns true.

If it does, we get the head block and its block class, Mage_Page_Block_Html_Head.

protected function _renderTitles()
{
    if ($this->_isLayoutLoaded && $this->_titles) {
        $titleBlock = $this->getLayout()->getBlock('head');
        if ($titleBlock) {
            if (!$this->_removeDefaultTitle) {
                $title = trim($titleBlock->getTitle());
                if ($title) {
                    array_unshift($this->_titles, $title);
                }
            }
            $titleBlock->setTitle(implode(' / ', array_reverse($this->_titles)));
        }
    }
}

The setTitle() method belongs in Mage_Page_Block_Html_Head, and it is here where the title is stored in a $this->_data array.

The next line to look at here is $this->getLayout()->getOutput().

The getOutput() method fetches the _output array that was generated from the loadLayout() method. See the Magento Load Layout article for more information.

public function getOutput()
{
    $out = '';
    if (!empty($this->_output)) {
        foreach ($this->_output as $callback) {
            $out .= $this->getBlock($callback[0])->$callback[1]();
        }
    }

    return $out;
}

If you’re creating a custom module and are just including the loadLayout() and renderLayout() methods within your controller’s action method, your array will probably look like this.

Array ( [root] => Array ( [0] => root [1] => toHtml ) [core_profiler] => Array ( [0] => core_profiler [1] => toHtml ) )

This output comes from the root and core_profiler blocks within the page.xml layout file. Both of these block contain the toHtml value in their output attributes and hence were added to the _output array within the loadLayout() method.

So for each output block we get the block class and execute the output attribute value e.g. toHtml. The toHtml() method exists in the Mage_Core_Block_Abstract class.

We then reach the following line.

Mage::getSingleton('core/translate_inline')->processResponseBody($output);
public function processResponseBody(&$body)
{
    if (!$this->isAllowed()) {
        if (Mage::getDesign()->getArea() == 'adminhtml') {
            $this->stripInlineTranslations($body);
        }
        return $this;
    }

    if (is_array($body)) {
        foreach ($body as &$part) {
            $this->processResponseBody($part);
        }
    } else if (is_string($body)) {
        $this->_content = $body;

        $this->_specialTags();
        $this->_tagAttributes();
        $this->_otherText();
        $this->_insertInlineScriptsHtml();

        $body = $this->_content;
    }

    return $this;
}

This method checks if inline translations are enabled for the frontend or admin area. If they are then we proceed to add the inline html and other inline scripts as part of the body content. If inline translations are not enabled then we simple return out of the method.

The isAllowed() method is responsible for checking if inline translations are enabled.

public function isAllowed($store = null)
{
    if (is_null($store)) {
        $store = Mage::app()->getStore();
    }
    if (!$store instanceof Mage_Core_Model_Store) {
        $store = Mage::app()->getStore($store);
    }

    if (is_null($this->_isAllowed)) {
        if (Mage::getDesign()->getArea() == 'adminhtml') {
            $active = Mage::getStoreConfigFlag('dev/translate_inline/active_admin', $store);
        } else {
            $active = Mage::getStoreConfigFlag('dev/translate_inline/active', $store);
        }

        $this->_isAllowed = $active && Mage::helper('core')->isDevAllowed($store);
    }

    /* @var $translate Mage_Core_Model_Translate */
    $translate = Mage::getSingleton('core/translate');

    return $translate->getTranslateInline() && $this->_isAllowed;
}

Lastly, the appendBody() method is called, and appends the content of the body to the response.

public function appendBody($content, $name = null)
{
    if ((null === $name) || !is_string($name)) {
        if (isset($this->_body['default'])) {
            $this->_body['default'] .= (string) $content;
        } else {
            return $this->append('default', $content);
        }
    } elseif (isset($this->_body[$name])) {
        $this->_body[$name] .= (string) $content;
    } else {
        return $this->append($name, $content);
    }

    return $this;
}

Note: This article is based on Magento Community/Open Source version 1.9.