The nolocal theming and packaging methodology

So this will cause ultimate uproar and go against the grain of every Magento developer - but we've got a solid process for theming - that does not use local.xml (more on that later).

We always work off the base/default template - but zero out the CSS. Even though all designs don't particularly lend themselves to the structural layout of a vanilla Magento store - we find it good practice to use the default theme as a starting point; we can remove un-used methods/loops/divs etc. as necessary during the templating.

When starting a theme

For EE

We install this extension first, so that we get a level of theme fallback - when we later remove the theme files we copied.

The package

We first start by creating the package and copying in the entire base/default theme; so for example (say it was our own website, we'd call the package sonassi)

cd ./app/design/frontend
mkdir sonassi
cp -par base/default sonassi/default
mkdir sonassi/default/layout/custom

The template

The ultimate goal is that we don't have to keep copy and pasting each file that we modify whenever we need to, we just edit the file in the theme.

But each time we edit the file, we strip out the Magento Commerce headers - and add an appropriate header/identifier to mark the file as being a custom template, usually something like ...

* @category    Template
* @package     sonassi_default
* @copyright   Copyright (c) 2013 Sonassi

This header serves a purpose later when we do the final template clean-up. As we will do a recursive diff on the base/default/template directory and the sonassi/default/template directory - then delete anything that hasn't been changed.

This way, only the modified files remain and the overall package has been reduced to the minimum changed files.

The layout files

We use a standard core module of our own sonassi.core. Yes, we always prefix the module namespace with a unique identifier - it stops conflicts where other companies have picked the same name (eg. fishpig/wordpress and sonassi/wordpress)

The nolocal layout methodology


Then the two magic classes that add the functionality to never need local.xml again,

class Sonassi_Core_Model_Core_Layout 
    extends Mage_Core_Model_Layout
     * Loyout xml generation
     * @return Mage_Core_Model_Layout
    public function generateXml()
        $xml = $this->getUpdate()->asSimplexml();
        $removeInstructions = $xml->xpath("//remove");
        if (is_array($removeInstructions)) {
            foreach ($removeInstructions as $infoNode) {
                $attributes = $infoNode->attributes();
                $blockName = (string)$attributes->name;
                if ($blockName) {
                    $unremoveNodes = $xml->xpath("//unremove[@name='".$blockName."']");
                    if (is_array($unremoveNodes) && count($unremoveNodes) > 0) {
                    $ignoreNodes = $xml->xpath("//block[@name='".$blockName."']");
                    if (!is_array($ignoreNodes)) {
                    $ignoreReferences = $xml->xpath("//reference[@name='".$blockName."']");
                    if (is_array($ignoreReferences)) {
                        $ignoreNodes = array_merge($ignoreNodes, $ignoreReferences);

                    foreach ($ignoreNodes as $block) {
                        if ($block->getAttribute('ignore') !== null) {
                        $acl = (string)$attributes->acl;
                        if ($acl && Mage::getSingleton('admin/session')->isAllowed($acl)) {
                        if (!isset($block->attributes()->ignore)) {
                            $block->addAttribute('ignore', true);
        return $this;


class Sonassi_Core_Model_Core_Layout_Update 
    extends Mage_Core_Model_Layout_Update

    public function getFileLayoutUpdatesXml($area, $package, $theme, $storeId = null)
        if (null === $storeId) {
            $storeId = Mage::app()->getStore()->getId();
        /* @var $design Mage_Core_Model_Design_Package */
        $design = Mage::getSingleton('core/design_package');
        $layoutXml = null;
        $elementClass = $this->getElementClass();
        $updatesRoot = Mage::app()->getConfig()->getNode($area.'/layout/updates');
        Mage::dispatchEvent('core_layout_update_updates_get_after', array('updates' => $updatesRoot));
        $updateFiles = array();
        foreach ($updatesRoot->children() as $updateNode) {
            if ($updateNode->file) {
                $module = $updateNode->getAttribute('module');
                if ($module && Mage::getStoreConfigFlag('advanced/modules_disable_output/' . $module, $storeId)) {
                $updateFiles[] = (string)$updateNode->file;

                // custom theme XML contents
                $updateFiles[] = 'custom/'.(string)$updateNode->file;    

                // custom theme XML override
                $updateFiles[] = 'local/'.(string)$updateNode->file;            

        // custom local layout updates file - load always last
        $updateFiles[] = 'local.xml';
        $layoutStr = '';
        foreach ($updateFiles as $file) {
            $filename = $design->getLayoutFilename($file, array(
                '_area'    => $area,
                '_package' => $package,
                '_theme'   => $theme
            if (!is_readable($filename)) {
            $fileStr = file_get_contents($filename);
            $fileStr = str_replace($this->_subst['from'], $this->_subst['to'], $fileStr);
            $fileXml = simplexml_load_string($fileStr, $elementClass);
            if (!$fileXml instanceof SimpleXMLElement) {
            $layoutStr .= $fileXml->innerXml();
        $layoutXml = simplexml_load_string('<layouts>'.$layoutStr.'</layouts>', $elementClass);
        return $layoutXml;


The two above classes add the functionality into Magento so that you can extend - but not overwrite a layout XML file. Extensibility of the layout XML is important for us, as it allows us to still maintain the same file separation catalog.xml, cms.xml etc. - but only need to add short portions of layout XML to manipulate blocks (insert/clone/remove).

The local.xml methodology is that you just enter your overriding changes into one cumbersome unmanageable file.

The nolocal methodology means that rather than putting all changes in a single file, you put them in a file with the appropriate filename that it is modifying (eg. catalog.xml) - by simply creating a new file sonassi/default/layout/custom/catalog.xml - with *only the modifications.

Again, once we're done making the template, we can just remove the contents of sonassi/default/layout with the exception of the custom directory. This way again, like with the template, we have a lightweight extended template - based off the base templates.

The style sheets

We delete them, all of them. We don't bother copying them into our package's CSS directory. We'll copy in the JS and that is it - the images and CSS directory will be empty from the start.

As we're using SASS nowadays, we'll have another directory (scss) for the pre-processed CSS - and output to the main styles/print CSS file(s).

Cleaning up the template

So as we mentioned, once the template theme is completed, you can now clean it up - to remove the un-modified files and reduce it down to the bare minimum.

cd ./app/design/frontend

diff -BPqr "base/default/template" "$THEME/template" | 
awk '{print $4}' | 
  while read FILE; do 
    DIR=$(dirname "$FILE")
    [ -d "$PREFIX$DIR" ] || mkdir -p "$PREFIX$DIR"
    [ -f "$PREFIX$FILE" ] || cp -pa "$FILE" "$PREFIX$FILE"
cp -par "$THEME/layout" "$PREFIX$THEME/"
  • Peter Svegrup

    Morning Ben,

    I'm not at all fully versed in the backend dev of magento so I just wanted to ask something on the nolocal way; where in the process of building a page is local.xml called in to notify the systems of any chqanges? I just read in the Magento Design guide that the fallback hierarchy puts local.xml after calling templates and skln which means that if there is a local.xml with changes, the system would have to reiterate over templates and skin to output the page. If this is so, where does that put your method in the hierarchy?

    I would love to test your method but just from reading your post I'm not sure I'm able to put together the module for it. Any chance you could extend your article to include some more pointers on how the module is built and what methods are available and how they are used (insert, clone, remove)?

    Thanks in general for an inspiring blog!


    • sonassi

      Hi Peter,

      The module need only consist of those 2 classes and a `config.xml`. Building your own module in Magento is going to be something you need to learn if you plan on working on a Magento store.

      In terms of hierarchy, it goes

      base/default > your_package/default > your_package/your_theme > your_package/your_theme/custom (this module) > your_package/your_theme/local.xml

      • Peter Svegrup

        Thanks for the pointers and thanks for the push 🙂 ... I have worked with quite a few shops already but coming from an amateur frontend background directly into Magento world and being the sole person in the ecommerce section at the office, there is just such a plethora of things to learn that I have just not gotten completely under the skin of it yet, but I sure will!

        Just so I understood the hierachy correctly; all xml files, including local.xml, are gone through before going after the templates and skin files?

        Have a great weekend!

        • sonassi