Exploiter l'ensemble des attributs catégories dans le menu principal

  • De le 25 septembre 2013
  • Difficulté : 2/4

Exploiter l'ensemble des attributs catégories dans le menu principal Par défaut, le menu principal de navigation ne permet d'exploiter que le nom, l'URL et le statut d'une catégorie. Ce sont les seules données associées à l'objet de la class Varien_Data_Tree_Node. Un module peut nous permettre d'exploiter l'ensemble des attributs, sans générer de requêtes supplémentaires. (Magento > 1.7.0.0)

Présentation

Les 3 attributs de catégories récupérés lors de l'instanciation d'une collection de catégories apparaissent dans le fichier de configuration du module Mage_Catalog :

app/code/core/Mage/Catalog/etc/config.xml

<category>
    <collection>
        <attributes>
            <name/>
            <url_key/>
            <is_active/>
        </attributes>
    </collection>
</category>

Il est alors facile d'imaginer créer un module ne contenant qu'un fichier de configuration alimentant le noeud de configuraiton category/collection/attributes. Mais cela n'aura pour effet que d'ajouter les attributs spécifiés à l'entité catégorie. Pour les exploiter au sein du menu, un développement supplémentaire est nécessaire. Et qu'en est-il du flat ?

Le module décrit dans cet article a pour objectif d'utiliser l'attribut thumbnail pour illustrer les catégories principales du menu.

Categories Tree Thumbnail

Architecture du module

Développement du module

config.xml

Commençons par le fichier de configuration. Ce fichier doit présenter les éléments suivants :

  • L'attribut thumbnail doit être ajouté au noeud category/collection/attributes.
  • La class Mage_Page_Block_Html_Topmenu doit être surchargée. La méthode _getHtml du bloc est chargé de la construction HTML du menu.
  • La class Mage_Catalog_Model_Observer doit être surchargée. La méthode _addCategoriesToMenu est à compléter pour spécifier les attributs du menu à exploiter.

app/code/local/Magentix/Navigation/etc/config.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_Navigation>
            <version>0.1.0</version>
        </Magentix_Navigation>
    </modules>
    <global>
        <blocks>
            <page>
                <rewrite>
                    <html_topmenu>Magentix_Navigation_Block_Page_Html_Topmenu</html_topmenu>
                </rewrite>
            </page>
        </blocks>
        <models>
            <catalog>
                <rewrite>
                    <observer>Magentix_Navigation_Model_Catalog_Observer</observer>
                </rewrite>
            </catalog>
        </models>
    </global>
    <frontend>
        <category>
            <collection>
                <attributes>
                    <thumbnail/>
                </attributes>
            </collection>
        </category>
    </frontend>
</config>

Observer.php

La méthode _addCategoriesToMenu de la class Mage_Catalog_Model_Observer est exécutée sur l'événement page_block_html_topmenu_gethtml_before (depuis la méthode addCatalogToTopmenuItems).

Nous indiquons que l'attribut thumbnail est à ajouter aux données :

app/code/local/Magentix/Navigation/Model/Catalog/Observer.php

<?php

class Magentix_Navigation_Model_Catalog_Observer extends Mage_Catalog_Model_Observer
{

    /**
     * Recursively adds categories to top menu
     *
     * @param Varien_Data_Tree_Node_Collection|array $categories
     * @param Varien_Data_Tree_Node $parentCategoryNode
     */
    protected function _addCategoriesToMenu($categories, $parentCategoryNode)
    {
        foreach ($categories as $category) {
            if (!$category->getIsActive()) {
                continue;
            }

            $nodeId = 'category-node-' . $category->getId();

            $tree = $parentCategoryNode->getTree();
            $categoryData = array(
                'name' => $category->getName(),
                'id' => $nodeId,
                'url' => Mage::helper('catalog/category')->getCategoryUrl($category),
                'is_active' => $this->_isActiveMenuCategory($category),
                /**** Attribut(s) supplémentaires ****/
                'thumbnail' => $category->getThumbnail(),
                /*************************************/
            );
            $categoryNode = new Varien_Data_Tree_Node($categoryData, 'id', $tree, $parentCategoryNode);
            $parentCategoryNode->addChild($categoryNode);

            if (Mage::helper('catalog/category_flat')->isEnabled()) {
                $subcategories = (array)$category->getChildrenNodes();
            } else {
                $subcategories = $category->getChildren();
            }

            $this->_addCategoriesToMenu($subcategories, $categoryNode);
        }
    }
}

Topmenu.php

Ce bloc permet par la méthode _getHtml de générer le menu. La récursivité facilite sa construction, l'utilisation d'un template n'est pas adapté.

Nous modifions simplement le code afin d'y ajouter notre miniature.

Une erreur fréquente est de voir les entités catégories chargées une à une depuis cette méthode. Cela pose un problème de performance : une requête supplémentaire par catégorie.

app/code/local/Magentix/Navigation/Block/Page/Html/Topmenu.php

<?php

class Magentix_Navigation_Block_Page_Html_Topmenu extends Mage_Page_Block_Html_Topmenu
{

    /**
     * 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);
            }

            $html .= '<li ' . $this->_getRenderedMenuItemAttributes($child) . '>';
            $html .= '<a href="' . $child->getUrl() . '" ' . $outermostClassCode . '><span>';

            /****** Miniature ******/
            if($child->getThumbnail()) {
                $html .= '<img src="'.Mage::getBaseUrl('media').'catalog/category/'.$child->getThumbnail().'" alt="" />';
            }
            /***********************/

            $html .= $this->escapeHtml($child->getName()). $child->getDescription() . '</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;
    }

}

Magentix_Navigation.xml

Il nous reste à déclarer le nouveau module :

app/etc/modules/Magentix_Navigation.xml

<?xml version="1.0"?>
<config>
    <modules>
        <Magentix_Navigation>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Catalog />
                <Mage_Page />
            </depends>
        </Magentix_Navigation>
    </modules>
</config> 

Flat Catalog Categories

Si le Flat Catalog Categories est activé (recommandé), notre menu ne présente plus la miniature. En effet, la requête exécutée ne tient pas compte des noeuds spécifiés dans le fichier de configuration (un peu dommage tout de même...).

Lorsque le flat est activé, un observer doit être ajouté. Reprenons notre fichier de configuration :

app/code/local/Magentix/Navigation/etc/config.xml

<!-- ......... -->
    <global>
        <!-- ......... -->
        <events>
            <catalog_category_flat_loadnodes_before>
                <observers>
                    <add_category_attributes>
                        <type>singleton</type>
                        <class>navigation/catalog_observer</class>
                        <method>addFlatAttributes</method>
                    </add_category_attributes>
                </observers>
            </catalog_category_flat_loadnodes_before>
        </events>
    </global>
<!-- ......... -->

L'événement est déclenché juste avant que la requête ne soit exécutée. Nous pouvons donc, via la nouvelle méthode addFlatAttributes de notre observer, spécifier les colonnes à ajouter :

app/code/local/Magentix/Navigation/Model/Catalog/Observer.php

<?php

class Magentix_Navigation_Model_Catalog_Observer extends Mage_Catalog_Model_Observer
{

    /* ......... */

    /**
     * Add columns to Request
     *
     * @param Varien_Event_Observer $observer
     * @return Magentix_Navigation_Model_Catalog_Observer
     */
    public function addFlatAttributes(Varien_Event_Observer $observer)
    {
        $select = $observer->getEvent()->getSelect();

        $select->columns('thumbnail');

        return $this;
    }

}
commentaires

Commentez cet article : Exploiter l'ensemble des attributs catégories dans le menu principal