Большинство магазинов позволяют пользователям выбирать вид каталога товаров на странице категории. Выглядит это примерно так.
Цель статьи - добавить данный функционал в virtuemart 3.
К сожалению, нельзя просто установить плагин, который сделает всю работу. Так же не может быть универсальной инструкции, подходящей для всех шаблонов.
В статье все правки будут рассматриваться на примере стандартного шаблона, в который была добавлена поддержка bootstrap сетки (подробнее про добавление сетки). Скачать файл-заготовку можно по этой ссылке.
Я постараюсь изложить алгоритм, который поможет сделать то же самое для любого шаблона virtuemart.
Кроме этого, существует несколько способов смены вида каталога:
- На странице одновременно выводятся два блока со всеми товарами. В каждом блоке своя разметка(плиткой и списком). При нажатии на кнопки происходит скрытие одного блока и показ другого.
- Товары выводятся в одном блоке. При нажатии на кнопки происходит добавление класса родительскому блоку с товарами, который меняет внешний вид.
В статье будет использован второй вариант. Он не утяжеляет страницу, хотя и накладывает некоторые ограничения на верстку.
Так же в статье все правки будут вноситься в стандартные файлы virtuemart, находящиеся в папке /components/com_virtuemart/views/. На вашем сайте данные файлы могут быть переопределены в шаблоне. В этом случае их нужно править в папке /templates/имя_шаблона/html/com_virtuemart/.
Добавление кнопок переключения
Начнем с добавления кнопок, при нажатии на которые будет меняться вид каталога. Например, добавим их после блока с сортировкой.
В файле /components/com_virtuemart/views/category/tmpl/default.php сразу после
1 2 3 4 5 6 7 8 9 10 11 12 |
<div class="orderby-displaynumber"> <div class="floatleft vm-order-list"> <?php echo $this->orderByList['orderby']; ?> <?php echo $this->orderByList['manufacturer']; ?> </div> <div class="vm-pagination vm-pagination-top"> <?php echo $this->vmPagination->getPagesLinks (); ?> <span class="vm-page-counter"><?php echo $this->vmPagination->getPagesCounter (); ?></span> </div> <div class="floatright display-number"><?php echo $this->vmPagination->getResultsCounter ();?><br/><?php echo $this->vmPagination->getLimitBox ($this->category->limit_list_step); ?></div> <div class="clear"></div> </div> <!-- end of orderby-displaynumber --> |
Вставим
1 2 3 4 5 |
<div class="product-view-button"> <span>Вид: </span> <a href="#" class="grid active"><i class="fa fa-th-large"></i></a> <a href="#" class="list"><i class="fa fa-th-list"></i></a> </div> |
Для иконок я использовал иконочные шрифты Font Awesome, но можно вставить просто картинки.
Для стилизации добавим немного css
1 2 3 4 5 6 7 8 |
.product-view-button a{ display: inline-block; font-size: 18px; color: #ddd; } .product-view-button a.active{ color: #428bca; } |
Получим следующее
Настройка разметки каталога
Это самый важный этап. Нужно настроить разметку так, чтобы при добавлении класса родительскому блоку с товарами можно было через css стили легко изменить внешний вид каталога.
Я предлагаю следующую схему
1 2 3 4 5 6 7 8 9 10 11 |
<div class="spacer"> <div class="vm-product-media-container"> <!-- Код вывода изображения товара --> </div> <div class="vm-product-descr-container"> <!-- Код вывода названия и краткого описания --> </div> <div class="vm-product-detail-container"> <!-- Код вывода цены, кнопки Купить, настраиваемых полей --> </div> </div> |
Вся информация о товаре располагается в 3 блоках. При выводе товаров плиткой каждый блок будет иметь ширину 100% и располагаться друг под другом. При выводе товаров списком ширина блоков будет изменена так, чтобы они располагались в одну строку. Это просто реализовать с помощью css.
Итак, в файле /components/com_virtuemart/sublayouts/products.php заменим все содержимое внутри тега spacer
1 2 3 |
<div class="spacer"> ... </div> |
На
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
<div class="vm-product-media-container"> <a title="<?php echo $product->product_name ?>" href="<?php echo $product->link.$ItemidStr; ?>"> <?php echo $product->images[0]->displayMediaThumb('class="browseProductImage"', false); ?> </a> </div> <div class="vm-product-descr-container"> <h2><?php echo JHtml::link ($product->link.$ItemidStr, $product->product_name); ?></h2> <?php if(!empty($rowsHeight[$row]['product_s_desc'])){ ?> <p class="product_s_desc"> <?php // Product Short Description if (!empty($product->product_s_desc)) { echo shopFunctionsF::limitStringByWord ($product->product_s_desc, 60, ' ...') ?> <?php } ?> </p> <?php } ?> <div class="vm-product-rating-container"> <?php echo shopFunctionsF::renderVmSubLayout('rating',array('showRating'=>$showRating, 'product'=>$product)); if ( VmConfig::get ('display_stock', 1)) { ?> <span class="vmicon vm2-<?php echo $product->stock->stock_level ?>" title="<?php echo $product->stock->stock_tip ?>"></span> <?php } echo shopFunctionsF::renderVmSubLayout('stockhandle',array('product'=>$product)); ?> </div> </div> <div class="vm-product-detail-container"> <?php //echo $rowsHeight[$row]['price'] ?> <div class="vm3pr-<?php echo $rowsHeight[$row]['price'] ?>"> <?php echo shopFunctionsF::renderVmSubLayout('prices',array('product'=>$product,'currency'=>$currency)); ?> <div class="clear"></div> </div> <?php //echo $rowsHeight[$row]['customs'] ?> <div class="vm3pr-<?php echo $rowsHeight[$row]['customfields'] ?>"> <?php echo shopFunctionsF::renderVmSubLayout('addtocart',array('product'=>$product,'rowHeights'=>$rowsHeight[$row], 'position' => array('ontop', 'addtocart'))); ?> </div> <div class="vm-details-button"> <?php // Product Details Button $link = empty($product->link)? $product->canonical:$product->link; echo JHtml::link($link.$ItemidStr,vmText::_ ( 'COM_VIRTUEMART_PRODUCT_DETAILS' ), array ('title' => $product->product_name, 'class' => 'product-details' ) ); //echo JHtml::link ( JRoute::_ ( 'index.php?option=com_virtuemart&view=productdetails&virtuemart_product_id=' . $product->virtuemart_product_id . '&virtuemart_category_id=' . $product->virtuemart_category_id , FALSE), vmText::_ ( 'COM_VIRTUEMART_PRODUCT_DETAILS' ), array ('title' => $product->product_name, 'class' => 'product-details' ) ); ?> </div> </div> |
В результате разметка каждого товара станет следующей
Добавление стилей для вывода товаров списком
При нажатии кнопок у родительского блока с классом .row будут переключаться классы .list-view и .grid-view.
Добавим в css файл шаблона стили, изменяющие вид каталога при наличии класса .list-view
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
.list-view .product, .list-view .spacer{ width: 100%; } .list-view .spacer .vm-product-media-container{ width: 20%; float: left; } .list-view .spacer .vm-product-descr-container{ width: 50%; float: left; text-align: left; } .list-view .spacer .vm-product-descr-container .vm-product-rating-container span{ float: left; } .list-view .spacer .vm-product-detail-container{ width: 30%; float: left; } |
В результате при наличии класса .list-view у блока .row каталог будет иметь следующий вид.
По умолчанию родительский блок должен иметь класс .grid-view. Для этого в файле /components/com_virtuemart/sublayouts/products.php заменим
1 |
<div class="row"> |
на
1 |
<div class="row grid-view"> |
Настройка переключения кнопок
Чтобы при нажатии на кнопки переключался вид, в конец файла /components/com_virtuemart/views/category/tmpl/default.php добавим следующий скрипт
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<script> jQuery('.product-view-button .grid').click(function(){ jQuery('.product-view-button .list').removeClass('active'); jQuery(this).addClass('active'); jQuery('.category-view .browse-view .row').removeClass('list-view').addClass('grid-view'); return false; }); jQuery('.product-view-button .list').click(function(){ jQuery('.product-view-button .grid').removeClass('active'); jQuery(this).addClass('active'); jQuery('.category-view .browse-view .row').removeClass('grid-view').addClass('list-view'); return false; }); </script> |
Теперь при нажатии кнопок вид каталога должен меняться.
Запоминаем выбранный вид
Финальный этап. Запоминаем выбранный вид каталога, чтобы он автоматически активировался при переходе в другую категорию или при заходе на сайт через несколько дней.
Можно использовать 2 способа:
- хранить данные в куках
- использовать локальное хранилище localStorage
Второй вариант более прост, поэтому используем его. Почитать про работу с localStorage можно в этой статье.
Заменим скрипт из предыдущего этапа на
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<script> var productView = localStorage.getItem('productView'); if(productView == 'list'){ jQuery('.product-view-button .grid').removeClass('active'); jQuery('.product-view-button .list').addClass('active'); jQuery('.category-view .browse-view .row').removeClass('grid-view').addClass('list-view'); } jQuery('.product-view-button .grid').click(function(){ localStorage.removeItem('productView'); localStorage.setItem('productView', 'grid'); jQuery('.product-view-button .list').removeClass('active'); jQuery(this).addClass('active'); jQuery('.category-view .browse-view .row').removeClass('list-view').addClass('grid-view'); return false; }); jQuery('.product-view-button .list').click(function(){ localStorage.removeItem('productView'); localStorage.setItem('productView', 'list'); jQuery('.product-view-button .grid').removeClass('active'); jQuery(this).addClass('active'); jQuery('.category-view .browse-view .row').removeClass('grid-view').addClass('list-view'); return false; }); </script> |
Конечный результат будет выглядеть так
Пример реализации можно также посмотреть на демо-сайте шаблона AirShop.
Итог
Каждый шаблон индивидуален, но алгоритм, изложенный в статье, применим к любому сайту.
Если с самостоятельной реализацией возникли трудности или нет времени разбираться с кодом, то вы можете заказать установку (почта для связи: admin@virtuemart.su)
Lagoon
Спасибо.
Сейчас делаю и у появился вопрос.
у вас в статье не указано в каком файле поменять
-------По умолчанию родительский блок должен иметь класс .grid-view. Для этого в файле заменим-----
без этого ничего не получается
admin
Править нужно в файле /components/com_virtuemart/sublayouts/products.php, добавил в статью.
Staffbsa
То же Интересно прилепить кнопку
Это из предыдущего описания
Все дальнейшие правки будут вноситься в файл /components/com_virtuemart/sublayouts/products.php, который отвечает за вид товаров в категории.
Lagoon
В файле таких 2 дива - какой из них менять?
Lagoon
spacer в файле 2 блока
admin
Править нужно второй блок.
Для шаблона LikeShop вышло обновление, в котором уже реализовано переключение.
Валерий
А первый способ вы описывать не будите?=)
admin
Необходимо одновременно вывести на странице товары плиткой и списком. При нажатии на кнопки смены вида вместо смены классов(как реализованно в статье) нужно просто скрывать блоки. Код для этого несложный. Вы можете самостоятельно вывести два вида товаров,а с javascript я помогу.
Иван
капец ну как можно писать статьи, с пользой для поисковиков, думаю желающих мульйон посетить эту страницу, а толку 0, или автор надеется что к нему все писать начнут в личку. Где расписаны у вас расписаны классы class="fa fa-th-large" и т.д. он даже кнопки не выводит, как переключатся?
Иван
у меня есть шаблон bootstrap, делаю изменения в двух файла (/components/com_virtuemart/views/category/tmpl/default.php и /components/com_virtuemart/sublayouts/products.php и сss) ничего не происходит, даже переключение не работает
Иван
ссори у меня в бутрапе ксс файл в котором были правки небыл прописан. всё работает
Иван
Работает отлично. Спасибо. Про Font Awesome я не знал. Подключил. Работает отлично.
admin
Рад, что все получилось.
pasha526
Вставим
после этого у меня появилась только надпись Вид:
файл заготовку скачивал и заменял
admin
В примере для иконок используются иконочный шрифт http://fontawesome.io/icons/
Установите его на сайт либо замените в
теги i на картинки
pasha526
установил на себе на сайт, появились
благодарю
admin
Отлично.
Алексей
Спасибо за статью! Всё очень доходчиво объяснил.
Но есть один момент...
Если на странице используется AJAX (например фильтр товаров), то выбранный вид не запоминается.
Ещё надо добавить обработчик событию:
вместо:
что-то типа этого:
vskuchmak
добрый день, файл с изменениями не выкладывали? (в начале статьи это с bs?)
admin
Здравствуйте!
В начале статье только заголовка шаблона товаров в категории(в bootstrap), файлов со всеми правками не выкладывал.
Алексей
Здравствуйте. Все замечательно, отлично работает, спасибо. Но вот я бы хотел сделать так, чтобы начальное было list, а не grid. Если я меняю все так, как я считаю должно работать, то у меня не сохраняется в при перелистывании страниц))) Подскажите, пожалуйста, как надо сделать и что изменить, чтобы работало, сохранялось в памяти при переходе на страницы, но изначально было list?
admin
Здравствуйте!
Код вывода кнопок замените на
скрипт замените на
в файле /components/com_virtuemart/sublayouts/products.php замените
на
Алексей
Спасибо большое. Помогло. И отдельное спасибо за оперативность 😉
admin
Рад, что проблема решилась.
Mdmax
Добрый день. Подскажите, пожалуйста, как прописать класс, что бы при отображении плиткой краткое описание не выводилось, а только в списке?
admin
Здравствуйте!
Нужно скрывать с помощью css. Чтобы точно ответить пришлите ссылку на сайт.
Mdmax
Ссылка на сайт - https://aqua-filter.net.ua/filtry-dlya-vody/filtry-dlya-pitevoi-vody/filtry-obratnogo-osmosa
admin
Попробуйте эти стили
Mdmax
Прошу прощения, что немного наспамил. Просто при отправке у вас на сайте система антиспама мои сообщения с ссылкой воспринимала как спам.
vladimirwk
Все получилось. Но интересует один вопрос, как сделать чтобы к примеру на главной странице по умолчанию выводилось плиткой, а на остальных списком? А то как то не очень выглядит когда все везде одинаково. Спасибо.
admin
Нужно усложнять скрипт, добавляя дополнительную переменную, которая будет запоминать и изменять вид на главной странице. Пошагово не смогу сказать, нужно пробовать непосредственно на сайте. Обратитесь на фриланс или напишите на admin@virtuemart.su
vladimirwk
Мне нужно чтобы на главной странице вообще ничего не менялось, чтобы какой задан шаблон в настройках Virtuemart, такой он и оставался. Дело в том что на страницах категорий у меня по умолчанию выводится списком. Нужно просто чтобы главная страница не обрабатывалась.
vladimirwk
Проблема решилась, просто создал отдельные шаблоны (макет и подмакет) для главной страницы и выбрал их в настройках меню главной страницы.
admin
Хорошо.
Алексей
Спасибо за статью! Есть примечание:
При таком подходе (при посещении следующих страниц с сохранением режима list) сначала страница загружается с режимом "grid" и только спустя некоторое время режим меняется средствами jQuery на "list". Происходит кратковременное "мигание", "дёргание" страницы.
Может быть, всё-таки использовать cookie и сразу в PHP проверять куку и дописывать диву класс, Ваше мнение?
Значение localStorage, насколько я понимаю, использовать в PHP не получится.
admin
Думал об этом пару дней назад, пожалуй такой вариант будет более предпочтителен если мигание сильно заметно. Готового кода не смогу выложить, нужно дополнительно разбираться.
Если получится решить, пожалуйста, поделитесь.
Алексей
Да, сделал. Делюсь.
Основываясь на предложенный Вами принцип сделал даже не 2, а 3 варианта вывода: плитка, список, таблица.
CSS приводить не буду, т.к. это довольно индивидуально, html-разметку тоже. Наверняка, большинство при желании с этим разберутся.
Что касается PHP, в шаблоне категории где начинается :
добавил
(если есть кука product_view, то дописываем этому диву ещё один класс с названием режима, например, "list-view")
В этом же файле ниже, где хотим вывести кнопки переключения режимов
(я сделал внутри блока с выбором кол-ва товаров на странице):
(добавил это прямо между vmPagination->getResultsCounter ();?> И vmPagination->getLimitBox ($this->category->limit_list_step); ?>)
Java скрипт сделал смешанным: jQuery и нативный, чтобы не подключать дополнительную библиотеку для использования cookie через jQuery.
И прописал скрипт не прямо в коде страницы, как предложено выше, а в своём кастомном файлике, подключаемом перед
body
:Работает чётко, никаких мерцаний, получилось, на мой взгляд, классно. Правда 3 вариант (табличный) ещё не до конца оформил, ну это мелочь, завтра доделаю.
admin
Спасибо, что поделились решением!
Алексей
Минут 20 писал комментарий со своим решением. В итоге нажал Отправить, но Ваш сайт счёт, что это "похоже на спам" и, судя по всему, комментарий не отправлен... Жаль. Писать тоже самое сначала пока что желания нет, может как-нибудь потом 🙂
admin
Такое бывает, я опубликовал коммент выше, весь код там есть.