Introducing Demac_BananaBread: Adding CMS Breadcrumbs From the Hierarchy in Magento

February 4, 2013 by Corey

Magento Enterprise Edition has some great features. Some of which are improvements to the CMS section. In the backend of Magento we can see under CMS > Pages > Manage Hierarchy a great system to manage CMS pages into a hierarchy which can be used as an organization tool. This systems lends itself to the idea that somehow on the frontend these pages will be organized in the same fashion. They are – to an extent. We can access these pages from a specific URL which will structure itself in the same structure of the hierarchy. However, the breadcrumbs on these pages are still structured like this: “Home / Current Page Name”. If we want to add our own breadcrumbs which replicates the hierarchy, we can use the method to our layout, or we can let the new module Demac_BananaBread do the work for us.

You can download the module here and follow along.

If you open up app/code/local/Demac/BananaBread/etc/config.xml you can see that we’re rewriting the Mage_Page_Block_Html_Breadcrumbs block. Our _toHtml() function is quite similar to the original, but we will check if we are in the CMS route and if we are, generate our own breadcrumbs via getCmsBreadcrumbs(). Let’s have a look at how this function works…

1. We begin by adding the “home” breadcrumb as it always comes first.

2. The hierarchy is stored in something called “nodes”. For each page in the hierarchy, another node is added. Nodes contain information regarding its level in the hierarchy, path, and associated page ID.

3. We then iterate through all nodes which are associated with our current page and take the node which has the longest path to construct the breadcrumbs

4. Once we’ve obtained our node, we want to break apart the Xpath (the path of node IDs which we will use to construct the breadcrumbs) We will use these node IDs to obtain all of the associated nodes to the current node to obtain all of their page IDs

5. We use these page IDs to get a collection of CMS pages, iterate through them, and if the page is active (not disabled) we will add it as a crumb to our protected $_crumbs array.

6. The code checks to see if the page is active. If it’s not but still in the hierarchy, don’t link to it in the breadcrumbs

7. We then add the final crumb which is the current page to the end of the breadcrumbs.

8. Finally, we return the crumbs and the parent _toHtml() function adds extra data like defining which is the first and last crumbs.

 Mage::helper('cms')->__('Home'),
                            'title' => Mage::helper('cms')->__('Go to Home Page'),
                            'link' => Mage::getBaseUrl(),
                            );

        // #2
        $hierarchyModel = Mage::getSingleton('enterprise_cms/hierarchy_node');
        $collection = $hierarchyModel
                            ->getCollection()
                            ->addFieldToFilter('page_id', $this->getHelper('cms/page')->getPage()->getPageId())
                            ;
        // First get the current CMS page's hierarchy
        // #3
        foreach ($collection as $currentNode) {
            if (!isset($node)) {
                $node = $currentNode;
                continue;
            }
            // Take the largest xpath for the current breadcrumbs
            if (count(explode('/', $currentNode->getXpath())) >= count(explode('/', $node->getXpath()))) {
                $node = $currentNode;
            }
        }

        // We may get a CMS page which actually has no nodes
        if (!isset($node)) {
            $crumbs['current_page'] = array(
                'label' => $this->getHelper('cms/page')->getPage()->getTitle(),
                'title' => $this->getHelper('cms/page')->getPage()->getTitle(),
            );
            return $crumbs;
        }

        // #4
        $hierarchy = array();
        $hierarchy['parent_nodes'] = explode('/', $node->getXpath());
        $hierarchy['level'] = $node->getLevel();
        if (isset($hierarchy['parent_nodes']) && $hierarchy['parent_nodes'] && $hierarchy['level'] > 1) {
            $nodeFilter = array();
            for ($i = 0; $i < count($hierarchy['parent_nodes']); $i++) {
                $nodeFilter[] = array('eq' => $hierarchy['parent_nodes'][$i]);
            }
            $parentNodes = $hierarchyModel
                                ->getCollection()
                                ->addFieldToFilter('node_id', $nodeFilter)
                                ;
            $pageIdFilter = array();
            foreach($parentNodes as $node) {
                $pageIdFilter[] = array('eq' => $node->getPageId());
                $pageIdAssoc[$node->getLevel()] = $node->getPageId();
            }

            // Get the pages so we can echo their title and full URL
            // #5
            $cmsPages = Mage::getSingleton('cms/page')
                            ->getCollection()
                            ->addFieldToFilter('page_id', $pageIdFilter)
                            ;
            // Make sure we're getting back the same amount of pages as we asked for
            if ($cmsPages->count() == count($pageIdAssoc)) {
                for($i = 1; $i < count($pageIdAssoc); $i++) {
                    $doNotAddPage = false;
                    // Begin putting the pages in their proper order
                    foreach($cmsPages as $page) {
                        if ($pageIdAssoc[$i] == $page->getPageId()) {
                            // #6
                            if (!$page->getIsActive()) {
                                $doNotAddPage = true;
                                break;
                            }
                            $currentPage = $page;
                            break;
                        }
                    }
                    if ($doNotAddPage) {
                        continue;
                    }

                    $crumbs[$currentPage['title']] = array(
                                                        'label' => $currentPage['title'],
                                                        'title' => $currentPage['title'],
                                                        'link' => Mage::getBaseUrl() . $currentPage['identifier'],
                                                    );
                    unset($currentPage);
                }
            }
        }

        // #7
        $crumbs['current_page'] = array(
                                    'label' => $this->getHelper('cms/page')->getPage()->getTitle(),
                                    'title' => $this->getHelper('cms/page')->getPage()->getTitle(),
                                   );

        // #8
        return $crumbs;
    }

    protected function _toHtml()
    {
        $request = $this->getRequest();
        $route = $request->getRouteName();
        if (strtolower($route) == 'cms') {
            $page = $this->getHelper('cms/page')->getPage();
            // Ripped from Mage_Cms_Block_Page in _prepareLayout() as we override their breadcrumbs with ours
            if (Mage::getStoreConfig('web/default/show_cms_breadcrumbs')
                && ($breadcrumbs = $this->getLayout()->getBlock('breadcrumbs'))
                && ($page->getIdentifier()!==Mage::getStoreConfig('web/default/cms_home_page'))
                && ($page->getIdentifier()!==Mage::getStoreConfig('web/default/cms_no_route'))) {
                    $this->_crumbs = $this->getCmsBreadcrumbs();
            }
        }
        return parent::_toHtml();
    }
}

Download the module here: Demac_BananaBread

.

About Corey

Certified Magento Developer

Read more posts by Corey