22 октября 2009 г.

Magento, products sitemap

На сайте есть обычные продукты, которые можно продавать, и есть специальная категория Glossary, в которой находятся определения - такие продукты нельзя купить :) Т.е. список определений сделан через категорию, это оказалось достаточно удобно.

Проблема в том, что автогенерируемая страница с картой сайта показывает все активные продукты, в том числе и из категории Glossary. Вот этого и надо избежать. Да, и ещё нужно отсортировать продукты по алфавиту.

Сначала я попробовал сделать категорию Glossary неактивной. Ничего не вышло, Sitemap по-прежнему отображал все продукты. Вариант "выключить" все продукты категории Glossary - вообще не вариант :) Т.е. нигде в настройках в админике, и в xml, нельзя задать ни список категорий для исключения, ни порядка сортировки (может я плохо искал?).

Значит надо делать это вручную. Можно либо поменять ядрёные файлы (оставив нетронутыми шаблонные файлы) - блок catalog/seo_sitemap_product, изменить его так, что бы он исключал категорию Glossary и сортировал продукты. Понятно, почему это плохой вариант, и мы так делать не будем :) Вместо этого мы будем менять только шаблонные файлы. Вообще решение этой проблемы добавит немало безнес-логики в шаблоны. Не очень хорошо, но с этим можно жить :) Зато без переделки ядрёных файлов.

Шаблон странички Sitemap находится в файле template/catalog/seo/sitemap.phtml. Существующий код берёт коллекцию всех продуктов (полученную в соответствующем блоке) и выводит все её элементы.

Мы добавим новый массив, который будет содержать продукты, теже объекты, что и коллекция. Но этот массив не будет содержать "продуктов" категории Glossary. После формирования массива вызовем функцию usort и отсортируем массив по названиям продуктов.

Что бы узнать, в каких группах находится текущий продукт, нужно вызвать метод getCategoryIds - он вернёт массив id категорий. Только нужно не забывать, что один и тот же шаблон template/catalog/seo/sitemap.phtml используется для вывода как продуктов, так и категорий. Если вызвать getCategoryIds у объекта-категории, он вернёт null. Нужно специально обработать этот случай.

Итак, вот код, формирующий новый массив без "продуктов" категории Glossary, и упорядоченный по именам объектов:
<?php $_items = $this->getCollection(); ?>
<?php
    // Original collection is not ordered. To sort items by name
    // we'll use array, then we'll sort it by name. Array will
    // contain the same objects as original collection
    $items = array();

    // Create our array, excluding Glossary category (id == 63)
    foreach ($_items as $_item) {
        if (is_array($_item->getCategoryIds()) && in_array(63, $_item->getCategoryIds()))
            continue;
        $items[] = $_item;
    }

    function cmp($a, $b) {
        return strcmp($a->getName(), $b->getName());
    }

    usort($items, cmp);
?>

Остальной код, по выводу продуктов, остаётся нетронутым, кроме перебора не коллекции $_items, а нового массива $items.

Сразу же после просмотра результата стал заметен баг - хотя продукты из категории Glossary теперь не отображаются, кол-во продуктов выводимое сразу перед списком продуктов (130 Item(s)) осталось прежним.

Поправить это оказалось чуть посложнее. Код, выводящий эту информацию, - шаблон template/page/html/pager.html. И используется он в catalog.xml вот так:
<catalog_seo_sitemap>
    ...
    <reference name="content">
        <block type="page/template_container" name="seo.sitemap.container" template="catalog/seo/sitemap/container.phtml">
            <block type="page/template_links" name="seo.sitemap.links" as="links" template="page/template/links.phtml"/>
            
            <!-- Magento adds block with template "page/html/pager.phtml" -->
            <block type="page/html_pager" name="seo.sitemap.pager.top" as="pager_top" template="page/html/pager.phtml"/>
            
            ...

Код использует исходную коллекцию, содержащую все продукты, её размер соответственно больше чем нужно. Выход - написать свой шаблон, который подкорректирует кол-во продуктов, выводимое на экран.

Создаим этот шаблон - template/catalog/seo/sitemap/mypager.phtml.

Сначала посчитаем продукты, исключая продукты из категории Glossary:
<?php // Calc products that don't belong to Glossary category (63) ?>
<?php // We already hide glossary "products" from sitemap page, now we need ?>
<?php // to correct products count ?>
<?php $productsCountWithoutGlossary = 0; ?>
<?php foreach ($this->getCollection() as $_i) { ?>
<?php     if (is_array($_i->getCategoryIds()) && in_array(63, $_i->getCategoryIds())) continue; ?>
<?php     $productsCountWithoutGlossary++; ?>
<?php } ?>

Т.к. Sitemap отображает вообще всё что есть на одной странице (это сделано уже давно), то и весь код пейджера, рисующий номера страниц, не нужен - оставим только тот код, который выводит кол-во элементов на одной странице:
<table class="pager" cellspacing="0">
    <tr>
        <td>
            <strong><?php echo $this->__('%s Item(s)', $productsCountWithoutGlossary) ?></strong>
        </td>
    </tr>
</table>

Ещё нужно сказать Magento что мы хотим использовать наш шаблон в файле catalog.xml:
<catalog_seo_sitemap>
    ...
    <reference name="content">
        <block type="page/template_container" name="seo.sitemap.container" template="catalog/seo/sitemap/container.phtml">
            <block type="page/template_links" name="seo.sitemap.links" as="links" template="page/template/links.phtml"/>
            
            <!-- Replace default template with ours "catalog/seo/sitemap/mypager.phtml" -->
            <block type="page/html_pager" name="seo.sitemap.pager.top" as="pager_top" template="catalog/seo/sitemap/mypager.phtml"/>
            
            ...

Последнее - кол-во продуктов выводится не только вверху, но и внизу. Для коррекции выводимого кол-ва так же просто поменяем шаблон в файле catalog.xml:
<catalog_seo_sitemap>
    ...
    <reference name="content">
        <block type="page/template_container" name="seo.sitemap.container" template="catalog/seo/sitemap/container.phtml">
            <block type="page/html_pager" name="seo.sitemap.pager.bottom" as="pager_bottom" template="catalog/seo/sitemap/mypager.phtml"/>
    ...

Вот, готово. Теперь Products Sitemap исключает продукты категории Glossary, и выводит правильное кол-во продуктов. Страница Category Sitemap не падает и выводит все категории :)

Изменённые файлы:
  • app/design/frontend/default/sunnyD/layout/catalog.xml
  • app/design/frontend/default/sunnyD/template/catalog/seo/sitemap.phtml
  • app/design/frontend/default/sunnyD/template/catalog/seo/sitemap/mypager.phtml

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

Отправить комментарий