RSS Мои друзья Контакты

Страницы всех новинок и спец. предложений с фильтрами в Magento

В одной из предыдущих статей я рассказывал, как можно вывести основные типы блоков для продуктов. Продолжая тему, хочу поделится идеей, как можно отобразить страницу категории с фильтрами, сортировкой и пейджингом для любых типов продуктов. Для простоты возьмем 2 типа: последние продукты (весь каталог обратном порядке) и продукты со спец. предложением.

Фундамент - залог устойчивости

Идея очень проста и состоит в том, что мы будем отображать дефолтную категорию, которая содержит в себе все продукты, применив к ним необходимые фильтры. Обязательным условием является установка атрибута "Is Anchor" в true.

Из той же статьи, которая была упомянута выше я возьму модуль и расширю его функционал. По сути нужно написать всего один класс контроллера, поскольку правила роутинга я прописал заранее. Контролеры модуля будут доступны по url products. Сам класс является наследником Mage_Catalog_CategoryController.

Как говорится все уже написано до нас, но немного не так, по-этому придется скопировать метод _initCategory и часть метода viewAction в новый контроллер из его родителя. В первом меняем строку

if (!Mage::helper('catalog/category')->canShow($category)) {
    return false;
}
Mage::getSingleton('catalog/session')->setLastVisitedCategoryId($category->getId());

на

$isRootCategory = !$category->isInRootCategoryList();
if (!$isRootCategory && !Mage::helper('catalog/category')->canShow($category)) {
    return false;
}

if (!$isRootCategory) {
    Mage::getSingleton('catalog/session')->setLastVisitedCategoryId($category->getId());
}

И тем самым позволяем инициализировать дефолтную категорию стора.

Создадим защищенный метод _prepareView, точная копия метода viewAction, за исключением что он не вызывает рендеринг лейаута, а возвращает модель инициализированной категории.

И наконец ядром всей этой системы является метод _emulateCategory, который принимает 2 аргумента: идентификатор категории (в нашем случае - это всегда рут категория, но может быть и любая другая!) и придуманное нами имя. Возвращает коллекцию продуктов или выбрасывает исключение, если на странице нет product_list блока. На всякий случай (может понадобится в будущем) ставим категории флаг "Is Emulated", чтобы знать что это нереальная категория.

protected function _emulateCategory($categoryId, $categoryTitle)
{
    $this->getRequest()->setParam('id', $categoryId);

    $category = $this->_prepareView();
    $category->setName($categoryTitle)
        ->setIsEmulated(true);

    // reset layout rendering
    if ($head = $this->getLayout()->getBlock('head')) {
        $head->setTitle($categoryTitle);
    }

    if ($breadcrumb = $this->getLayout()->getBlock('breadcrumbs')) {
        $breadcrumb->addCrumb('specials', array(
            'readonly' => true,
            'title'    => $categoryTitle,
            'label'    => $categoryTitle
        ));
    }

    if ($list = $this->getLayout()->getBlock('product_list')) {
        return $list->getLoadedProductCollection();
    }
    Mage::throwException($this->__('Unable to find products collection'));
}

Крепкий фундамент заложен, теперь можно приступить к реализации того, что нам нужно было изначально.

Стены - уют и покой

Чтобы отобразить страницу, нужно создать метод-екшен с именем lastAction

public function lastAction()
{
    $id   = Mage::app()->getStore()->getRootCategoryId();
    $name = Mage::helper('catalog')->__('Last Products');

    try {
        $productCollection = $this->_emulateCategory($id, $name);
        // filter products in some way
        $productCollection->setOrder('entity_id', 'desc');

        if ($layer = $this->getLayout()->getBlock('catalog.leftnav')) {
            // set visible filters
            #$layer->setVisibleFilters(array('price', 'manufacturer'));
        }
    } catch (Exception $e) {
        return $this->_redirect('');
    }

    $this->renderLayout();
}

Страница спец. предложений делается аналогичным образом. Думаю Вы заметили комментарий "set visible filters". Я немного усложнил задание и сделал возможность отображения только тех фильтров, которые мы хотим чтобы были видны на этой странице.

Чтобы это заработало придется еще переопределить стандартный шаблон catalog/layer/view.phtml. Добавив в него проверку на видимость фильтра, если установлено свойство visible_filters, если нет - то показываем все фильтры. Страница доступна по url: /products/index/last. Вот что получилось у меня

Magento special products page

Исходный код можно скачать здесь.

P.S.: код фильтров для новых продуктов и спец. предложений можно найти здесь, где все детально расписано.

Добавить комментарий

Комментариев: 7

  • Дмитрий
    Ответить 20 июля 2012 г., 15:38
    Спасибо, получилось вывести страницу со специальной ценой. У меня вопрос. Предположим, что в магазине 3000 товаров. Со специальной ценой - всего 45. Так вот на странице модуля, где отображаются товары со специальной ценой, фильтры, получается, по всем 3000 товарам, а нужно же ведь по 45?
    • Дмитрий
      Ответить 20 июля 2012 г., 15:50
      Просто в таком случае было бы проще в layout'е прописать:
      <reference name="right"><block type="catalog/layer_view" name="catalog.leftnav" after="currency" template="catalog/layer/view.phtml"/> </reference>
      • Сергей (Администратор)
        Ответить 20 июля 2012 г., 18:42
        В таком случае Вам нужно создать свой контроллер + свой блок и фильтровать коллекцию в блоке. В данном случае создается только один контроллер
    • Сергей (Администратор)
      Ответить 20 июля 2012 г., 18:40
      Фильтр (запрос в базу на выборку данных) всегда идет по всем товарам с учетом индексов понятно же. На страничке будут видны только товары со спец. предложением
      • Дмитрий
        Ответить 25 июля 2012 г., 11:27
        Пагинацию смог добавить, почему заработало после удаления в методе specialsAction() метода "addCategoryIds()" у $productCollection. А вот осталось последнее, с чем уже долго мучаюсь - не отображаются фильтры Layered Navigation. Необходимы фильтры по разделам и по цене, как у вас в блоке "shopping by". Дело в том, что у меня в теме этот блок по умолчанию справа, так вот на странице products/index/last он вообще пустой. Не подскажете в какую сторону копать? Дело в том, что в вашем модуле я не нашел ничего, что к нему бы обращалось. Спасибо.
        • Дмитрий
          Ответить 25 июля 2012 г., 12:03
          $this->getLayout()->getBlock('catalog.leftnav') возвращает false, хотя он объявлен в catalog.xml на хэндле <catalog_category_default>
  • Дмитрий
    Ответить 25 июля 2012 г., 14:16
    Проблема решена. В административной панели, так как для вывода используется Root-каталог, я зашел в Каталог->Управление разделами->Root Catalog->Пользовательский дизайн и в Custom Layout Update прописал
    <reference name="left">
    <block type="catalog/layer_view" name="catalog.leftnav" after="currency" template="catalog/layer/view-special.phtml"/>
    </reference>
    после этого создал view-special.phtml и написал необходимые фильтры Layered Navigation.
    Ну это для тех, у кого вдруг такая же проблема. Спасибо.