I would like to rewrite a block in a 3rd party module and have tried creating my own module to achieve this with class rewrites.
My module is called Creed_CustomMenu and the module name of the module whose block I am trying to rewrite is called Wp_CustomMenu.
I thought I had it coded corectly but when I place a break point on PatentStorm on my class none it doesn't break in my class rewrite and none of my changes take effect.
Here is my Code for the Creed_CustomMenu module
app/etc/modules/Creed_CustomMenu.xml
<?xml version="1.0"?>
<config>
<modules>
<Creed_CustomMenu>
<active>true</active>
<codePool>local</codePool>
<depends>
<WP_CustomMenu />
</depends>
</Creed_CustomMenu>
</modules>
</config>
app/code/local/Creed/CustomMenu/etc/config.xml
<config>
<modules>
<Creed_CustomMenu>
<version>0.1.0</version>
</Creed_CustomMenu>
</modules>
<global>
<blocks>
<custommenu>
<rewrite>
<navigation>Creed_CustomMenu_Block_Navigation</navigation>
</rewrite>
</custommenu>
</blocks>
</global>
</config>
app/code/local/Creed/CustomMenu/Block/Navigation.php
<?php
class Creed_CustomMenu_Block_Navigation extends WP_CustomMenu_Block_Navigation
{
public function drawCustomMenuItem($category, $level = 0, $last = false)
{
if (!$category->getIsActive()) return '';
$html = array();
$id = $category->getId();
// --- Static Block ---
$blockId = sprintf(self::CUSTOM_BLOCK_TEMPLATE, $id); // --- static block key
#Mage::log($blockId);
$collection = Mage::getModel('cms/block')->getCollection()
->addFieldToFilter('identifier', array('like' => $blockId . '%'))
->addFieldToFilter('is_active', 1);
$blockId = $collection->getFirstItem()->getIdentifier();
#Mage::log($blockId);
$blockHtml = $this->getLayout()->createBlock('cms/block')->setBlockId($blockId)->toHtml();
// --- Sub Categories ---
$activeChildren = $this->_getActiveChildren($category, $level);
// --- class for active category ---
$active = ''; if ($this->isCategoryActive($category)) $active = ' act';
// --- Popup functions for show ---
$wideBlock = false; // CB: added new condition for setting extra wide static blocks
if (strpos($blockId,'wide') !== false) {
$wideBlock = true;
}
$drawPopup = ($blockHtml || count($activeChildren));
if ($drawPopup) {
$html[] = '<div id="menu' . $id . '" class="menu' . $active . '" onmouseover="wpShowMenuPopup(this, event, \'popup' . $id . '\');" onmouseout="wpHideMenuPopup(this, event, \'popup' . $id . '\', \'menu' . $id . '\')">';
} else {
$html[] = '<div id="menu' . $id . '" class="menu' . $active . '">';
}
// --- Top Menu Item ---
$html[] = '<div class="parentMenu">';
if ($level == 0 && $drawPopup) {
$html[] = '<a href="javascript:void(0);" rel="'.$this->getCategoryUrl($category).'">';
} else {
$html[] = '<a href="'.$this->getCategoryUrl($category).'">';
}
$name = $this->escapeHtml($category->getName());
if (Mage::getStoreConfig('custom_menu/general/non_breaking_space')) {
$name = str_replace(' ', ' ', $name);
}
$html[] = '<span>' . $name . '</span>';
$html[] = '</a>';
$html[] = '</div>';
$html[] = '</div>';
// --- Add Popup block (hidden) ---
if ($drawPopup) {
// --- Popup function for hide ---
$html[] = '<div id="popup' . $id . '" class="wp-custom-menu-popup" onmouseout="wpHideMenuPopup(this, event, \'popup' . $id . '\', \'menu' . $id . '\')" onmouseover="wpPopupOver(this, event, \'popup' . $id . '\', \'menu' . $id . '\')">';
// --- draw Sub Categories ---
if ($blockHtml)
{
if (count($activeChildren))
{
if ($wideBlock) {
$html[] = '<div class="block1 grid12-2">';
} else{
$html[] = '<div class="block1 grid12-7">';
}
$html[] = $this->drawColumns($activeChildren);
$html[] = '<div class="clearBoth"></div>';
$html[] = '</div>';
}
// --- draw Custom User Block ---
if ($wideBlock) {
$html[] = '<div id="' . $blockId . '" class="block2 grid12-10">';
} else{
$html[] = '<div id="' . $blockId . '" class="block2 grid12-5">';
}
$html[] = $blockHtml;
$html[] = '</div>';
}
else
if (count($activeChildren)) {
$html[] = '<div class="block1 grid-full">';
$html[] = $this->drawColumns($activeChildren);
$html[] = '<div class="clearBoth"></div>';
$html[] = '</div>';
}
$html[] = '</div>';
}
$html = implode("\n", $html);
return $html;
}
}
And here is my Code for the WP_CustomMenu module I'm trying to rewrite app/code/local/WP/CustomMenu/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<WP_CustomMenu>
<version>2.4.0</version>
</WP_CustomMenu>
</modules>
<frontend>
<layout>
<updates>
<custommenu>
<file>webandpeople/custommenu.xml</file>
</custommenu>
</updates>
</layout>
</frontend>
<adminhtml>
<acl>
<resources>
<all>
<title>Allow Everything</title>
</all>
<admin>
<children>
<system>
<children>
<config>
<children>
<custom_menu translate="title" module="custommenu">
<title><![CDATA[Web & People: Custom Menu]]></title>
<sort_order>2000</sort_order>
</custom_menu>
</children>
</config>
</children>
</system>
</children>
</admin>
</resources>
</acl>
</adminhtml>
<global>
<blocks>
<catalog>
<rewrite>
<navigation>WP_CustomMenu_Block_Navigation</navigation>
<!-- v1.4-1.6 -->
</rewrite>
</catalog>
<page>
<rewrite>
<html_topmenu>WP_CustomMenu_Block_Topmenu</html_topmenu>
<!-- v1.7 -->
</rewrite>
</page>
<custommenu>
<class>WP_CustomMenu_Block</class>
</custommenu>
</blocks>
<helpers>
<custommenu>
<class>WP_CustomMenu_Helper</class>
</custommenu>
</helpers>
</global>
<default>
<custom_menu>
<general>
<enabled>1</enabled>
<display_empty_categories>1</display_empty_categories>
<max_level>3</max_level>
<show_home_link>1</show_home_link>
<non_breaking_space>0</non_breaking_space>
<ie6_ignore>1</ie6_ignore>
<rtl>0</rtl>
<version>2.4.0</version>
</general>
<columns>
<count>3</count>
<divided_horizontally>0</divided_horizontally>
<integrate>1</integrate>
</columns>
<popup>
<width>0</width>
<top_offset>0</top_offset>
<delay_displaying>0</delay_displaying>
<delay_hiding>0</delay_hiding>
</popup>
</custom_menu>
</default>
<adminhtml>
<acl>
<resources>
<admin>
<children>
<system>
<children>
<config>
<children>
<about_webandpeople translate="title" module="custommenu">
<title><![CDATA[Web & People: About Us]]></title>
<sort_order>1000</sort_order>
</about_webandpeople>
</children>
</config>
</children>
</system>
</children>
</admin>
</resources>
</acl>
</adminhtml>
</config>
app/code/local/WP/CustomMenu/Block/Navigation.php
<?php
class WP_CustomMenu_Block_Navigation extends Mage_Catalog_Block_Navigation { const CUSTOM_BLOCK_TEMPLATE = "wp_custom_menu_%d";
private $_productsCount = null;
public function showHomeLink()
{
return Mage::getStoreConfig('custom_menu/general/show_home_link');
}
public function drawCustomMenuItem($category, $level = 0, $last = false)
{
if (!$category->getIsActive()) return '';
$html = array();
$id = $category->getId();
// --- Static Block ---
$blockId = sprintf(self::CUSTOM_BLOCK_TEMPLATE, $id); // --- static block key
#Mage::log($blockId);
$collection = Mage::getModel('cms/block')->getCollection()
->addFieldToFilter('identifier', array('like' => $blockId . '%'))
->addFieldToFilter('is_active', 1);
$blockId = $collection->getFirstItem()->getIdentifier();
#Mage::log($blockId);
$blockHtml = $this->getLayout()->createBlock('cms/block')->setBlockId($blockId)->toHtml();
// --- Sub Categories ---
$activeChildren = $this->_getActiveChildren($category, $level);
// --- class for active category ---
$active = ''; if ($this->isCategoryActive($category)) $active = ' act';
// --- Popup functions for show ---
$drawPopup = ($blockHtml || count($activeChildren));
if ($drawPopup) {
$html[] = '<div id="menu' . $id . '" class="menu' . $active . '" onmouseover="wpShowMenuPopup(this, event, \'popup' . $id . '\');" onmouseout="wpHideMenuPopup(this, event, \'popup' . $id . '\', \'menu' . $id . '\')">';
} else {
$html[] = '<div id="menu' . $id . '" class="menu' . $active . '">';
}
// --- Top Menu Item ---
$html[] = '<div class="parentMenu">';
if ($level == 0 && $drawPopup) {
$html[] = '<a href="javascript:void(0);" rel="'.$this->getCategoryUrl($category).'">';
} else {
$html[] = '<a href="'.$this->getCategoryUrl($category).'">';
}
$name = $this->escapeHtml($category->getName());
if (Mage::getStoreConfig('custom_menu/general/non_breaking_space')) {
$name = str_replace(' ', ' ', $name);
}
$html[] = '<span>' . $name . '</span>';
$html[] = '</a>';
$html[] = '</div>';
$html[] = '</div>';
// --- Add Popup block (hidden) ---
if ($drawPopup) {
// --- Popup function for hide ---
$html[] = '<div id="popup' . $id . '" class="wp-custom-menu-popup" onmouseout="wpHideMenuPopup(this, event, \'popup' . $id . '\', \'menu' . $id . '\')" onmouseover="wpPopupOver(this, event, \'popup' . $id . '\', \'menu' . $id . '\')">';
// --- draw Sub Categories ---
if ($blockHtml)
{
if (count($activeChildren))
{
$html[] = '<div class="block1 grid12-7">';
$html[] = $this->drawColumns($activeChildren);
$html[] = '<div class="clearBoth"></div>';
$html[] = '</div>';
}
// --- draw Custom User Block ---
$html[] = '<div id="' . $blockId . '" class="block2 grid12-5">';
$html[] = $blockHtml;
$html[] = '</div>';
}
else
if (count($activeChildren)) {
$html[] = '<div class="block1 grid-full">';
$html[] = $this->drawColumns($activeChildren);
$html[] = '<div class="clearBoth"></div>';
$html[] = '</div>';
}
$html[] = '</div>';
}
$html = implode("\n", $html);
return $html;
}
public function drawMenuItem($children, $level = 1)
{
$html = '<div class="itemMenu level' . $level . '">';
$keyCurrent = $this->getCurrentCategory()->getId();
foreach ($children as $child)
{
if (is_object($child) && $child->getIsActive())
{
// --- class for active category ---
$active = '';
if ($this->isCategoryActive($child))
{
$active = ' actParent';
if ($child->getId() == $keyCurrent) $active = ' act';
}
// --- format category name ---
$name = $this->escapeHtml($child->getName());
if (Mage::getStoreConfig('custom_menu/general/non_breaking_space'))
$name = str_replace(' ', ' ', $name);
$html.= '<a class="itemMenuName level' . $level . $active . '" href="' . $this->getCategoryUrl($child) . '"><span>' . $name . '</span></a>';
$activeChildren = $this->_getActiveChildren($child, $level);
if (count($activeChildren) > 0)
{
$html.= '<div class="itemSubMenu level' . $level . '">';
$html.= $this->drawMenuItem($activeChildren, $level + 1);
$html.= '</div>';
}
}
}
$html.= '</div>';
return $html;
}
public function drawColumns($children)
{
$html = '';
// --- explode by columns ---
$columns = (int)Mage::getStoreConfig('custom_menu/columns/count');
if ($columns < 1) $columns = 1;
$chunks = $this->_explodeByColumns($children, $columns);
// --- draw columns ---
$lastColumnNumber = count($chunks);
$i = 1;
foreach ($chunks as $key => $value)
{
if (!count($value)) continue;
$class = '';
if ($i == 1) $class.= ' first';
if ($i == $lastColumnNumber) $class.= ' last';
if ($i % 2) $class.= ' odd'; else $class.= ' even';
$html.= '<div class="column' . $class . '">';
$html.= $this->drawMenuItem($value, 1);
$html.= '</div>';
$i++;
}
return $html;
}
protected function _getActiveChildren($parent, $level)
{
$activeChildren = array();
// --- check level ---
$maxLevel = (int)Mage::getStoreConfig('custom_menu/general/max_level');
if ($maxLevel > 0)
{
if ($level >= ($maxLevel - 1)) return $activeChildren;
}
// --- / check level ---
if (Mage::helper('catalog/category_flat')->isEnabled())
{
$children = $parent->getChildrenNodes();
$childrenCount = count($children);
}
else
{
$children = $parent->getChildren();
$childrenCount = $children->count();
}
$hasChildren = $children && $childrenCount;
if ($hasChildren)
{
foreach ($children as $child)
{
if ($this->_isCategoryDisplayed($child))
{
array_push($activeChildren, $child);
}
}
}
return $activeChildren;
}
private function _isCategoryDisplayed(&$child)
{
if (!$child->getIsActive()) return false;
// === check products count ===
// --- get collection info ---
if (!Mage::getStoreConfig('custom_menu/general/display_empty_categories'))
{
$data = $this->_getProductsCountData();
// --- check by id ---
$id = $child->getId();
#Mage::log($id); Mage::log($data);
if (!isset($data[$id]) || !$data[$id]['product_count']) return false;
}
// === / check products count ===
return true;
}
private function _getProductsCountData()
{
if (is_null($this->_productsCount))
{
$collection = Mage::getModel('catalog/category')->getCollection();
$storeId = Mage::app()->getStore()->getId();
/* @var $collection Mage_Catalog_Model_Resource_Eav_Mysql4_Category_Collection */
$collection->addAttributeToSelect('name')
->addAttributeToSelect('is_active')
->setProductStoreId($storeId)
->setLoadProductCount(true)
->setStoreId($storeId);
$productsCount = array();
foreach($collection as $cat)
{
$productsCount[$cat->getId()] = array(
'name' => $cat->getName(),
'product_count' => $cat->getProductCount(),
);
}
#Mage::log($productsCount);
$this->_productsCount = $productsCount;
}
return $this->_productsCount;
}
private function _explodeByColumns($target, $num)
{
if ((int)Mage::getStoreConfig('custom_menu/columns/divided_horizontally')) {
$target = self::_explodeArrayByColumnsHorisontal($target, $num);
} else {
$target = self::_explodeArrayByColumnsVertical($target, $num);
}
#return $target;
if ((int)Mage::getStoreConfig('custom_menu/columns/integrate') && count($target))
{
// --- combine consistently numerically small column ---
// --- 1. calc length of each column ---
$max = 0; $columnsLength = array();
foreach ($target as $key => $child)
{
$count = 0;
$this->_countChild($child, 1, $count);
if ($max < $count) $max = $count;
$columnsLength[$key] = $count;
}
// --- 2. merge small columns with next ---
$xColumns = array(); $column = array(); $cnt = 0;
$xColumnsLength = array(); $k = 0;
foreach ($columnsLength as $key => $count)
{
$cnt+= $count;
if ($cnt > $max && count($column))
{
$xColumns[$k] = $column;
$xColumnsLength[$k] = $cnt - $count;
$k++; $column = array(); $cnt = $count;
}
$column = array_merge($column, $target[$key]);
}
$xColumns[$k] = $column;
$xColumnsLength[$k] = $cnt - $count;
// --- 3. integrate columns of one element ---
$target = $xColumns; $xColumns = array(); $nextKey = -1;
if ($max > 1 && count($target) > 1)
{
foreach($target as $key => $column)
{
if ($key == $nextKey) continue;
if ($xColumnsLength[$key] == 1)
{
// --- merge with next column ---
$nextKey = $key + 1;
if (isset($target[$nextKey]) && count($target[$nextKey]))
{
$xColumns[] = array_merge($column, $target[$nextKey]);
continue;
}
}
$xColumns[] = $column;
}
$target = $xColumns;
}
}
$_rtl = Mage::getStoreConfigFlag('custom_menu/general/rtl');
if ($_rtl) {
$target = array_reverse($target);
}
return $target;
}
private function _countChild($children, $level, &$count)
{
foreach ($children as $child)
{
if ($child->getIsActive())
{
$count++; $activeChildren = $this->_getActiveChildren($child, $level);
if (count($activeChildren) > 0) $this->_countChild($activeChildren, $level + 1, $count);
}
}
}
private static function _explodeArrayByColumnsHorisontal($list, $num)
{
if ($num <= 0) return array($list);
$partition = array();
$partition = array_pad($partition, $num, array());
$i = 0;
foreach ($list as $key => $value) {
$partition[$i][$key] = $value;
if (++$i == $num) $i = 0;
}
return $partition;
}
private static function _explodeArrayByColumnsVertical($list, $num)
{
if ($num <= 0) return array($list);
$listlen = count($list);
$partlen = floor($listlen / $num);
$partrem = $listlen % $num;
$partition = array();
$mark = 0;
for ($column = 0; $column < $num; $column++) {
$incr = ($column < $partrem) ? $partlen + 1 : $partlen;
$partition[$column] = array_slice($list, $mark, $incr);
$mark += $incr;
}
return $partition;
}
/**
* Render category to html
*
* @param Mage_Catalog_Model_Category $category
* @param int Nesting level number
* @param boolean Whether ot not this item is last, affects list item class
* @param boolean Whether ot not this item is first, affects list item class
* @param boolean Whether ot not this item is outermost, affects list item class
* @param string Extra class of outermost list items
* @param string If specified wraps children list in div with this class
* @param boolean Whether ot not to add on* attributes to list item
* @return string
*/
protected function _renderCategoryMenuItemHtml($category, $level = 0, $isLast = false, $isFirst = false,
$isOutermost = false, $outermostItemClass = '', $childrenWrapClass = '', $noEventAttributes = false)
{
if (!$category->getIsActive()) {
return '';
}
$html = array();
// get all children
if (Mage::helper('catalog/category_flat')->isEnabled()) {
$children = (array)$category->getChildrenNodes();
$childrenCount = count($children);
} else {
$children = $category->getChildren();
$childrenCount = $children->count();
}
$hasChildren = ($children && $childrenCount);
// select active children
$activeChildren = array();
foreach ($children as $child) {
if ($child->getIsActive()) {
$activeChildren[] = $child;
}
}
$activeChildrenCount = count($activeChildren);
$hasActiveChildren = ($activeChildrenCount > 0);
// prepare list item html classes
$classes = array();
$classes[] = 'level' . $level;
$classes[] = 'nav-' . $this->_getItemPosition($level);
if ($this->isCategoryActive($category)) {
$classes[] = 'active';
}
$linkClass = '';
if ($isOutermost && $outermostItemClass) {
$classes[] = $outermostItemClass;
$linkClass = ' class="'.$outermostItemClass.'"';
}
if ($isFirst) {
$classes[] = 'first';
}
if ($isLast) {
$classes[] = 'last';
}
if ($hasActiveChildren) {
$classes[] = 'parent';
}
//NEW: add special class if level == 1 and menu is not an accordion.
if ($this->_isAccordion == FALSE && $level == 1) {
$classes[] = 'item';
}
// prepare list item attributes
$attributes = array();
if (count($classes) > 0) {
$attributes['class'] = implode(' ', $classes);
}
if ($hasActiveChildren && !$noEventAttributes) {
$attributes['onmouseover'] = 'toggleMenu(this,1)';
$attributes['onmouseout'] = 'toggleMenu(this,0)';
}
// assemble list item with attributes
$htmlLi = '<li';
foreach ($attributes as $attrName => $attrValue) {
$htmlLi .= ' ' . $attrName . '="' . str_replace('"', '\"', $attrValue) . '"';
}
$htmlLi .= '>';
$html[] = $htmlLi;
$html[] = '<a href="'.$this->getCategoryUrl($category).'"'.$linkClass.'>';
$html[] = '<span>' . $this->escapeHtml($category->getName()) . '</span>';
$html[] = '</a>';
// render children
$htmlChildren = '';
$j = 0;
foreach ($activeChildren as $child) {
$htmlChildren .= $this->_renderCategoryMenuItemHtml(
$child,
($level + 1),
($j == $activeChildrenCount - 1),
($j == 0),
false,
$outermostItemClass,
$childrenWrapClass,
$noEventAttributes
);
$j++;
}
if (!empty($htmlChildren)) {
//NEW: add opener if menu is used as accordion.
if ($this->_isAccordion == TRUE)
$html[] = '<span class="opener"> </span>';
if ($childrenWrapClass) {
$html[] = '<div class="' . $childrenWrapClass . '">';
}
$html[] = '<ul class="level' . $level . '">';
$html[] = $htmlChildren;
$html[] = '</ul>';
if ($childrenWrapClass) {
$html[] = '</div>';
}
}
$html[] = '</li>';
$html = implode("\n", $html);
return $html;
}
/**
* Get catagories of current store
*
* @return Varien_Data_Tree_Node_Collection
*/
public function getStoreCategories()
{
$helper = Mage::helper('catalog/category');
return $helper->getStoreCategories();
}
/**
* Render categories menu in HTML
*
* @param bool Add opener if menu is used as accordion.
* @param int Level number for list item class to start from
* @param string Extra class of outermost list items
* @param string If specified wraps children list in div with this class
* @return string
*/
public function renderCategoriesMenuHtml($isAccordion = FALSE, $level = 0, $outermostItemClass = '', $childrenWrapClass = '')
{
//NEW: save additional attribute
$this->_isAccordion = $isAccordion;
$activeCategories = array();
foreach ($this->getStoreCategories() as $child) {
if ($child->getIsActive()) {
$activeCategories[] = $child;
}
}
$activeCategoriesCount = count($activeCategories);
$hasActiveCategoriesCount = ($activeCategoriesCount > 0);
if (!$hasActiveCategoriesCount) {
return '';
}
$html = '';
$j = 0;
foreach ($activeCategories as $category) {
$html .= $this->_renderCategoryMenuItemHtml(
$category,
$level,
($j == $activeCategoriesCount - 1),
($j == 0),
true,
$outermostItemClass,
$childrenWrapClass,
true
);
$j++;
}
return $html;
}
}