我希望我的主菜单不包含任何空的类别。我已经使用
在相关的phtml文件中轻松完成了分层导航$_category->getProductCount()
然而,对于导航菜单,我发现不可能轻易做到这一点(我已经看过Prattski的例子,但看起来确实相当于OTT)。
主菜单似乎是在Mage_Page_Block_Html_Topmenu.php
中构建的,特别是在函数_getHtml
中。这会让所有孩子都进入菜单,如果我尝试$child->getId()
之类的内容,我会得到像"category-node-36"
这样的内容。
我似乎没有能够使用getProductCount()
,所以测试它是否超过零。
有可能这样做吗?有人可以指点我怎么做?
如果可以的话,我会用我的版本扩展课程。
答案 0 :(得分:0)
要执行此操作,请转到:
app/code/core/Mage/Catalog/Block
文件夹并复制 Navigation.php 并在您的本地包中覆盖它。
打开您的软件包的 Navigation.php 并将以下代码粘贴到此文件中:
if ($category->getIsActive()) {
$cat = Mage::getModel('catalog/category')->load($category->getId());
$products = Mage::getResourceModel('catalog/product_collection')->addCategoryFilter($cat);
Mage::getSingleton('catalog/product_status')->addVisibleFilterToCollection($products);
Mage::getSingleton('catalog/product_visibility')->addVisibleInCatalogFilterToCollection($products);
Mage::getSingleton('cataloginventory/stock')->addInStockFilterToCollection($products);
if(count($products)==0)
return;
}
我希望我的代码可以帮到你。
答案 1 :(得分:0)
我终于破解了它,尽管我并不相信它是一个最佳解决方案。无论如何,我将描述我在这里所做的事情,并希望有人能够提高效率。因为我不熟悉很多方面,所以我会逐一介绍一下。所以道歉。
正如我所说,至少在我的情况下,主菜单是通过app / code / core / Mage / Page / Block / Html中的Topmenu.php构建的,特别是方法_getHtml。我绝对不想修改核心文件,因此我发现了如何通过新模块扩展此方法。 (如果您熟悉创建新模块,可以跳过这一步。)
我需要创建一个新模块(我将在下面将其命名为MYMOD)。当我覆盖核心magento页面块时,我不得不创建新文件夹:app / code / local / MYMOD / Page以及两个子文件夹Block等(我相信它们区分大小写)。并在Block内另一个子文件夹Html。您可以看到这与app / code / core / Mage中的文件夹结构完全相同。
etc文件夹在config.xml文件中保存新模块的规范。这就是我的样子:
<?xml version="1.0" encoding="UTF-8"?>
<!-- The root node for Magento module configuration -->
<config>
<!--
The module's node contains basic
information about each Magento module
-->
<modules>
<!--
This must exactly match the namespace and module's folder
names, with directory separators replaced by underscores
-->
<MYMOD_Page>
<!-- The version of our module, starting at 0.0.1 -->
<version>0.0.1</version>
</MYMOD_Page>
</modules>
<global>
<blocks>
<page>
<rewrite>
<html_topmenu>MYMOD_Page_Block_Html_Topmenu</html_topmenu>
</rewrite>
</page>
</blocks>
</global>
</config>
你可以在其他地方了解其中的原因和地点。
不幸的是(在我看来!),你不是要在Magento中指定一个新模块。您还必须创建一个名为&#34; MYMOD_Page.xml&#34;的文件。在app / etc / modules中。这只是告诉Magento你的模块以及在哪里寻找它。我看起来像这样:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<MYMOD_Page>
<!-- Whether our module is active: true or false -->
<active>true</active>
<!-- Which code pool to use: core, community or local -->
<codePool>local</codePool>
</MYMOD_Page>
</modules>
</config>
好的,对不起关于模块的无关指示,但我确实喜欢自成一体的详细解释。
我现在可以在我的模块中使用子类创建一个新文件,在该子类中我可以使用将用于代替核心Magento的方法(函数)。文件名必须与原始文件Topmenu.php相同,并且它位于app / code / local / MYMOD / Page / Block / Html中。
请记住,面向对象的结构意味着Topmenu.php的原始核心版本中的所有功能都可供我使用,我不必在我的新版本中复制它们(非常适合可维护性)。我的Topmenu.php版本只需要包含我可能想要的任何新功能(在这种情况下我不需要任何功能)并重新声明我想用我自己的版本覆盖的任何功能。在我的例子中,我需要修改两个函数:_getHtml和_getMenuItemClasses。
_getHtml需要额外检查,因此不包括任何空类别。
_getMenuItemClasses需要额外的检查,以便类&#34; parent&#34;没有添加到子项为空的类别中。
以下是我的做法(附评论)。我确信有更好的方法,但我对Magento还是比较新的。
class MYMOD_Page_Block_Html_Topmenu extends Mage_Page_Block_Html_Topmenu
// Create my subclass, in accordance with how I've defined the new module
{
/**
* Recursively generates top menu html from data that is specified in $menuTree
*
* @param Varien_Data_Tree_Node $menuTree
* @param string $childrenWrapClass
* @return string
*/
protected function _getHtml(Varien_Data_Tree_Node $menuTree, $childrenWrapClass)
{
$html = '';
$children = $menuTree->getChildren();
$parentLevel = $menuTree->getLevel();
$childLevel = is_null($parentLevel) ? 0 : $parentLevel + 1;
$counter = 1;
$childrenCount = $children->count();
$parentPositionClass = $menuTree->getPositionClass();
$itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';
foreach ($children as $child) {
$child->setLevel($childLevel);
$child->setIsFirst($counter == 1);
$child->setIsLast($counter == $childrenCount);
$child->setPositionClass($itemPositionClassPrefix . $counter);
$outermostClassCode = '';
$outermostClass = $menuTree->getOutermostClass();
if ($childLevel == 0 && $outermostClass) {
$outermostClassCode = ' class="' . $outermostClass . '" ';
$child->setClass($outermostClass);
}
/*
* Find out if this category has any products. I don't know an easier way.
* The id of every child returned by getID is of the form "category-node-nnn"
* where nnn is the id that can be used to select the category details.
* substr strips everything leaving just the nnn.
* Then use getModel-> getCollection with a filter on the id. Although this looks
* like it will return many, obviously category ids are unique so in fact it only
* returns the category we're currently looking at.
*/
$_gcategoryId = substr($child->getId(), 14, 6);
$_gcategories = Mage::getModel('catalog/category')->getCollection()->addFieldToFilter('entity_id', array('eq', $_gcategoryId));
foreach ($_gcategories as $_gcategory) {
$_gcategoryCount = $_gcategory->getProductCount();
}
/*
* Now only include those categories that have products.
* In my case I also wanted to include the top level categories come what may.
*/
if (($childLevel == 0) || ($_gcategoryCount > 0)) {
$html .= '<li ' . $this->_getRenderedMenuItemAttributes($child) . '>';
$html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>'
. $this->escapeHtml($child->getName()) . '</span></a>';
if ($child->hasChildren()) {
if (!empty($childrenWrapClass)) {
$html .= '<div class="' . $childrenWrapClass . '">';
}
$html .= '<ul class="level' . $childLevel . '">';
$html .= $this->_getHtml($child, $childrenWrapClass);
$html .= '</ul>';
if (!empty($childrenWrapClass)) {
$html .= '</div>';
}
}
$html .= '</li>';
}
$counter++;
}
return $html;
}
/**
* Returns array of menu item's classes
*
* @param Varien_Data_Tree_Node $item
* @return array
*/
protected function _getMenuItemClasses(Varien_Data_Tree_Node $item)
{
$classes = array();
$classes[] = 'level' . $item->getLevel();
$classes[] = $item->getPositionClass();
if ($item->getIsFirst()) {
$classes[] = 'first';
}
if ($item->getIsActive()) {
$classes[] = 'active';
}
if ($item->getIsLast()) {
$classes[] = 'last';
}
if ($item->getClass()) {
$classes[] = $item->getClass();
}
if ($item->hasChildren()) {
/*
* Don't just check if there are children but, if there are, are they all empty?
* If so, then the changes in _getHtml will mean none of them will be included
* and so this one has no children displayed and so the "parent" class is not appropriate.
*/
$children = $item->getChildren(); // Get all the children from this menu category
foreach ($children as $child) { // Loop over each child and find out how many products (see _getHtml)
$_gcategoryId = substr($child->getId(), 14, 6);
$_gcategories = Mage::getModel('catalog/category')->getCollection()->addFieldToFilter('entity_id', array('eq', $_gcategoryId));
foreach ($_gcategories as $_gcategory) { // Remember, there's actually only one category that will match the child's id
$_gcategoryCount = $_gcategory->getProductCount();
}
if ($_gcategoryCount > 0) { // As soon as one child has products, then we have a parent and can stop looking
$classes[] = 'parent';
break;
}
}
}
return $classes;
}
}
我希望这很清楚。它做我想要的(我的商店很小),但欢迎任何改进建议。
答案 2 :(得分:0)
路径:app / design / frontend / rwd / default / template / page / html / topmenu / renderer.phtml
在foreach ($children as $child) {
$mageconnection = Mage::getSingleton("core/resource")->getConnection("core_read");
$query="select count(cataloginventory_stock_item.is_in_stock) as subcount,catalog_category_flat_store_1.`name` from catalog_category_flat_store_1 INNER JOIN
catalog_category_product_index on catalog_category_product_index.category_id=catalog_category_flat_store_1.entity_id INNER JOIN
cataloginventory_stock_item on cataloginventory_stock_item.product_id=catalog_category_product_index.product_id
where cataloginventory_stock_item.is_in_stock=1 and catalog_category_product_index.category_id=";
$subCatqueryId = str_replace('category-node-', '', $child->getId());
$prodCollection = $mageconnection->fetchAll("$query'{$subCatqueryId}'");
if($prodCollection[0]["subcount"] > 0) {
$child->setLevel($childLevel);
$child->setIsFirst($counter == 1);
// these are the existing code ..
...
...
$counter++;
}
}
控制产品数量是非常快速和安全的方法。