Virtuemart 2 – фильтр \ поиск по характеристикам товаров
Задача: создать для Виртумарта поисковый фильтр по размерам одежды в интернет-магазине: одежда для беременных и кормящих мам (Joomla 2.5).
Открываем файл \administrator\components\com_virtuemart\models\product.php
Находим в нем следующий код и заменяем на наш.
if (!empty($this->searchcustoms)){
$joinCustom = true ;
....
}
<?php
if (!empty($this->searchcustoms)){
$joinCustom = true ;
foreach ($this->searchcustoms as $key => $searchcustom) {
if($searchcustom=trim($searchcustom))
$custom_search[] = '(pf.`virtuemart_custom_id`="'.(int)$key.'" and pf.`custom_value` like "' . $this->_db->getEscaped( $searchcustom, true ) . '")';
}
if(count($custom_search)) $where[] = " ( ".implode(' OR ', $custom_search )." ) ";
else{
$joinCustom=false;
$this->searchcustoms=false;
}
}
?>
Дальше открываем файл \components\com_virtuemart\views\category\tmpl\default.php
Находим строку <div class="orderby-displaynumber"> и после нее заменяем этот код <div class="width70 floatleft">...</div> на наш:
<?php
/*
Делаем выборку из таблицы #__virtuemart_product_customfields всех размеров одежды virtuemart_custom_id=9, ID поля можно посмотреть тут:
Virtuemart -> Товары -> Настраиваемые поля -> смотрим первую колонку, это ID записи, в нашем случаи это «Размер одежды», тип поля «Атрибут корзины».
*/
$razmery='';
$db=JFactory::getDbo();
$db->setQuery('SELECT DISTINCT(custom_value) AS razmer FROM #__virtuemart_product_customfields WHERE virtuemart_custom_id=9');
$res=$db->loadObjectList();
if(is_array($res) && count($res)){
//Массив Размеров
$a=array(0=>'Любой');
//Заносим данные из таблицы в массив Размеров
foreach($res as $v) $a[$v->razmer]=$v->razmer;
//Сортируем
ksort($a);
//Получаем значение выбранного размера одежды из запроса пользователя
$razmer=JRequest::getvar('customfields', null);
$razmer=(isset($razmer[9])) ? $razmer[9] : 0;
//Этот размер помещаем в начале массива
if($razmer && isset($a[$razmer])){
$x=array( $razmer=>'' );
foreach($a as $k => $v) $x[$k]=$v;
$a=$x;
}else $razmer=0;
//Создаем фильтр по размерам одежды
$razmery='<div class="orderlistcontainer"><div class="title">Выбрать размер</div>';
$flag=false;
foreach($a as $k => $v){
if((string)$k==(string)$razmer) $x='<div class="activeOrder">';
else{
if(!$flag){
$x='<div class="orderlist"><div>';
$flag=true;
}else $x='<div>';
}
$razmery.=$x.'<a href="'.JRoute::_('index.php?option=com_virtuemart&view=category&limitstart=0&virtuemart_category_id='.$this->category->virtuemart_category_id.(($k) ? '&customfields[9]='.$k : '')).'">'.$v.'</a></div>';
}
$razmery.='</div></div>';
}
?>
<div class="width70 floatleft">
<table border=0 cellpadding="0" cellspacing="0" style="margin:0;padding:0">
<tr><td>
<?php echo $this->orderByList['orderby']; ?>
<?php echo $this->orderByList['manufacturer']; ?>
</td><td>
<?php echo $razmery; ?>
</td></tr></table>
</div>
В продолжение темы поиска, была написана вторая статья: Поиск товаров в Virtuemart 2 по нескольким фильтрам.
Комментарии
Можете предоставить нам доступ к сайту (коду), чтобы локализовать проблему, поскольку так сложно сказать что-то конкретное в вашем случае.
Здравствуйте! Мы не стали изобретать велосипедов и воспользовались существующим сервисом http://share42.com/
В принципе, там всё просто. Если возникнут какие-то вопросы, обращайтесь. Поможем.
Ебираю
Код заменяю примерно на стр. 235.
Если этот блок не вставлять, то фильтр с размерами появляется.
Помогите решить проблему, пожалуйста.
убрать нужно полностью этот сегмент кода:
if (!empty($this->searchcustoms)){
$joinCustom = true ;
foreach ($this->searchcustoms as $key => $searchcustom) { /*…*/ }
if(count($custom_search)) /*…*/
else{ /*...*/ }
}
и новый код вставлять нужно без этого: скобка?php и ?скобка
ну и пишите тут ошибки, которые выдает PHP
Покажите или бросьте, пожалуйста, на мою почту код без сокрашения, который нужно заменить. Желательно номер строки, хоть примерно.
Да, правильно. На почту отправлено.
Спасибо огромное!
А возможно по аналогии добавить еще фильтры для других полей?
Да, все дальнейшие изменения идут только тут уже: \components\com_virtuemart\views\category\tmpl\default.php
Например, фильтр по цвету:
$color=’’;
тут идет код запроса в базу и создание фильтра
вывод echo $color;
Не могу побороть проблему - по умолчанию показывается весь список значений. После клика на нудном поле становится нормальным - выпадающим списком. При клике на ЛЮБОЙ - опять весь список.
//Создаем фильтр по жанрам
$janry='Выбрать жанр';
$flag=false;
foreach($a as $k => $v){
if($k==$janr) $x='';
else{
if(!$flag){
$x='';
$flag=true;
}else $x='';
}
$janry.=$x.''.$v.'';
}
$janry.='';
}
Попробуйте указать тип сравниваемых данных (string)
//Создаем фильтр по жанрам
$janry='Выбрать жанр';
$flag=false;
foreach($a as $k => $v){
if((string)$k==(string)$janr) $x='';
else{
if(!$flag){
$x='';
$flag=true;
}else $x='';
}
$janry.=$x.''.$v.'';
}
$janry.='';
}
Например, поместить код сюда:
if(preg_match('/\/(odezhda|detskaya)\-/i', $_SERVER['REQUEST_URI'])){
отсюда
$db=JFactory::getDbo();
досюда
$razmery.='</div></div>';
}
}
Для раздела Разное, уже фильтра нет:
http://mama-dama.com/magazin/31/raznoe.html
Нужно вставить в главную страницу следующий код (используя плагин Add PHP http://2v3.su/blog/web/35.html, либо mod_php):
$js = "jQuery(document).ready(function () {
jQuery('.orderlistcontainer').hover(
function() { jQuery(this).find('.orderlist').stop().show()},
function() { jQuery(this).find('.orderlist').stop().hide()}
)
});";
$document = JFactory::getDocument();
$document->addScriptDeclaration($js);
Далее идет код, приведенный в статье:
\components\com_virtuemart\views\category\tmpl\default.php
Из него нужно убрать вывод сортировки и производителей: $this->orderByList['orderby'], $this->orderByList['manufacturer'].
Спасибо за помощь. Скажите а я смогу с помощью этого кода сделать фильтр по нескольким полям?
//не тестировал, но вот так:
$results=array(9=>'Выбрать размер', 10=>'Выбрать цвет');
$customfields=array(9=>0, 10=>0);
$var=JRequest::getvar('customfields', null);
foreach($customfields as $custom_id => &$value){
if($var && !empty($var[$custom_id]))
$value='&customfields['.$custom_id.']='.$var[$custom_id];
else unset($customfields[$custom_id]);
}
foreach($results as $custom_id => &$result){
$ff=$customfields;
unset($ff[$custom_id]);
$ff=implode('', $ff);
$title=$result;
$result='';
/*
1) сюда нужно поместить код из статьи, начиная от $db=JFactory::getDbo(); до ?>
2) заменить все 9 на $custom_id, а переменную $razmery на $result;
3) заменить в статье текст: Выбрать размер на '.$title.'
4) после $this->category->virtuemart_category_id. добавить $ff.
*/
}
//Результат будет тут: $results[9] и $results[10]
Наверно не правильно сформулировал вопрос :). Да в результате появилось два поля, Но вильтр по ним работает оддельно, как сделать так что бы утбирался товар по двум условиям и по размеру и по цвету. Сейчас на поле фильтра получается активна ссылка и нажимая на нее я перехожу на фильтр только по одному параметру, а нужно как я уже сказал по двум. Буду очень признателен в помощи, уже весь нет облазил, а найти не могу. Спасибо!
Этот код и должен был по двум отбирать, при нажатии на Размер, фильтруется по размеру, который будет учитываться при клике на Цвет, уже в категории товаров. В переменной $ff должно было быть для Цвета: &customfields[9]=Размер, а для Размера, к ссылке фильтра JRoute прибавляться: &customfields[10]=Цвет.
все изменения идут тут \components\com_virtuemart\views\category\tmpl\default.php т.е. то что указано в статье вложить в цикл, который написан выше.
\administrator\components\com_virtuemart\models\product.php
а в этой строке: if(count($custom_search)) $where[] = " ( ".implode(' OR ', $custom_search )." ) "; можно заменить OR на AND
Если изменить так то вообще ничего не ищет, те запрос получается таким ВЫБРАТЬ costomfields с ИД 13 где costum_value = 32 И Красный и ноже самое для другого ид, Скажите что можно сделать. Спасибо
в фильтре выберите размер и цвет, или хоть что-то одно, в исходнике страницы найдите ссылки вида: для цвета ?customfields[9]=размер&customfields[10]=цвет и для размера ?customfields[10]=цвет&customfields[9]=размер. Скиньте, если они есть.
Также после этого блока в product.php
if (!empty($this->searchcustoms)){
тут код
}
впишите:
echo 'СКОБКА!--debug: '.var_export($where, true).'--СКОБКА';
чтобы посмотреть отладочную информацию внутри страницы.
отладочная информация выдала
в результате показались лиш товары гдеcustomfields [10]=1
отладочная информация выдала
Сделал ошибку в предыдущем посте
знак вопроса (?) может быть только один, после него идут разделители параметров амперсанды (&).
в отладочной информации var_export($where) должен быть SQL код.
Открываем файл \administrator\components\com_virtuemart\models\product.php
Находим в нем следующий код.
if (!empty($this->searchcustoms)){
$joinCustom = true ;
....
}
после него var_export($where);
Я уже написал выше что:
а в этой строке: if(count($custo m_search)) $where[] = " ( ".implode(' OR ', $custom_search )." ) "; заменить OR на AND
ссылка в выде
отладочная инфа
вообще ничего не показывает хотя товар такой есть
выправил ссылку на index.php?option=com_virtuemart&search=true&view=category&customfields[10]=2&customfields[4]=226&customfields[4]=226&customfields[10]=2
тоже ничего :(
http://foamart/index.php?option=com_virtuemart&search=true&view=category&customfields[10]=2&customfields[4]=226?customfields[4]=226&customfields[10]=2
то отладочная инфа имеет такой вид:
array ( 0 => ' ( (pf.`virtuemart_custom_id`="10" and pf.`custom_value` like "2") AND (pf.`virtuemart_custom_id`="4" and pf.`custom_value` like "226?customfields[4]=226") ) ', )
этого 226?customfields[4]=226 тут не должно быть, я выше написал, что нужно исправить ссылку.
если такой товар точно есть, тогда перед строкой в product.php
$product_ids = $this->exeSortSearchListQuery(2, $select, $joinedTables, $whereString, $groupBy, $orderBy, $this->filter_order_Dir, $nbrReturnProducts);
добавить:
echo $select.$joinedTables.$whereString.$groupBy.$orderBy;
и вывести SQL запрос полностью, затем поэкспериментировать с ним в таблице товаров в phpmyadmin
ноесли выполнить в phpmyadmin говорит
запрос правильный, просто при копировании в конце захватились лишние символы, удалите их в конце запроса. И поэкспериментируйте с этими значениями, пока не будет выдан товар в phpmyadmin: (pf.`virtuemart_custom_id`="10" and pf.`custom_value` like "2") AND (pf.`virtuemart_custom_id`="4" and pf.`custom_value` like "226")
Результат такой
MySQL returned an empty result set (i.e. zero rows). ( Query took 0.1220 sec )
те пусто
но в базе если сделать выборку по id товара то выдает
и тут все же нужно указывать OR а не AND
if(count($custom_search)) $where[] = " ( ".implode(' OR ', $custom_search )." ) ";
для эксперимента:
SELECT * FROM `jm75l_virtuemart_products_ru_ru` as l JOIN `jm75l_virtuemart_products` AS p using (`virtuemart_product_id`) LEFT JOIN `jm75l_virtuemart_product_customfields` as pf ON p.`virtuemart_product_id` = pf.`virtuemart_product_id` WHERE ( ( (pf.`virtuemart_custom_id`="10" and pf.`custom_value` like "2") OR (pf.`virtuemart_custom_id`="4" and pf.`custom_value` like "226") ) AND p.`published`="1") group by p.`virtuemart_product_id` ORDER BY p.virtuemart_product_id;
потом этот:
SELECT * FROM `jm75l_virtuemart_products_ru_ru` as l JOIN `jm75l_virtuemart_products` AS p using (`virtuemart_product_id`) LEFT JOIN `jm75l_virtuemart_product_customfields` as pf ON p.`virtuemart_product_id` = pf.`virtuemart_product_id` WHERE ( ( (pf.`virtuemart_custom_id`="10" and pf.`custom_value` = "2") OR (pf.`virtuemart_custom_id`="4" and pf.`custom_value` = "226") )) group by p.`virtuemart_product_id` ORDER BY p.virtuemart_product_id;
if (!empty($this->searchcustoms)){
$joinCustom = true ;
foreach ($this->searchcustoms as $key => $searchcustom) {
if($searchcustom=trim($searchcustom)){
$key=intval($key);
$custom_search[$key] = '(pf'.$key.'.`virtuemart_custom_id`="'.$key.'" and pf'.$key.'.`custom_value` like "' . $this->_db->getEscaped( $searchcustom, true ) . '")';
}
}
if(count($custom_search)) $where[] = " ( ".implode(' AND ', $custom_search )." ) ";
else{
$joinCustom=false;
$this->searchcustoms=false;
}
}
найти строку if ($this->searchcustoms) { и заменить:
if ($this->searchcustoms) {
foreach (array_keys($this->searchcustoms) as $key) {
$joinedTables .= ' LEFT JOIN `#__virtuemart_product_customfields` as pf'.$key.' ON p.`virtuemart_product_id` = pf'.$key.'.`virtuemart_product_id` ';
}
}
тестируйте, у меня просто под рукой нет товаров с различными параметрами.
и в первом и во втором варианте выводит только где `custom_value` = "226")
по верому ничего не выводит, по второму и все товары
если 10=2 и 4=226 относятся к товару 61, то и должна возвращаться одна строка товара, если других товаров нет.
Просто вариант с OR ищет товары по Размеру или Цвету, но не оба совпадения сразу. А вариант с AND, см выше, должен учитывать оба параметра.
т.е. вариант с AND ничего не выдал, тогда мне нужны ваши таблицы с товарами, для тестирования.
Если кидать сам запрос в базу выдается результат и по одному и по второму полю отдельно, что здесть можно сделать? Я понимаю что оно ищет совподение в одной строке а не по всей таблице? Или сделать отдельный запрос в базу где прощитать самому какие кей передать и все, только накручено получится к:)
хоть сюда или на почту, в контактах есть почта для сайтов.
хорошо, но тут mail [@] 2v3.su пока нет. Тогда можно загрузить на майл или rghost.ru и скинуть ссылку на почту.
Цитата Отдел разработки сайтов
посте я просто правильно не сделал второй пункт, и все получилось, еще раз спасибо
Cкажите пожалуйста, можно ли сделать выборку чтобы к конкретным категориям показывались конкретные размеры? из одного поля "размер"
Т.к. у меня сайт предусматривает что у одних товаров показан размер, у других длина, у третих - рост. А мне не нужно чтобы там где размер (M,L,XL) выводился рост (181см., 205см.)...
Зарание благодарен))
http://2v3.su/blog/web/72.html#comment-79
$results=$customfields=array();
if(preg_match('#/odezhda#i', $_SERVER['REQUEST_URI'])){
$results=array( 4=>'Выбрать размер', 10=>'Выбрать цвет');
$customfields=a rray(4=>0, 10=>0);
}elseif(preg_match('#/obuv#i', $_SERVER['REQUEST_URI'])){
$results=array( 5=>'Выбрать размер обуви');
$customfields=array(5=>0);
}
Что касается общего поля Размер, то тут только фильтровать через сравнение, приблизительно так:
$flag_odezhda=preg_match('#/odezhda#i', $_SERVER['REQUEST_URI']);
$flag_obuv=preg_match('#/obuv#i', $_SERVER['REQUEST_URI']);
foreach($res as $v){
if($flag_odezhda && $v->razmer < 100){
$a[$v->razmer]=$v->razmer;
}elseif($flag_obuv && $v->razmer < 50){
$a[$v->razmer]=$v->razmer;
}
}
Спасибо большое. Немного доработал, но в целом именно оно))
Только почему-то не вводится последовательность категорий (от "Первой" до "Десятой" применяем один фильтр)... Пришлось отдельно под каждую категорию Риджест_УРЛ писать.
Может есть какая-то возможно по АйДи, например, добавить?
да, например:
$flag_odezhda=($_REQUEST['virtuemart_category_id']==1);
$flag_obuv=($_REQUEST['virtuemart_category_id']==2);
или если много
$flag_odezhda=in_array($_REQUEST['virtuemart_category_id'], array(1,3,5));
$flag_obuv=in_array($_REQUEST['virtuemart_category_id'], array(2,4,6));
если кратко, то:
открыть файл \administrator\components\com_virtuemart\models\product.php
перед строкой:
if($onlyPublished){ $where[] = ' p.`published`="1" '; }
вставить:
if($useCore && !empty($this->keyword)){
$keyword = '"%' . $this->_db->getEscaped($this->keyword, true) . '%"';
$where[]='pf.`custom_value` like '.$keyword;
if(!$this->searchcustoms) $this->searchcustoms=true;
if(!$groupBy) $groupBy = 'group by p.`virtuemart_product_id`';
}
этот код при стандартном поиске (название, описание и т.д.), дополнительно проверяет еще настраиваемые поля.
в том же файле, перед строкой: return $product_ids;
добавьте:
echo $select . $joinedTables . $whereString . $groupBy . $orderBy;
чтобы посмотреть сформированный запрос, сюда его.
перед строкой if(!empty($filter_search)){
это:
$filter_search[]='pf.`custom_value` like '.$keyword;
а перед if($onlyPublished){ $where[] = ' p.`published`="1" '; }
это:
if(!empty($filter_search) && !$this->searchcustoms)
$this->searchcustoms=true;
посидел немного поэкспериментировал и в строчке
$razmery.=$x.''.$v.'';
вставил в переменную customfields[3] значение 3 и все заработало... правильно я все сделал?
Если все работает, то значит правильно. Вот еще вариант реализации: http://2v3.su/blog/web/72.html
Т.е. все сделано как тут http://2v3.su/blog/web/72.html и второго поля все равно нет?
если честно немного затупил.. извените..
Еще один встречный вопрос а как можно сделать фльрацию по цене?
Опять же если кратко:
<form action="index.php" method="get">
Цена от <input type="text" name="product_price1" /> до <input type="text" name="product_price2" />
<input type="hidden" name="limitstart" value="0" />
<input type="hidden" name="option" value="com_virtuemart" />
<input type="hidden" name="view" value="category" />
<input type="submit" value="Найти" />
</form>
В файле \administrator\components\com_virtuemart\models\product.php
перед if ($virtuemart_category_id>0) добавить:
$product_price1 =JRequest::getInt('product_price1',0);
$product_price2 =JRequest::getInt('product_price2',0);
if($product_price1) $where[] = 'pp.`product_price` >='. $product_price1;
if($product_price2) $where[] = 'pp.`product_price` <='. $product_price2;
if($product_price1 || $product_price2) $joinPrice=true;
Благодорю вас за помощь, у меня клиент обьявился по поводу создания наподобии букмектерской конторы.. я дал ваш сайт и сказал чтобы он к вам обратился по этому поводу.
В файле \administrator\components\com_virtuemart\models\product.php нет такой у меня проверки вообще if ($virtuemart_category_id>0)
Надо было указать версию виртумарта. Можно тогда вставить в районе следующего кода:
if($onlyPublished){
$where[] = ' p.`published`="1" ';
}
и такого нет... у меня версия стоит 2.0.8e
специально пришлось выкачать эту версию, как и предполагалось, там есть и то и другое, А поискать можно было хотя бы по словам: $virtuemart_category_id или $onlyPublished
ну там по всему коду эти переменные разбросаны... а нужно же вставлять в определенное какое то место!
а для чего спрашивается выдержки из кода, для локализации места вставки:
if ($onlyPublished) {
$where[] = ' p.`published`="1" ';
}
или
if ($virtuemart_category_id > 0) {
А так же не могу понять почему через фильтр не выводятся те товары, в которых прописан данный размер.
Спасибо за ответ. Всех с наступающим.
В статье описываются изменения, которые требуются для создания фильтра, все прочее, предполагает самостоятельные доработки. Помимо фильтра в код вносились дополнительные модификации: http://2v3.su/src/blog/web/blog72.zip
Цитата Павел
Если все сделано верно, то товары должны были быть. Можете попробовать другой вариант:
http://2v3.su/blog/web/72.html
Фильтр для виртумарт 1.9 не делали, так что уточните детали ТЗ и отправьте нам на почту.
У меня код сработал, но при выборе размера virtuemart тормозит и даже когда добавляю новые товары они очень поздно появляются на сайт. В чем проблема?
Заранее спасибо!
Проблема может быть связана с хостингом на котором расположен сайт или же со скоростью работы вашего интернета. Если сайт расположен на локальном компьютере, то тогда причина может быть в производительности компьютера (его загруженности) или в настройках mysql-сервера. Причин много, так сразу и не ответить...
Скажем так, я подсказываю то, что знаю, и там где не требуется затрачивать много времени, потому что у меня тоже заказы и сроки, времени всегда не хватает, даже статей пока новых по виртумарту не пишу.
Цитата Narek
Если возможно, то скиньте ссылку на портфолио сюда или на почту, поскольку у нас нет постоянного дизайнера, в основном делаем на шаблонах, так что, ваши услуги могут пригодиться, за деньги, разумеется.
В принципе тут расписано все, и тем более вы позиционируете себя как веб-студия, должны немного ориентироваться в коде. Если уж совсем никак, то тут только платно.
попробуйте сделать так: заменить $a=array(0=>'Любой'); на $a=array();
после ksort($a); вставить $a=array_merge(array(0=>'Любой'), $a);
Выше двух товаров выводит стандартную сортировку а провее от нее написано слово "Аксесуары" Наведите на аксесуары и увидите что список выподает но изночально он отображается не так как нужно.. увидели?
Да, я сразу не заметил, и отредактировал предыдущее сообщение.
Большое спасибо. У меня своя мини студия. если нужна помощь будет при верстке, создании дизайна образайтесь поможем с удовольствием!
Сейчас напишу вам на почту, есть вопрос по вашим ценам.
будем рады сотрудничеству!
Вот пример http://2v3.su/src/blog/web/blog72.zip изменения кода в скриптах, только не нужно заменять файлы поверх старых, могут быть нестыковки в версиях VM.
Если на хостинге запрещен вывод php-ошибок в браузер, то посмотрите лог-файлы, и скопируйте ошибку сюда, скорее всего у вас допущена неточность в синтаксисе.
Подсказываю бесплатно, но работы от 500 руб.
Ктонибудь пробовал тестить на Joomla! 2.5.14 и VM 2.0.24? Оч полезная статья, но на указаных версиях не получается настроить, отпишитесь если у кого получилось или кто может помочь.
На VM 2.0.24 не тестировал, но должно работать. Внимательнее вносите корректировки. Для просмотра вставок, вот пример http://2v3.su/src/blog/web/blog72.zip (поверх копировать не нужно).
В верхнем сообщении же есть пример: http://2v3.su/src/blog/web/blog72.zip
Поиск по производителю это стандартный функционал виртумарта: Виртумарт – Настройки – Шаблоны – отметить Показывать производителей.
Что касается вывода категорий производителей, то вроде бы, они не выводятся стандартным образом, да и зачем, если есть категории товаров. Но если у вас нестандартная задача, то уже могу сделать в индивидуальном порядке.
только не так $joinedTables .=
а так $joinedTables[] =
спасибо получилось тоже
Ну, хорошо, что получилось. Что касается $joinedTables, то виртумарт от версии к версии изменяется, для новых, да, нужно добавлять в массив $joinedTables[].
Белый экран, это из-за какой-то ошибки, которую нужно смотреть в логах хостинга.