0byt3m1n1 - D7net
0byt3m1n1 - D7net
Path:
/
home
/
s13cf5ef
/
www
/
pshoptuscamisetaspersonalizadas
/
modules
/
blocklayered
/
[
Home
]
Name File: blocklayered.php
< back
<?php /* * 2007-2013 PrestaShop * * NOTICE OF LICENSE * * This source file is subject to the Academic Free License (AFL 3.0) * that is bundled with this package in the file LICENSE.txt. * It is also available through the world-wide-web at this URL: * http://opensource.org/licenses/afl-3.0.php * If you did not receive a copy of the license and are unable to * obtain it through the world-wide-web, please send an email * to license@prestashop.com so we can send you a copy immediately. * * DISCLAIMER * * Do not edit or add to this file if you wish to upgrade PrestaShop to newer * versions in the future. If you wish to customize PrestaShop for your * needs please refer to http://www.prestashop.com for more information. * * @author PrestaShop SA <contact@prestashop.com> * @copyright 2007-2013 PrestaShop SA * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0) * International Registred Trademark & Property of PrestaShop SA */ if (!defined('_PS_VERSION_')) exit; class BlockLayered extends Module { private $products; private $nbr_products; private $page = 1; public function __construct() { $this->name = 'blocklayered'; $this->tab = 'front_office_features'; $this->version = '1.8.9'; $this->author = 'PrestaShop'; $this->need_instance = 0; parent::__construct(); $this->displayName = $this->l('Layered navigation block'); $this->description = $this->l('Displays a block with layered navigation filters.'); if ((int)Tools::getValue('p')) $this->page = (int)Tools::getValue('p'); } public function install() { if (parent::install() && $this->registerHook('leftColumn') && $this->registerHook('header') && $this->registerHook('footer') && $this->registerHook('categoryAddition') && $this->registerHook('categoryUpdate') && $this->registerHook('attributeGroupForm') && $this->registerHook('afterSaveAttributeGroup') && $this->registerHook('afterDeleteAttributeGroup') && $this->registerHook('featureForm') && $this->registerHook('afterDeleteFeature') && $this->registerHook('afterSaveFeature') && $this->registerHook('categoryDeletion') && $this->registerHook('afterSaveProduct') && $this->registerHook('productListAssign') && $this->registerHook('postProcessAttributeGroup') && $this->registerHook('postProcessFeature') && $this->registerHook('featureValueForm') && $this->registerHook('postProcessFeatureValue') && $this->registerHook('afterDeleteFeatureValue') && $this->registerHook('afterSaveFeatureValue') && $this->registerHook('attributeForm') && $this->registerHook('postProcessAttribute') && $this->registerHook('afterDeleteAttribute') && $this->registerHook('afterSaveAttribute')) { Configuration::updateValue('PS_LAYERED_HIDE_0_VALUES', 1); Configuration::updateValue('PS_LAYERED_SHOW_QTIES', 1); Configuration::updateValue('PS_LAYERED_FULL_TREE', 1); Configuration::updateValue('PS_LAYERED_FILTER_PRICE_USETAX', 1); Configuration::updateValue('PS_LAYERED_FILTER_CATEGORY_DEPTH', 1); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_QTY', 0); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CDT', 0); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_MNF', 0); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CAT', 0); $this->rebuildLayeredStructure(); $products_count = Db::getInstance()->getValue('SELECT COUNT(*) FROM `'._DB_PREFIX_.'product`'); if ($products_count < 20000) // Lock template filter creation if too many products $this->rebuildLayeredCache(); self::installPriceIndexTable(); $this->installFriendlyUrlTable(); $this->installIndexableAttributeTable(); $this->installProductAttributeTable(); if ($products_count < 5000) // Lock indexation if too many products { $this->indexUrl(); $this->indexAttribute(); self::fullPricesIndexProcess(); } return true; } else { // Installation failed (or hook registration) => uninstall the module $this->uninstall(); return false; } } public function uninstall() { /* Delete all configurations */ Configuration::deleteByName('PS_LAYERED_HIDE_0_VALUES'); Configuration::deleteByName('PS_LAYERED_SHOW_QTIES'); Configuration::deleteByName('PS_LAYERED_FULL_TREE'); Configuration::deleteByName('PS_LAYERED_INDEXED'); Configuration::deleteByName('PS_LAYERED_FILTER_PRICE_USETAX'); Configuration::deleteByName('PS_LAYERED_FILTER_CATEGORY_DEPTH'); Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_QTY'); Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_CDT'); Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_MNF'); Configuration::deleteByName('PS_LAYERED_FILTER_INDEX_CAT'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_price_index'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_friendly_url'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_attribute_group'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_feature'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_indexable_feature_lang_value'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_category'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_filter'); Db::getInstance()->Execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_filter_shop'); Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_product_attribute'); return parent::uninstall(); } private static function installPriceIndexTable() { Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_price_index`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_price_index` ( `id_product` INT NOT NULL, `id_currency` INT NOT NULL, `id_shop` INT NOT NULL, `price_min` INT NOT NULL, `price_max` INT NOT NULL, PRIMARY KEY (`id_product`, `id_currency`, `id_shop`), INDEX `id_currency` (`id_currency`), INDEX `price_min` (`price_min`), INDEX `price_max` (`price_max`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); } private function installFriendlyUrlTable() { Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_friendly_url`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_friendly_url` ( `id_layered_friendly_url` INT NOT NULL AUTO_INCREMENT, `url_key` varchar(32) NOT NULL, `data` varchar(200) NOT NULL, `id_lang` INT NOT NULL, PRIMARY KEY (`id_layered_friendly_url`), INDEX `id_lang` (`id_lang`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); Db::getInstance()->execute('CREATE INDEX `url_key` ON `'._DB_PREFIX_.'layered_friendly_url`(url_key(5))'); } private function installIndexableAttributeTable() { // Attributes Groups Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_group`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_group` ( `id_attribute_group` INT NOT NULL, `indexable` BOOL NOT NULL DEFAULT 0, PRIMARY KEY (`id_attribute_group`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'layered_indexable_attribute_group` SELECT id_attribute_group, 1 FROM `'._DB_PREFIX_.'attribute_group`'); Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_group_lang_value`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_group_lang_value` ( `id_attribute_group` INT NOT NULL, `id_lang` INT NOT NULL, `url_name` VARCHAR(20), `meta_title` VARCHAR(20), PRIMARY KEY (`id_attribute_group`, `id_lang`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); // Attributes Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_attribute_lang_value`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_attribute_lang_value` ( `id_attribute` INT NOT NULL, `id_lang` INT NOT NULL, `url_name` VARCHAR(20), `meta_title` VARCHAR(20), PRIMARY KEY (`id_attribute`, `id_lang`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); // Features Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature` ( `id_feature` INT NOT NULL, `indexable` BOOL NOT NULL DEFAULT 0, PRIMARY KEY (`id_feature`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'layered_indexable_feature` SELECT id_feature, 1 FROM `'._DB_PREFIX_.'feature`'); Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature_lang_value`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature_lang_value` ( `id_feature` INT NOT NULL, `id_lang` INT NOT NULL, `url_name` VARCHAR(20) NOT NULL, `meta_title` VARCHAR(20), PRIMARY KEY (`id_feature`, `id_lang`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); // Features values Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_indexable_feature_value_lang_value`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_indexable_feature_value_lang_value` ( `id_feature_value` INT NOT NULL, `id_lang` INT NOT NULL, `url_name` VARCHAR(20), `meta_title` VARCHAR(20), PRIMARY KEY (`id_feature_value`, `id_lang`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); } /** * * create table product attribute */ public function installProductAttributeTable() { Db::getInstance()->execute('DROP TABLE IF EXISTS `'._DB_PREFIX_.'layered_product_attribute`'); Db::getInstance()->execute(' CREATE TABLE `'._DB_PREFIX_.'layered_product_attribute` ( `id_attribute` int(10) unsigned NOT NULL, `id_product` int(10) unsigned NOT NULL, `id_attribute_group` int(10) unsigned NOT NULL DEFAULT "0", `id_shop` int(10) unsigned NOT NULL DEFAULT "1", KEY `id_attribute` (`id_attribute`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); } /** * * Generate data product attribute */ public function indexAttribute($id_product = null) { if (is_null($id_product)) Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_product_attribute'); else Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_product_attribute WHERE id_product = '.(int)$id_product); Db::getInstance()->execute('INSERT INTO `'._DB_PREFIX_.'layered_product_attribute` (`id_attribute`, `id_product`, `id_attribute_group`, `id_shop`) SELECT pac.id_attribute, pa.id_product, ag.id_attribute_group, '.(version_compare(_PS_VERSION_,'1.5','>') ? 'product_attribute_shop.`id_shop`' : '1').' FROM '._DB_PREFIX_.'product_attribute pa '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product_attribute', 'pa') : '').' INNER JOIN '._DB_PREFIX_.'product_attribute_combination pac ON pac.id_product_attribute = pa.id_product_attribute INNER JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute = pac.id_attribute) INNER JOIN '._DB_PREFIX_.'attribute_group ag ON ag.id_attribute_group = a.id_attribute_group '.(is_null($id_product) ? '' : 'AND pa.id_product = '.(int)$id_product).' GROUP BY a.id_attribute, pa.id_product '.(version_compare(_PS_VERSION_,'1.5','>') ? ', product_attribute_shop.`id_shop`' : '')); return 1; } /* * Url indexation */ public function indexUrl($ajax = false, $truncate = true) { if ($truncate) Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_friendly_url'); $attribute_values_by_lang = array(); $filters = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT lc.*, id_lang, name, link_rewrite, cl.id_category FROM '._DB_PREFIX_.'layered_category lc INNER JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = lc.id_category AND lc.id_category <> 1 ) GROUP BY type, id_value, id_lang'); if (!$filters) return; foreach ($filters as $filter) switch ($filter['type']) { case 'id_attribute_group': $attributes = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT agl.public_name name, a.id_attribute_group id_name, al.name value, a.id_attribute id_value, al.id_lang, liagl.url_name name_url_name, lial.url_name value_url_name FROM '._DB_PREFIX_.'attribute_group ag INNER JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (agl.id_attribute_group = ag.id_attribute_group) INNER JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute_group = ag.id_attribute_group) INNER JOIN '._DB_PREFIX_.'attribute_lang al ON (al.id_attribute = a.id_attribute) LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group liag ON (liag.id_attribute_group = a.id_attribute_group) LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value liagl ON (liagl.id_attribute_group = ag.id_attribute_group AND liagl.id_lang = '.(int)$filter['id_lang'].') LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial ON (lial.id_attribute = a.id_attribute AND lial.id_lang = '.(int)$filter['id_lang'].') WHERE a.id_attribute_group = '.(int)$filter['id_value'].' AND agl.id_lang = al.id_lang AND agl.id_lang = '.(int)$filter['id_lang']); foreach ($attributes as $attribute) { if (!isset($attribute_values_by_lang[$attribute['id_lang']])) $attribute_values_by_lang[$attribute['id_lang']] = array(); if (!isset($attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']])) $attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']] = array(); $attribute_values_by_lang[$attribute['id_lang']]['c'.$attribute['id_name']][] = array( 'name' => (!empty($attribute['name_url_name']) ? $attribute['name_url_name'] : $attribute['name']), 'id_name' => 'c'.$attribute['id_name'], 'value' => (!empty($attribute['value_url_name']) ? $attribute['value_url_name'] : $attribute['value']), 'id_value' => $attribute['id_name'].'_'.$attribute['id_value'], 'id_id_value' => $attribute['id_value'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } break; case 'id_feature': $features = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT fl.name name, fl.id_feature id_name, fvl.id_feature_value id_value, fvl.value value, fl.id_lang, fl.id_lang, lifl.url_name name_url_name, lifvl.url_name value_url_name FROM '._DB_PREFIX_.'feature_lang fl LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature lif ON (lif.id_feature = fl.id_feature) INNER JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature = fl.id_feature) INNER JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fv.id_feature_value) LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_lang_value lifl ON (lifl.id_feature = fl.id_feature AND lifl.id_lang = '.(int)$filter['id_lang'].') LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_value_lang_value lifvl ON (lifvl.id_feature_value = fvl.id_feature_value AND lifvl.id_lang = '.(int)$filter['id_lang'].') WHERE fl.id_feature = '.(int)$filter['id_value'].' AND fvl.id_lang = fl.id_lang AND fvl.id_lang = '.(int)$filter['id_lang']); foreach ($features as $feature) { if (!isset($attribute_values_by_lang[$feature['id_lang']])) $attribute_values_by_lang[$feature['id_lang']] = array(); if (!isset($attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']])) $attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']] = array(); $attribute_values_by_lang[$feature['id_lang']]['f'.$feature['id_name']][] = array( 'name' => (!empty($feature['name_url_name']) ? $feature['name_url_name'] : $feature['name']), 'id_name' => 'f'.$feature['id_name'], 'value' => (!empty($feature['value_url_name']) ? $feature['value_url_name'] : $feature['value']), 'id_value' => $feature['id_name'].'_'.$feature['id_value'], 'id_id_value' => $feature['id_value'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } break; case 'category': $categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT cl.name, cl.id_lang, c.id_category FROM '._DB_PREFIX_.'category c INNER JOIN '._DB_PREFIX_.'category_lang cl ON (c.id_category = cl.id_category) WHERE cl.id_lang = '.(int)$filter['id_lang']); foreach ($categories as $category) { if (!isset($attribute_values_by_lang[$category['id_lang']])) $attribute_values_by_lang[$category['id_lang']] = array(); if (!isset($attribute_values_by_lang[$category['id_lang']]['category'])) $attribute_values_by_lang[$category['id_lang']]['category'] = array(); $attribute_values_by_lang[$category['id_lang']]['category'][] = array('name' => $this->translateWord('Categories', $category['id_lang']), 'id_name' => null, 'value' => $category['name'], 'id_value' => $category['id_category'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } break; case 'manufacturer': $manufacturers = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT m.name as name,l.id_lang as id_lang, id_manufacturer FROM '._DB_PREFIX_.'manufacturer m , '._DB_PREFIX_.'lang l WHERE l.id_lang = '.(int)$filter['id_lang'].' '); foreach ($manufacturers as $manufacturer) { if (!isset($attribute_values_by_lang[$manufacturer['id_lang']])) $attribute_values_by_lang[$manufacturer['id_lang']] = array(); if (!isset($attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer'])) $attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer'] = array(); $attribute_values_by_lang[$manufacturer['id_lang']]['manufacturer'][] = array('name' => $this->translateWord('Manufacturer', $manufacturer['id_lang']), 'id_name' => null, 'value' => $manufacturer['name'], 'id_value' => $manufacturer['id_manufacturer'], 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); } break; case 'quantity': $avaibility_list = array( $this->translateWord('Not available', (int)$filter['id_lang']), $this->translateWord('In stock', (int)$filter['id_lang']) ); foreach ($avaibility_list as $key => $quantity) $attribute_values_by_lang[$filter['id_lang']]['quantity'][] = array('name' => $this->translateWord('Availability', (int)$filter['id_lang']), 'id_name' => null, 'value' => $quantity, 'id_value' => $key, 'id_id_value' => 0, 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); break; case 'condition': $condition_list = array( 'new' => $this->translateWord('New', (int)$filter['id_lang']), 'used' => $this->translateWord('Used', (int)$filter['id_lang']), 'refurbished' => $this->translateWord('Refurbished', (int)$filter['id_lang']) ); foreach ($condition_list as $key => $condition) $attribute_values_by_lang[$filter['id_lang']]['condition'][] = array('name' => $this->translateWord('Condition', (int)$filter['id_lang']), 'id_name' => null, 'value' => $condition, 'id_value' => $key, 'category_name' => $filter['link_rewrite'], 'type' => $filter['type']); break; } // Foreach langs foreach ($attribute_values_by_lang as $id_lang => $attribute_values) { // Foreach attributes generate a couple "/<attribute_name>_<atttribute_value>". For example: color_blue foreach ($attribute_values as $attribute) foreach ($attribute as $param) { $selected_filters = array(); $link = '/'.str_replace('-', '_', Tools::link_rewrite($param['name'])).'-'.str_replace('-', '_', Tools::link_rewrite($param['value'])); $selected_filters[$param['type']] = array(); if (!isset($param['id_id_value'])) $param['id_id_value'] = $param['id_value']; $selected_filters[$param['type']][$param['id_id_value']] = $param['id_value']; $url_key = md5($link); $id_layered_friendly_url = Db::getInstance()->getValue('SELECT id_layered_friendly_url FROM `'._DB_PREFIX_.'layered_friendly_url` WHERE `id_lang` = '.$id_lang.' AND `url_key` = \''.$url_key.'\''); if ($id_layered_friendly_url == false) { Db::getInstance()->AutoExecute(_DB_PREFIX_.'layered_friendly_url', array('url_key' => $url_key, 'data' => serialize($selected_filters), 'id_lang' => $id_lang), 'INSERT'); $id_layered_friendly_url = Db::getInstance()->Insert_ID(); } } } if ($ajax) return '{"result": 1}'; else return 1; } public function translateWord($string, $id_lang ) { static $_MODULES = array(); global $_MODULE; $file = _PS_MODULE_DIR_.$this->name.'/'.Language::getIsoById($id_lang).'.php'; if (!array_key_exists($id_lang, $_MODULES)) { if (!file_exists($file)) return $string; include($file); $_MODULES[$id_lang] = $_MODULE; } $string = str_replace('\'', '\\\'', $string); // set array key to lowercase for 1.3 compatibility $_MODULES[$id_lang] = array_change_key_case($_MODULES[$id_lang]); $current_key = '<{'.strtolower( $this->name).'}'.strtolower(_THEME_NAME_).'>'.strtolower($this->name).'_'.md5($string); $default_key = '<{'.strtolower( $this->name).'}prestashop>'.strtolower($this->name).'_'.md5($string); if (isset($_MODULES[$id_lang][$current_key])) $ret = stripslashes($_MODULES[$id_lang][$current_key]); else if (isset($_MODULES[$id_lang][Tools::strtolower($current_key)])) $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($current_key)]); else if (isset($_MODULES[$id_lang][$default_key])) $ret = stripslashes($_MODULES[$id_lang][$default_key]); else if (isset($_MODULES[$id_lang][Tools::strtolower($default_key)])) $ret = stripslashes($_MODULES[$id_lang][Tools::strtolower($default_key)]); else $ret = stripslashes($string); return str_replace('"', '"', $ret); } public function hookProductListAssign($params) { global $smarty; if (version_compare(_PS_VERSION_,'1.5','<') && !Configuration::get('PS_LAYERED_INDEXED') || version_compare(_PS_VERSION_,'1.5','>') && !Configuration::getGlobalValue('PS_LAYERED_INDEXED')) return; // Inform the hook was executed $params['hookExecuted'] = true; // List of product to overrride categoryController $params['catProducts'] = array(); $selected_filters = $this->getSelectedFilters(); $filter_block = $this->getFilterBlock($selected_filters); $title = ''; if (is_array($filter_block['title_values'])) foreach ($filter_block['title_values'] as $key => $val) $title .= ' – '.$key.' '.implode('/', $val); $smarty->assign('categoryNameComplement', $title); $this->getProducts($selected_filters, $params['catProducts'], $params['nbProducts'], $p, $n, $pages_nb, $start, $stop, $range); // Need a nofollow on the pagination links? $smarty->assign('no_follow', $filter_block['no_follow']); } public function hookAfterSaveProduct($params) { if (!$params['id_product']) return; self::indexProductPrices((int)$params['id_product']); $this->indexAttribute((int)$params['id_product']); } public function hookAfterSaveFeature($params) { if (!$params['id_feature'] || Tools::getValue('layered_indexable') === false) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']); Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature VALUES ('.(int)$params['id_feature'].', '.(int)Tools::getValue('layered_indexable').')'); Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_lang_value WHERE id_feature = '.(int)$params['id_feature']); // don't care about the id_lang foreach (Language::getLanguages(false) as $language) { // Data are validated by method "hookPostProcessFeature" $id_lang = (int)$language['id_lang']; Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_lang_value VALUES ('.(int)$params['id_feature'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\', \''.pSQL(Tools::getValue('meta_title_'.$id_lang), true).'\')'); } } public function hookAfterSaveFeatureValue($params) { if (!$params['id_feature_value']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value WHERE id_feature_value = '.(int)$params['id_feature_value']); // don't care about the id_lang foreach (Language::getLanguages(false) as $language) { // Data are validated by method "hookPostProcessFeatureValue" $id_lang = (int)$language['id_lang']; Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_value_lang_value VALUES ('.(int)$params['id_feature_value'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\', \''.pSQL(Tools::getValue('meta_title_'.$id_lang), true).'\')'); } } public function hookAfterDeleteFeatureValue($params) { if (!$params['id_feature_value']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value WHERE id_feature_value = '.(int)$params['id_feature_value']); } public function hookPostProcessFeatureValue($params) { $this->hookPostProcessAttributeGroup($params); } public function hookFeatureValueForm($params) { $languages = Language::getLanguages(false); $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT')); $lang_value = array(); if (version_compare(_PS_VERSION_,'1.5','>')) $return = ' <script type="text/javascript"> flag_fields = \'\'; </script>'; else $return = ''; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value WHERE id_feature_value = '.(int)$params['id_feature_value']); if ($result) foreach ($result as $data) $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); $return .= '<div class="clear"></div> <label>'.$this->l('URL:').'</label> <div class="margin-form"> <script type="text/javascript"> flag_fields += \'¤url_name¤meta_title\'; </script> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" /> <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer"> </span></span> <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Meta title:').' </label> <div class="margin-form"> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" /> <p style="clear: both">'.$this->l('Specific format for meta title').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true); $return .= ' </div> <div class="clear"></div> </div>'; return $return; } public function hookAfterSaveAttribute($params) { if (!$params['id_attribute']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value WHERE id_attribute = '.(int)$params['id_attribute']); // don't care about the id_lang foreach (Language::getLanguages(false) as $language) { // Data are validated by method "hookPostProcessAttribute" $id_lang = (int)$language['id_lang']; Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_lang_value VALUES ('.(int)$params['id_attribute'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\', \''.pSQL(Tools::getValue('meta_title_'.$id_lang), true).'\')'); } } public function hookAfterDeleteAttribute($params) { if (!$params['id_attribute']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value WHERE id_attribute = '.(int)$params['id_attribute']); } public function hookPostProcessAttribute($params) { $this->hookPostProcessAttributeGroup($params); } public function hookAttributeForm($params) { $languages = Language::getLanguages(false); $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT')); $lang_value = array(); if (version_compare(_PS_VERSION_,'1.5','>')) $return = ' <script type="text/javascript"> flag_fields = \'\'; </script>'; else $return = ''; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_attribute_lang_value WHERE id_attribute = '.(int)$params['id_attribute']); if ($result) foreach ($result as $data) $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); $return .= '<div class="clear"></div> <label>'.$this->l('URL:').'</label> <div class="margin-form"> <script type="text/javascript"> flag_fields += \'¤url_name¤meta_title\'; </script> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" /> <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer"> </span></span> <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Meta title:').' </label> <div class="margin-form"> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" /> <p style="clear: both">'.$this->l('Specific format for meta title').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true); $return .= ' </div> <div class="clear"></div> </div>'; return $return; } public function hookPostProcessFeature($params) { $this->hookPostProcessAttributeGroup($params); } public function hookAfterDeleteFeature($params) { if (!$params['id_feature']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']); } public function hookAfterSaveAttributeGroup($params) { if (!$params['id_attribute_group'] || Tools::getValue('layered_indexable') === false) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE id_attribute_group = '.(int)$params['id_attribute_group']); Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group VALUES ('.(int)$params['id_attribute_group'].', '.(int)Tools::getValue('layered_indexable').')'); Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value WHERE id_attribute_group = '.(int)$params['id_attribute_group']); // don't care about the id_lang foreach (Language::getLanguages(false) as $language) { // Data are validated by method "hookPostProcessAttributeGroup" $id_lang = (int)$language['id_lang']; Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value VALUES ('.(int)$params['id_attribute_group'].', '.$id_lang.', \''.pSQL(Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang))).'\', \''.pSQL(Tools::getValue('meta_title_'.$id_lang), true).'\')'); } } public function hookPostProcessAttributeGroup($params) { // Limit to one call static $once = false; if ($once) return; $once = true; $errors = array(); foreach (Language::getLanguages(false) as $language) { $id_lang = $language['id_lang']; if (Tools::getValue('url_name_'.$id_lang)) if (Tools::link_rewrite(Tools::getValue('url_name_'.$id_lang)) != strtolower( Tools::getValue('url_name_'.$id_lang))) { // Here use the reference "errors" to stop saving process $params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), Tools::getValue('url_name_'.$id_lang))); } } } public function hookAfterDeleteAttributeGroup($params) { if (!$params['id_attribute_group']) return; Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE id_attribute_group = '.(int)$params['id_attribute_group']); Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value WHERE id_attribute_group = '.(int)$params['id_attribute_group']); } public function hookAttributeGroupForm($params) { $languages = Language::getLanguages(false); $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT')); $indexable = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT indexable FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE id_attribute_group = '.(int)$params['id_attribute_group']); $lang_value = array(); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value WHERE id_attribute_group = '.(int)$params['id_attribute_group']); if ($result) foreach ($result as $data) $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); if ($indexable === false) $on = true; else $on = (bool)$indexable; if (version_compare(_PS_VERSION_,'1.5','>')) $return = ' <script type="text/javascript"> flag_fields = \'\'; </script>'; else $return = ''; $return .= '<div class="clear"></div> <label>'.$this->l('URL:').'</label> <div class="margin-form"> <script type="text/javascript"> flag_fields += \'¤url_name¤meta_title\'; </script> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" /> <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer"> </span></span> <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Meta title:').' </label> <div class="margin-form"> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" /> <p style="clear: both">'.$this->l('Specific format for meta title').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Indexable:').' </label> <div class="margin-form"> <input type="radio" '.(($on) ? 'checked="checked"' : '').' value="1" id="indexable_on" name="layered_indexable"> <label for="indexable_on" class="t"><img title="Yes" alt="Enabled" src="../img/admin/enabled.gif"></label> <input type="radio" '.((!$on) ? 'checked="checked"' : '').' value="0" id="indexable_off" name="layered_indexable"> <label for="indexable_off" class="t"><img title="No" alt="Disabled" src="../img/admin/disabled.gif"></label> <p>'.$this->l('Use this attribute in URL generated by the layered navigation module').'</p> </div>'; return $return; } public function hookFeatureForm($params) { $languages = Language::getLanguages(false); $default_form_language = (int)(Configuration::get('PS_LANG_DEFAULT')); $indexable = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue('SELECT indexable FROM '._DB_PREFIX_.'layered_indexable_feature WHERE id_feature = '.(int)$params['id_feature']); $lang_value = array(); $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS( 'SELECT url_name, meta_title, id_lang FROM '._DB_PREFIX_.'layered_indexable_feature_lang_value WHERE id_feature = '.(int)$params['id_feature']); if ($result) foreach ($result as $data) $lang_value[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); if ($indexable === false) $on = true; else $on = (bool)$indexable; if (version_compare(_PS_VERSION_,'1.5','>')) $return = ' <script type="text/javascript"> flag_fields = \'\'; </script>'; else $return = ''; $return .= '<div class="clear"></div> <label>'.$this->l('URL:').'</label> <div class="margin-form"> <script type="text/javascript"> flag_fields += \'¤url_name¤meta_title\'; </script> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="url_name_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="url_name_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['url_name'], true).'" /> <span class="hint" name="help_box">'.$this->l('Invalid characters:').' <>;=#{}_<span class="hint-pointer"> </span></span> <p style="clear: both">'.$this->l('Specific URL format in block layered generation').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'url_name', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Meta title:').' </label> <div class="margin-form"> <div class="translatable">'; foreach ($languages as $language) $return .= ' <div class="lang_'.$language['id_lang'].'" id="meta_title_'.$language['id_lang'].'" style="display: '.($language['id_lang'] == $default_form_language ? 'block' : 'none').'; float: left;"> <input size="33" type="text" name="meta_title_'.$language['id_lang'].'" value="'.Tools::safeOutput(@$lang_value[$language['id_lang']]['meta_title'], true).'" /> <p style="clear: both">'.$this->l('Specific format for meta title').'</p> </div>'; if (version_compare(_PS_VERSION_,'1.5','<')) $return .= $this->displayFlags($languages, $default_form_language, 'flag_fields', 'meta_title', true, true); $return .= ' </div> <div class="clear"></div> </div> <label>'.$this->l('Indexable:').' </label> <div class="margin-form"> <input type="radio" '.(($on) ? 'checked="checked"' : '').' value="1" id="indexable_on" name="layered_indexable"> <label for="indexable_on" class="t"><img title="Yes" alt="Enabled" src="../img/admin/enabled.gif"></label> <input type="radio" '.((!$on) ? 'checked="checked"' : '').' value="0" id="indexable_off" name="layered_indexable"> <label for="indexable_off" class="t"><img title="No" alt="Disabled" src="../img/admin/disabled.gif"></label> <p>'.$this->l('Use this attribute in URL generated by the layered navigation module').'</p> </div>'; return $return; } /* * $cursor $cursor in order to restart indexing from the last state */ public static function fullPricesIndexProcess($cursor = 0, $ajax = false, $smart = false) { if ($cursor == 0 && !$smart) self::installPriceIndexTable(); return self::indexPrices($cursor, true, $ajax, $smart); } /* * $cursor $cursor in order to restart indexing from the last state */ public static function pricesIndexProcess($cursor = 0, $ajax = false) { return self::indexPrices($cursor, false, $ajax); } private static function indexPrices($cursor = null, $full = false, $ajax = false, $smart = false) { if ($full) if (version_compare(_PS_VERSION_,'1.5','>')) $nb_products = (int)Db::getInstance()->getValue(' SELECT count(DISTINCT p.`id_product`) FROM '._DB_PREFIX_.'product p INNER JOIN `'._DB_PREFIX_.'product_shop` ps ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1)'); else $nb_products = (int)Db::getInstance()->getValue(' SELECT count(DISTINCT p.`id_product`) FROM '._DB_PREFIX_.'product p WHERE `active` = 1'); else if (version_compare(_PS_VERSION_,'1.5','>')) $nb_products = (int)Db::getInstance()->getValue(' SELECT COUNT(DISTINCT p.`id_product`) FROM `'._DB_PREFIX_.'product` p INNER JOIN `'._DB_PREFIX_.'product_shop` ps ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1) LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product) WHERE psi.id_product IS NULL'); else $nb_products = (int)Db::getInstance()->getValue(' SELECT COUNT(DISTINCT p.`id_product`) FROM `'._DB_PREFIX_.'product` p LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product) WHERE `active` = 1 AND psi.id_product IS NULL'); $max_executiontime = @ini_get('max_execution_time'); if ($max_executiontime > 5 || $max_executiontime <= 0) $max_executiontime = 5; $start_time = microtime(true); do { $cursor = (int)self::indexPricesUnbreakable((int)$cursor, $full, $smart); $time_elapsed = microtime(true) - $start_time; } while ($cursor < $nb_products && (Tools::getMemoryLimit()) > memory_get_peak_usage() && $time_elapsed < $max_executiontime); if (($nb_products > 0 && !$full || $cursor < $nb_products && $full) && !$ajax) { $token = substr(Tools::encrypt('blocklayered/index'), 0, 10); if (Tools::usingSecureMode()) $domain = Tools::getShopDomainSsl(true); else $domain = Tools::getShopDomain(true); if (!Tools::file_get_contents($domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-price-indexer.php?token='.$token.'&cursor='.(int)$cursor.'&full='.(int)$full)) self::indexPrices((int)$cursor, (int)$full); return $cursor; } if ($ajax && $nb_products > 0 && $cursor < $nb_products && $full) return '{"cursor": '.$cursor.', "count": '.($nb_products - $cursor).'}'; else if ($ajax && $nb_products > 0 && !$full) return '{"cursor": '.$cursor.', "count": '.($nb_products).'}'; else { if (version_compare(_PS_VERSION_,'1.5','>')) Configuration::updateGlobalValue('PS_LAYERED_INDEXED', 1); else Configuration::updateValue('PS_LAYERED_INDEXED', 1); if ($ajax) return '{"result": "ok"}'; else return -1; } } /* * $cursor $cursor in order to restart indexing from the last state */ private static function indexPricesUnbreakable($cursor, $full = false, $smart = false) { static $length = 100; // Nb of products to index if (is_null($cursor)) $cursor = 0; if ($full) if (version_compare(_PS_VERSION_,'1.5','>')) $query = ' SELECT p.`id_product` FROM `'._DB_PREFIX_.'product` p INNER JOIN `'._DB_PREFIX_.'product_shop` ps ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1) GROUP BY p.`id_product` ORDER BY p.`id_product` LIMIT '.(int)$cursor.','.(int)$length; else $query = ' SELECT p.`id_product` FROM `'._DB_PREFIX_.'product` p WHERE `active` = 1 GROUP BY p.`id_product` ORDER BY p.`id_product` LIMIT '.(int)$cursor.','.(int)$length; else if (version_compare(_PS_VERSION_,'1.5','>')) $query = ' SELECT p.`id_product` FROM `'._DB_PREFIX_.'product` p INNER JOIN `'._DB_PREFIX_.'product_shop` ps ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1) LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product) WHERE psi.id_product IS NULL GROUP BY p.`id_product` ORDER BY p.`id_product` LIMIT 0,'.(int)$length; else $query = ' SELECT p.`id_product` FROM `'._DB_PREFIX_.'product` p LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product) WHERE `active` = 1 AND psi.id_product IS NULL GROUP BY p.`id_product` ORDER BY p.`id_product` LIMIT 0,'.(int)$length; foreach (Db::getInstance()->executeS($query) as $product) self::indexProductPrices((int)$product['id_product'], ($smart && $full)); return (int)($cursor + $length); } public static function indexProductPrices($id_product, $smart = true) { static $groups = null; if (is_null($groups)) { $groups = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT id_group FROM `'._DB_PREFIX_.'group_reduction`'); if (!$groups) $groups = array(); } $shop_list = array(); if (version_compare(_PS_VERSION_,'1.5','>')) $shop_list = Shop::getShops(false, null, true); else $shop_list[] = 0; foreach ($shop_list as $id_shop) { static $currency_list = null; if (is_null($currency_list)) { if (version_compare(_PS_VERSION_,'1.5','>')) $currency_list = Currency::getCurrencies(false, 1, new Shop($id_shop)); else $currency_list = Currency::getCurrencies(false, 1); } $min_price = array(); $max_price = array(); if ($smart) Db::getInstance()->execute('DELETE FROM `'._DB_PREFIX_.'layered_price_index` WHERE `id_product` = '.(int)$id_product.' AND `id_shop` = '.(int)$id_shop); if (Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX')) { if (version_compare(_PS_VERSION_,'1.5','>')) $max_tax_rate = Db::getInstance()->getValue(' SELECT max(t.rate) max_rate FROM `'._DB_PREFIX_.'product_shop` p LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg ON (trg.id_tax_rules_group = p.id_tax_rules_group AND p.id_shop = '.(int)$shop_list.') LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (tr.id_tax_rules_group = trg.id_tax_rules_group) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.id_tax = tr.id_tax AND t.active = 1) WHERE id_product = '.(int)$id_product.' GROUP BY id_product'); else $max_tax_rate = Db::getInstance()->getValue(' SELECT max(t.rate) max_rate FROM `'._DB_PREFIX_.'product` p LEFT JOIN `'._DB_PREFIX_.'tax_rules_group` trg ON (trg.id_tax_rules_group = p.id_tax_rules_group) LEFT JOIN `'._DB_PREFIX_.'tax_rule` tr ON (tr.id_tax_rules_group = trg.id_tax_rules_group) LEFT JOIN `'._DB_PREFIX_.'tax` t ON (t.id_tax = tr.id_tax AND t.active = 1) WHERE id_product = '.(int)$id_product.' GROUP BY id_product'); } else $max_tax_rate = 0; $product_min_prices = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT id_shop, id_currency, id_country, id_group, from_quantity FROM `'._DB_PREFIX_.'specific_price` WHERE id_product = '.(int)$id_product); // Get min price foreach ($currency_list as $currency) { $price = Product::priceCalculation($id_shop, (int)$id_product, null, null, null, null, $currency['id_currency'], null, null, false, 6, false, true, true, $specific_price_output, true); if (!isset($max_price[$currency['id_currency']])) $max_price[$currency['id_currency']] = 0; if (!isset($min_price[$currency['id_currency']])) $min_price[$currency['id_currency']] = null; if ($price > $max_price[$currency['id_currency']]) $max_price[$currency['id_currency']] = $price; if ($price == 0) continue; if (is_null($min_price[$currency['id_currency']]) || $price < $min_price[$currency['id_currency']]) $min_price[$currency['id_currency']] = $price; } foreach ($product_min_prices as $specific_price) foreach ($currency_list as $currency) { if ($specific_price['id_currency'] && $specific_price['id_currency'] != $currency['id_currency']) continue; $price = Product::priceCalculation((($specific_price['id_shop'] == 0) ? null : (int)$specific_price['id_shop']), (int)$id_product, null, (($specific_price['id_country'] == 0) ? null : $specific_price['id_country']), null, null, $currency['id_currency'], (($specific_price['id_group'] == 0) ? null : $specific_price['id_group']), $specific_price['from_quantity'], false, 6, false, true, true, $specific_price_output, true); if (!isset($max_price[$currency['id_currency']])) $max_price[$currency['id_currency']] = 0; if (!isset($min_price[$currency['id_currency']])) $min_price[$currency['id_currency']] = null; if ($price > $max_price[$currency['id_currency']]) $max_price[$currency['id_currency']] = $price; if ($price == 0) continue; if (is_null($min_price[$currency['id_currency']]) || $price < $min_price[$currency['id_currency']]) $min_price[$currency['id_currency']] = $price; } foreach ($groups as $group) foreach ($currency_list as $currency) { $price = Product::priceCalculation(null, (int)$id_product, null, null, null, null, (int)$currency['id_currency'], (int)$group['id_group'], null, false, 6, false, true, true, $specific_price_output, true); if (!isset($max_price[$currency['id_currency']])) $max_price[$currency['id_currency']] = 0; if (!isset($min_price[$currency['id_currency']])) $min_price[$currency['id_currency']] = null; if ($price > $max_price[$currency['id_currency']]) $max_price[$currency['id_currency']] = $price; if ($price == 0) continue; if (is_null($min_price[$currency['id_currency']]) || $price < $min_price[$currency['id_currency']]) $min_price[$currency['id_currency']] = $price; } $values = array(); foreach ($currency_list as $currency) $values[] = '('.(int)$id_product.', '.(int)$currency['id_currency'].', '.$id_shop.', '.(int)$min_price[$currency['id_currency']].', '.(int)Tools::ps_round($max_price[$currency['id_currency']] * (100 + $max_tax_rate) / 100, 0).')'; Db::getInstance()->execute(' INSERT INTO `'._DB_PREFIX_.'layered_price_index` (id_product, id_currency, id_shop, price_min, price_max) VALUES '.implode(',', $values).' ON DUPLICATE KEY UPDATE id_product = id_product # avoid duplicate keys'); } } public function hookLeftColumn($params) { return $this->generateFiltersBlock($this->getSelectedFilters()); } public function hookRightColumn($params) { return $this->hookLeftColumn($params); } public function hookHeader($params) { global $smarty, $cookie; // No filters => module disable if ($filter_block = $this->getFilterBlock($this->getSelectedFilters())) if ($filter_block['nbr_filterBlocks'] == 0) return false; if (Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)) == 1) return; $id_lang = (int)$cookie->id_lang; $category = new Category((int)Tools::getValue('id_category')); // Generate meta title and meta description $category_title = (empty($category->meta_title[$id_lang]) ? $category->name[$id_lang] : $category->meta_title[$id_lang]); $title = ''; $description = ''; $keywords = ''; if (is_array($filter_block['meta_values'])) foreach ($filter_block['meta_values'] as $key => $val) { if (!empty($val['title'])) $val['title'] = $val['title'].' '; foreach ($val['values'] as $value) { $title .= $category_title.' '.$val['title'].$value.' - '; $description .= $category_title.' '.$val['title'].$value.', '; $keywords .= $val['title'].$value.', '; } } // Title attributes (ex: <attr1> <value1>/<value2> - <attr2> <value1>) $title = strtolower(rtrim(substr($title, 0, -3))); // Title attributes (ex: <attr1> <value1>/<value2>, <attr2> <value1>) $description = strtolower(rtrim(substr($description, 0, -2))); // kewords attributes (ex: <attr1> <value1>, <attr1> <value2>, <attr2> <value1>) if (version_compare(_PS_VERSION_, '1.5', '>')) $category_metas = Meta::getMetaTags($id_lang, 'category', $title); else $category_metas = Tools::getMetaTags($id_lang, '', $title); if (!empty($title)) { $smarty->assign('meta_title', ucfirst(substr($category_metas['meta_title'], 3))); $smarty->assign('meta_description', $description.'. '.$category_metas['meta_description']); } else $smarty->assign('meta_title', $category_metas['meta_title']); $keywords = substr(strtolower($keywords), 0, 1000); if (!empty($keywords)) $smarty->assign('meta_keywords', rtrim($category_title.', '.$keywords.', '.$category_metas['meta_keywords'], ', ')); if (version_compare(_PS_VERSION_, '1.5', '>')) { $this->context->controller->addJS(($this->_path).'blocklayered.js'); $this->context->controller->addJS(_PS_JS_DIR_.'jquery/jquery-ui-1.8.10.custom.min.js'); $this->context->controller->addJQueryUI('ui.slider'); $this->context->controller->addCSS(($this->_path).'blocklayered-15.css', 'all'); $this->context->controller->addJQueryPlugin('scrollTo'); } else { Tools::addJS(($this->_path).'blocklayered.js'); Tools::addJS(_PS_JS_DIR_.'jquery/jquery-ui-1.8.10.custom.min.js'); Tools::addCSS(_PS_CSS_DIR_.'jquery-ui-1.8.10.custom.css', 'all'); Tools::addCSS(($this->_path).'blocklayered.css', 'all'); Tools::addJS(_PS_JS_DIR_.'jquery/jquery.scrollTo-1.4.2-min.js'); } $filters = $this->getSelectedFilters(); // Get non indexable attributes $attribute_group_list = Db::getInstance()->executeS('SELECT id_attribute_group FROM '._DB_PREFIX_.'layered_indexable_attribute_group WHERE indexable = 0'); // Get non indexable features $feature_list = Db::getInstance()->executeS('SELECT id_feature FROM '._DB_PREFIX_.'layered_indexable_feature WHERE indexable = 0'); $attributes = array(); $features = array(); $blacklist = array('weight', 'price'); if (!Configuration::get('PS_LAYERED_FILTER_INDEX_CDT')) $blacklist[] = 'condition'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_QTY')) $blacklist[] = 'quantity'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_MNF')) $blacklist[] = 'manufacturer'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_CAT')) $blacklist[] = 'category'; foreach ($filters as $type => $val) { switch ($type) { case 'id_attribute_group': foreach ($val as $attr) { $attr_id = preg_replace('/_\d+$/', '', $attr); if (in_array($attr_id, $attributes) || in_array(array('id_attribute_group' => $attr_id), $attribute_group_list)) { $smarty->assign('nobots', true); $smarty->assign('nofollow', true); return; } $attributes[] = $attr_id; } break; case 'id_feature': foreach ($val as $feat) { $feat_id = preg_replace('/_\d+$/', '', $feat); if (in_array($feat_id, $features) || in_array(array('id_feature' => $feat_id), $feature_list)) { $smarty->assign('nobots', true); $smarty->assign('nofollow', true); return; } $features[] = $feat_id; } break; default: if (in_array($type, $blacklist)) { if (count($val)) { $smarty->assign('nobots', true); $smarty->assign('nofollow', true); return; } } elseif (count($val) > 1) { $smarty->assign('nobots', true); $smarty->assign('nofollow', true); return; } break; } } } public function hookFooter($params) { // No filters => module disable if ($filter_block = $this->getFilterBlock($this->getSelectedFilters())) if ($filter_block['nbr_filterBlocks'] == 0) return false; if (basename($_SERVER['PHP_SELF']) == 'category.php' && version_compare(_PS_VERSION_, '1.5', '<') || version_compare(_PS_VERSION_, '1.5', '>') && Dispatcher::getInstance()->getController() == 'category') return ' <script type="text/javascript"> //<![CDATA[ $(document).ready(function() { $(\'#selectPrductSort\').unbind(\'change\').bind(\'change\', function() { reloadContent(); }) }); //]]> </script>'; } public function hookCategoryAddition($params) { $this->rebuildLayeredCache(array(), array((int)$params['category']->id)); } public function hookCategoryUpdate($params) { /* The category status might (active, inactive) have changed, we have to update the layered cache table structure */ if (isset($params['category']) && !$params['category']->active) $this->hookCategoryDeletion($params); } public function hookCategoryDeletion($params) { $layered_filter_list = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM '._DB_PREFIX_.'layered_filter'); foreach ($layered_filter_list as $layered_filter) { $data = self::unSerialize($layered_filter['filters']); if (in_array((int)$params['category']->id, $data['categories'])) { unset($data['categories'][array_search((int)$params['category']->id, $data['categories'])]); Db::getInstance()->execute('UPDATE `'._DB_PREFIX_.'layered_filter` SET `filters` = \''.pSQL(serialize($data)).'\' WHERE `id_layered_filter` = '.(int)$layered_filter['id_layered_filter'].''); } } $this->buildLayeredCategories(); } public function getContent() { global $cookie; $html = ''; if (Tools::isSubmit('SubmitFilter')) { if (!Tools::getValue('layered_tpl_name')) $html .= ' <div class="error"> <span style="float:right"> <a href="" id="hideError"><img src="../img/admin/close.png" alt="X"></a> </span> <img src="../img/admin/error2.png">'.$this->l('Filter template name required (cannot be empty)').' </div>'; else { if (isset($_POST['id_layered_filter']) && $_POST['id_layered_filter']) { Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)Tools::getValue('id_layered_filter')); $this->buildLayeredCategories(); } if (Tools::getValue('scope') == 1) { Db::getInstance()->execute('TRUNCATE TABLE '._DB_PREFIX_.'layered_filter'); $categories = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT id_category FROM '._DB_PREFIX_.'category'); foreach ($categories as $category) $_POST['categoryBox'][] = (int)$category['id_category']; } if (version_compare(_PS_VERSION_, '1.5', '>')) { $id_layered_filter = (int)$_POST['id_layered_filter']; if (!$id_layered_filter) $id_layered_filter = (int)Db::getInstance()->Insert_ID(); $shop_list = array(); if (isset($_POST['checkBoxShopAsso_layered_filter'])) { foreach ($_POST['checkBoxShopAsso_layered_filter'] as $id_shop => $row) { $assos[] = array('id_object' => (int)$id_layered_filter, 'id_shop' => (int)$id_shop); $shop_list[] = (int)$id_shop; } } else $shop_list = array(Context::getContext()->shop->id); } else $shop_list = array(0); if (count($_POST['categoryBox'])) { /* Clean categoryBox before use */ if (isset($_POST['categoryBox']) && is_array($_POST['categoryBox'])) foreach ($_POST['categoryBox'] as &$category_box_tmp) $category_box_tmp = (int)$category_box_tmp; $filter_values = array(); foreach ($_POST['categoryBox'] as $idc) $filter_values['categories'][] = (int)$idc; $filter_values['shop_list'] = $shop_list; $values = false; foreach ($_POST['categoryBox'] as $id_category_layered) { foreach ($_POST as $key => $value) if (substr($key, 0, 17) == 'layered_selection' && $value == 'on') { $values = true; $type = 0; $limit = 0; if (Tools::getValue($key.'_filter_type')) $type = Tools::getValue($key.'_filter_type'); if (Tools::getValue($key.'_filter_show_limit')) $limit = Tools::getValue($key.'_filter_show_limit'); $filter_values[$key] = array( 'filter_type' => (int)$type, 'filter_show_limit' => (int)$limit ); } } if (version_compare(_PS_VERSION_, '1.5', '>')) { Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_filter_shop WHERE `id_layered_filter` = '.(int)$id_layered_filter); if (isset($assos)) foreach ($assos as $asso) Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_filter_shop (`id_layered_filter`, `id_shop`) VALUES('.$id_layered_filter.', '.(int)$asso['id_shop'].')'); } $values_to_insert = array( 'name' => pSQL(Tools::getValue('layered_tpl_name')), 'filters' => pSQL(serialize($filter_values)), 'n_categories' => (int)count($filter_values['categories']), 'date_add' => date('Y-m-d H:i:s')); if (isset($_POST['id_layered_filter']) && $_POST['id_layered_filter']) $values_to_insert['id_layered_filter'] = (int)Tools::getValue('id_layered_filter'); Db::getInstance()->autoExecute(_DB_PREFIX_.'layered_filter', $values_to_insert, 'INSERT'); $this->buildLayeredCategories(); $html .= '<div class="conf">'.(version_compare(_PS_VERSION_,'1.5','>') ? '' : '<img src="../img/admin/ok2.png" alt="" />'). $this->l('Your filter').' "'.Tools::safeOutput(Tools::getValue('layered_tpl_name')).'" '. ((isset($_POST['id_layered_filter']) && $_POST['id_layered_filter']) ? $this->l('was updated successfully.') : $this->l('was added successfully.')).'</div>'; } } } else if (Tools::isSubmit('submitLayeredSettings')) { Configuration::updateValue('PS_LAYERED_HIDE_0_VALUES', (int)Tools::getValue('ps_layered_hide_0_values')); Configuration::updateValue('PS_LAYERED_SHOW_QTIES', (int)Tools::getValue('ps_layered_show_qties')); Configuration::updateValue('PS_LAYERED_FULL_TREE', (int)Tools::getValue('ps_layered_full_tree')); Configuration::updateValue('PS_LAYERED_FILTER_PRICE_USETAX', (int)Tools::getValue('ps_layered_filter_price_usetax')); Configuration::updateValue('PS_LAYERED_FILTER_CATEGORY_DEPTH', (int)Tools::getValue('ps_layered_filter_category_depth')); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_QTY', (int)Tools::getValue('ps_layered_filter_index_availability')); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CDT', (int)Tools::getValue('ps_layered_filter_index_condition')); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_MNF', (int)Tools::getValue('ps_layered_filter_index_manufacturer')); Configuration::updateValue('PS_LAYERED_FILTER_INDEX_CAT', (int)Tools::getValue('ps_layered_filter_index_category')); $html .= ' <div class="conf">'. (version_compare(_PS_VERSION_,'1.5','>') ? '' : '<img src="../img/admin/ok2.png" alt="" />').$this->l('Settings saved successfully').' </div>'; } else if (isset($_GET['deleteFilterTemplate'])) { $layered_values = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' SELECT filters FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)$_GET['id_layered_filter']); if ($layered_values) { Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)$_GET['id_layered_filter'].' LIMIT 1'); $this->buildLayeredCategories(); $html .= ' <div class="conf">'.(version_compare(_PS_VERSION_,'1.5','>') ? '' : '<img src="../img/admin/ok2.png" alt="" />').' '.$this->l('Filter template deleted, categories updated (reverted to default Filter template).').' </div>'; } else { $html .= ' <div class="error"> <img src="../img/admin/error.png" alt="" title="" /> '.$this->l('Filter template not found').' </div>'; } } $html .= ' <div id="ajax-message-ok" class="conf ajax-message" style="display: none"> '.(version_compare(_PS_VERSION_,'1.5','>') ? '' : '<img src="../img/admin/ok2.png" alt="" />').'<span class="message"></span> </div> <div id="ajax-message-ko" class="error ajax-message" style="display: none"> '.(version_compare(_PS_VERSION_,'1.5','>') ? '' : '<img src="../img/admin/errors.png" alt="" />').'<span class="message"></span> </div> <h2>'.$this->l('Layered navigation').'</h2> <fieldset class="width4"> <legend><img src="../img/admin/cog.gif" alt="" />'.$this->l('Indexes and caches').'</legend> <span id="indexing-warning" style="display: none; color:red; font-weight: bold">'.$this->l('Indexing is in progress. Please do not leave this page').'<br/><br/></span>'; if (version_compare(_PS_VERSION_, '1.5', '<') && !Configuration::get('PS_LAYERED_INDEXED') || version_compare(_PS_VERSION_, '1.5', '>') && !Configuration::getGlobalValue('PS_LAYERED_INDEXED')) $html .= ' <script type="text/javascript"> $(document).ready(function() { $(\'#url-indexer\').click(); $(\'#full-index\').click(); }); </script>'; $category_ist = array(); foreach (Db::getInstance()->executeS('SELECT id_category FROM `'._DB_PREFIX_.'category`') as $category) if ($category['id_category'] != 1) $category_ist[] = $category['id_category']; $domain = Tools::getProtocol(Tools::usingSecureMode()).$_SERVER['HTTP_HOST']; $html .= ' <a class="bold ajaxcall-recurcive" style="width: 250px; text-align:center;display:block;border:1px solid #aaa;text-decoration:none;background-color:#fafafa;color:#123456;margin:2px;padding:2px" href="'.$domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-price-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'">'. $this->l('Index all missing prices').'</a> <br /> <a class="bold ajaxcall-recurcive" style="width: 250px; text-align:center;display:block;border:1px solid #aaa;text-decoration:none;background-color:#fafafa;color:#123456;margin:2px;padding:2px" id="full-index" href="'.$domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-price-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&full=1">'. $this->l('Rebuild entire price index').'</a> <br /> <a class="bold ajaxcall" id="attribute-indexer" rel="attribute" style="width: 250px; text-align:center;display:block;border:1px solid #aaa;text-decoration:none;background-color:#fafafa;color:#123456;margin:2px;padding:2px" id="full-index" href="'.$domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-attribute-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'">'. $this->l('Build attribute index').'</a> <br /> <a class="bold ajaxcall" id="url-indexer" rel="price" style="width: 250px; text-align:center;display:block;border:1px solid #aaa;text-decoration:none;background-color:#fafafa;color:#123456;margin:2px;padding:2px" id="full-index" href="'.$domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-url-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&truncate=1">'. $this->l('Build URL index').'</a> <br /> <br /> '.$this->l('You can set a cron job that will rebuild price index using the following URL:').'<br /><b>'. $domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-price-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&full=1</b> <br /> '.$this->l('You can set a cron job that will rebuild URL index using the following URL:').'<br /><b>'. $domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-url-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&truncate=1</b> <br /> '.$this->l('You can set a cron job that will rebuild attribute index using the following URL:').'<br /><b>'. $domain.__PS_BASE_URI__.'modules/blocklayered/blocklayered-attribute-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'</b> <br /><br /> '.$this->l('A nightly rebuild is recommended.').' <script type="text/javascript"> $(\'.ajaxcall\').click(function() { if (this.legend == undefined) this.legend = $(this).html(); if (this.running == undefined) this.running = false; if (this.running == true) return false; $(\'.ajax-message\').hide(); this.running = true; if (typeof(this.restartAllowed) == \'undefined\' || this.restartAllowed) { $(this).html(this.legend+\' '.addslashes($this->l('(in progress)')).'\'); $(\'#indexing-warning\').show(); } this.restartAllowed = false; var type = $(this).attr(\'rel\'); $.ajax({ url: this.href+\'&ajax=1\', context: this, dataType: \'json\', cache: \'false\', success: function(res) { this.running = false; this.restartAllowed = true; $(\'#indexing-warning\').hide(); $(this).html(this.legend); if (type == \'price\') $(\'#ajax-message-ok span\').html(\''.addslashes($this->l('URL indexation finished')).'\'); else $(\'#ajax-message-ok span\').html(\''.addslashes($this->l('Attribute indexation finished')).'\'); $(\'#ajax-message-ok\').show(); return; }, error: function(res) { this.restartAllowed = true; $(\'#indexing-warning\').hide(); if (type == \'price\') $(\'#ajax-message-ko span\').html(\''.addslashes($this->l('URL indexation failed')).'\'); else $(\'#ajax-message-ko span\').html(\''.addslashes($this->l('Attribute indexation failed')).'\'); $(\'#ajax-message-ko\').show(); $(this).html(this.legend); this.running = false; } }); return false; }); $(\'.ajaxcall-recurcive\').each(function(it, elm) { $(elm).click(function() { if (this.cursor == undefined) this.cursor = 0; if (this.legend == undefined) this.legend = $(this).html(); if (this.running == undefined) this.running = false; if (this.running == true) return false; $(\'.ajax-message\').hide(); this.running = true; if (typeof(this.restartAllowed) == \'undefined\' || this.restartAllowed) { $(this).html(this.legend+\' '.addslashes($this->l('(in progress)')).'\'); $(\'#indexing-warning\').show(); } this.restartAllowed = false; $.ajax({ url: this.href+\'&ajax=1&cursor=\'+this.cursor, context: this, dataType: \'json\', cache: \'false\', success: function(res) { this.running = false; if (res.result) { this.cursor = 0; $(\'#indexing-warning\').hide(); $(this).html(this.legend); $(\'#ajax-message-ok span\').html(\''.addslashes($this->l('Price indexation finished')).'\'); $(\'#ajax-message-ok\').show(); return; } this.cursor = parseInt(res.cursor); $(this).html(this.legend+\' '.addslashes($this->l('(in progress, %s products price to index)')).'\'.replace(\'%s\', res.count)); $(this).click(); }, error: function(res) { this.restartAllowed = true; $(\'#indexing-warning\').hide(); $(\'#ajax-message-ko span\').html(\''.addslashes($this->l('Price indexation failed')).'\'); $(\'#ajax-message-ko\').show(); $(this).html(this.legend); this.cursor = 0; this.running = false; } }); return false; }); }); </script> </fieldset> <br /> <fieldset class="width4"> <legend><img src="../img/admin/cog.gif" alt="" />'.$this->l('Existing filter templates').'</legend>'; $filters_templates = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM '._DB_PREFIX_.'layered_filter ORDER BY date_add DESC'); if (count($filters_templates)) { $html .= '<p>'.count($filters_templates).' '.$this->l('filter templates are configured:').'</p> <table id="table-filter-templates" class="table" style="width: 700px;"> <tr> <th>'.$this->l('ID').'</th> <th>'.$this->l('Name').'</th> <th>'.$this->l('Categories').'</th> <th>'.$this->l('Created on').'</th> <th>'.$this->l('Actions').'</th> </tr>'; foreach ($filters_templates as $filters_template) { /* Clean request URI first */ $_SERVER['REQUEST_URI'] = preg_replace('/&deleteFilterTemplate=[0-9]*&id_layered_filter=[0-9]*/', '', $_SERVER['REQUEST_URI']); $html .= ' <tr> <td>'.(int)$filters_template['id_layered_filter'].'</td> <td style="text-align: left; padding-left: 10px; width: 270px;">'.$filters_template['name'].'</td> <td style="text-align: center;">'.(int)$filters_template['n_categories'].'</td> <td>'.Tools::displayDate($filters_template['date_add'], (int)$cookie->id_lang, true).'</td> <td> <a href="#" onclick="return updElements('.($filters_template['n_categories'] ? 0 : 1).', '.(int)$filters_template['id_layered_filter'].');"> <img src="../img/admin/edit.gif" alt="" title="'.$this->l('Edit').'" /></a> <a href="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'&deleteFilterTemplate=1&id_layered_filter='.(int)$filters_template['id_layered_filter'].'" onclick="return confirm(\''.addslashes(sprintf($this->l('Delete filter template #%d?'), (int)$filters_template['id_layered_filter'])).'\');"> <img src="../img/admin/delete.gif" alt="" title="'.$this->l('Delete').'" /></a> </td> </tr>'; } $html .= ' </table>'; } else $html .= $this->l('No filter template found.'); $html .= ' </fieldset><br /> <fieldset class="width4"> <legend><img src="../img/admin/cog.gif" alt="" />'.$this->l('Build your own filter template').'</legend> <link rel="stylesheet" href="'._PS_CSS_DIR_.'jquery-ui-1.8.10.custom.css" /> <style type="text/css"> #error-filter-name { display: none; } #layered_container_left ul, #layered_container_right ul { list-style-type: none; padding-left: 0px; } .ui-effects-transfer { border: 1px solid #CCC; } .ui-state-highlight { height: 1.5em; line-height: 1.2em; } ul#selected_filters, #layered_container_right ul { list-style-type: none; margin: 0; padding: 0; } ul#selected_filters li, #layered_container_right ul li { width: 326px; font-size: 11px; padding: 8px 9px 7px 20px; height: 14px; margin-bottom: 5px; } ul#selected_filters li span.ui-icon { position: absolute; margin-top: -2px; margin-left: -18px; } #layered_container_right ul li span { display: none; } #layered_container_right ul li { padding-left: 8px; position: relative; } #layered_container_left ul li { cursor: move; position: relative; } #layered-cat-counter { display: none; } #layered-step-2, #layered-step-3 { display: none; } #layered-step-2 h3 { margin-top: 0; } #table-filter-templates tr th, #table-filter-templates tr td { text-align: center; } .filter_type { width: 70px; position: absolute; right: 53px; top: 5px;} .filter_show_limit { position: absolute; width: 40px; right: 5px; top: 5px; } #layered-step-3 .alert { width: auto; } #fancybox-content { height: 400px !important; overflow: auto !important; } </style> <form action="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'" method="post" onsubmit="return checkForm();">'; $html .= ' <h2>'.$this->l('Step 1/3 - Select categories').'</h2> <p style="margin-top: 20px;"> <span style="color: #585A69;display: block;float: left;font-weight: bold;text-align: right;width: 200px;" >'.$this->l('Use this template for:').'</span> <input type="radio" id="scope_1" name="scope" value="1" style="margin-left: 15px;" onclick="$(\'#error-treeview\').hide(); $(\'#layered-step-2\').show(); updElements(1, 0);" /> <label for="scope_1" style="float: none;">'.$this->l('All categories').'</label> <input type="radio" id="scope_2" name="scope" value="2" style="margin-left: 15px;" class="layered-category-selection" onclick="$(\'label a#inline\').click(); $(\'#layered-step-2\').show();" /> <style> .link { color: black; cursor: pointer; text-decoration: underline; } .link:hover { color: gray; } </style> <label for="scope_2" style="float: none;"><a id="inline" href="#layered-categories-selection" style="text-decoration: underline;"></a>'.preg_replace('/\*([^*]+)\*/Usi', '<span class="link">$1</span>', $this->l('*Specific* categories')).' (<span id="layered-cat-counter"></span> '.$this->l('selected').')</label> </p>'; if (version_compare(_PS_VERSION_,'1.5','>')) { $shops = Shop::getShops(true, null, true); if (count($shops) > 1) { $helper = new HelperForm(); $helper->id = null; $helper->table = 'layered_filter'; $helper->identifier = 'id_layered_filter'; if (Shop::isFeatureActive()) { $html .= '<span style="color: #585A69;display: block;float: left;font-weight: bold;text-align: right;width: 200px;" >'.$this->l('Choose shop association:').'</span>'; $html .= '<div id="shop_association" style="width: 300px;margin-left: 215px;">'.$helper->renderAssoShop().'</div>'; } } } $html .= ' <div id="error-treeview" class="error" style="display: none;"> <img src="../img/admin/error2.png" alt="" /> '.$this->l('Please select at least one specific category or select "All categories".').' </div> <div style="display: none;"> <div id="layered-categories-selection" style="padding: 10px; text-align: left;"> <h2>'.$this->l('Categories using this template').'</h2> <ol style="padding-left: 20px;"> <li>'.$this->l('Select one ore more category using this filter template').'</li> <li>'.$this->l('Press "Save this selection" or close the window to save').'</li> </ol>'; $selected_cat = array(); // Translations are not automatic for the moment ;) if (version_compare(_PS_VERSION_,'1.5','>')) { if (Shop::getContext() == Shop::CONTEXT_SHOP) { $root_category = Category::getRootCategory(); $root_category = array('id_category' => $root_category->id_category, 'name' => $root_category->name); } else $root_category = array('id_category' => '0', 'name' => $this->l('Root')); $helper = new Helper(); $html .= $helper->renderCategoryTree(null, $selected_cat, 'categoryBox'); } else { $trads = array( 'Home' => $this->l('Home'), 'selected' => $this->l('selected'), 'Collapse All' => $this->l('Collapse All'), 'Expand All' => $this->l('Expand All'), 'Check All' => $this->l('Check All'), 'Uncheck All' => $this->l('Uncheck All'), 'search' => $this->l('Search a category') ); $html .= Helper::renderAdminCategorieTree($trads, $selected_cat, 'categoryBox'); } $html .= ' <br /> <center><input type="button" class="button" value="'.$this->l('Save this selection').'" onclick="$.fancybox.close();" /></center> </div> </div> <div id="layered-step-2"> <hr size="1" noshade /> <h2>'.$this->l('Step 2/3 - Select filters').'</h2> <div id="layered_container"> <div id="layered_container_left" style="width: 360px; float: left; height: 200px; overflow-y: auto;"> <h3>'.$this->l('Selected filters').' <span id="num_sel_filters">(0)</span></h3> <p id="no-filters">'.$this->l('No filters selected yet.').'</p> <ul id="selected_filters"></ul> </div> <div id="layered-ajax-refresh"> '.$this->ajaxCallBackOffice().' </div> </div> <div class="clear"></div> <hr size="1" noshade />'; if (version_compare(_PS_VERSION_,'1.5','>')) { $this->context->controller->addJQueryPlugin('fancybox'); $this->context->controller->addJQueryUI('ui.sortable'); $this->context->controller->addJQueryUI('ui.draggable'); $this->context->controller->addJQueryUI('effects.transfer'); $id_lang = Context::getContext()->cookie->id_lang; } else { $html .= '<script type="text/javascript" src="'.__PS_BASE_URI__.'js/jquery/jquery-ui-1.8.10.custom.min.js"></script> <script type="text/javascript" src="'.__PS_BASE_URI__.'js/jquery/jquery.fancybox-1.3.4.js"></script> <link type="text/css" rel="stylesheet" href="'.__PS_BASE_URI__.'css/jquery.fancybox-1.3.4.css" />'; $id_lang = (int)$cookie->id_lang; } $html .= ' <script type="text/javascript"> function updLayCounters(showAlert) { $(\'#num_sel_filters\').html(\'(\'+$(\'ul#selected_filters\').find(\'li\').length+\')\'); $(\'#num_avail_filters\').html(\'(\'+$(\'#layered_container_right ul\').find(\'li\').length+\')\'); if ($(\'ul#selected_filters\').find(\'li\').length >= 1) { $(\'#layered-step-3\').show(); $(\'#layered-step-3 .alert\').hide(); } else { if (showAlert) $(\'#layered-step-3\').show(); else $(\'#layered-step-3\').hide(); $(\'#layered-step-3 .alert\').show(); } } function updPositions() { $(\'#layered_container_left li\').each(function(idx) { $(this).find(\'span.position\').html(parseInt(1+idx)+\'. \'); }); } function updCatCounter() { $(\'#layered-cat-counter\').html($(\'#categories-treeview\').find(\'input:checked\').length); $(\'#layered-cat-counter\').show(); } function updHeight() { $(\'#layered_container_left\').css(\'height\', 30+(1+$(\'#layered_container_left\').find(\'li\').length)*34); $(\'#layered_container_right\').css(\'height\', 30+(1+$(\'#layered_container_right\').find(\'li\').length)*34); } function updElements(all, id_layered_filter) { if ($(\'#error-treeview\').is(\':hidden\')) $(\'#layered-step-2\').show(); else $(\'#layered-step-2\').hide(); $(\'#layered-ajax-refresh\').css(\'background-color\', \'black\'); $(\'#layered-ajax-refresh\').css(\'opacity\', \'0.2\'); $(\'#layered-ajax-refresh\').html(\'<div style="margin: 0 auto; padding: 10px; text-align: center;">\' +\'<img src="../img/admin/ajax-loader-big.gif" alt="" /><br /><p style="color: white;">'.addslashes($this->l('Loading...')).'</p></div>\'); $.ajax( { type: \'POST\', url: \''.__PS_BASE_URI__.'\' + \'modules/blocklayered/blocklayered-ajax-back.php\', data: \'layered_token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&id_lang='.$id_lang.'&\' +(all ? \'\' : $(\'input[name="categoryBox[]"]\').serialize()+\'&\') +(id_layered_filter ? \'id_layered_filter=\'+parseInt(id_layered_filter) : \'\') +\'&base_folder='.urlencode(_PS_ADMIN_DIR_).'\', success: function(result) { $(\'#layered-ajax-refresh\').css(\'background-color\', \'transparent\'); $(\'#layered-ajax-refresh\').css(\'opacity\', \'1\'); $(\'#layered-ajax-refresh\').html(result); $(\'#layered_container_right li input\').each(function() { if ($(\'#layered_container_left\').find(\'input[id="\'+$(this).attr(\'id\')+\'"]\').length > 0) $(this).parent().remove(); }); updHeight(); updLayCounters(true); } }); return false; } function checkForm() { if ($(\'#layered_tpl_name\').val() == \'\') { $(\'#error-filter-name\').show(); return false; } else if ($(\'#scope_1\').attr(\'checked\') && $(\'#n_existing\').val() > 0) if (!confirm(\''.addslashes($this->l('You selected -All categories-, all existing filter templates will be deleted, OK?')).'\')) return false; return true; } function launch() { $(\'#layered_container input\').live(\'click\', function () { if ($(this).parent().hasClass(\'layered_right\')) { $(\'p#no-filters\').hide(); $(this).parent().css(\'background\', \'url("../img/jquery-ui/ui-bg_glass_100_fdf5ce_1x400.png") repeat-x scroll 50% 50% #FDF5CE\'); $(this).parent().removeClass(\'layered_right\'); $(this).parent().addClass(\'layered_left\'); $(this).effect(\'transfer\', { to: $(\'#layered_container_left ul#selected_filters\') }, 300, function() { $(this).parent().appendTo(\'ul#selected_filters\'); updLayCounters(false); updHeight(); updPositions(); }); } else { $(this).parent().css(\'background\', \'url("../img/jquery-ui/ui-bg_glass_100_f6f6f6_1x400.png") repeat-x scroll 50% 50% #F6F6F6\'); $(this).effect(\'transfer\', { to: $(\'#layered_container_right ul#all_filters\') }, 300, function() { $(this).parent().removeClass(\'layered_left\'); $(this).parent().addClass(\'layered_right\'); $(this).parent().appendTo(\'ul#all_filters\'); updLayCounters(true); updHeight(); updPositions(); if ($(\'#layered_container_left ul\').length == 0) $(\'p#no-filters\').show(); }); } enableSortable(); }); $(\'label a#inline\').fancybox({ \'hideOnContentClick\': false, \'onClosed\': function() { lock_treeview_hidding = false; $(\'#categories-treeview\').parent().parent().hide(); updCatCounter(); if ($(\'#categories-treeview\').find(\'input:checked\').length == 0) $(\'#error-treeview\').show(); else $(\'#error-treeview\').hide(); updElements(0, 0); }, \'onComplete\': function() { lock_treeview_hidding = true; $(\'#categories-treeview\').parent().parent().show(); if($($(\'#categories-treeview li\')[0]).attr(\'cleaned\')) return; if($($(\'#categories-treeview li\')[0]).attr(\'cleaned\', true)) $($(\'#categories-treeview li\')[0]).removeClass(\'static\'); $($(\'#categories-treeview li span\')[0]).trigger(\'click\'); $($(\'#categories-treeview li\')[0]).children(\'div\').remove(); $($(\'#categories-treeview li\')[0]). removeClass(\'collapsable lastCollapsable\'). addClass(\'last static\'); $(\'.hitarea\').live(\'click\', function(it) { $(this).parent().find(\'> .category_label\').click(); }); } }); updHeight(); updLayCounters(false); updPositions(); updCatCounter(); enableSortable(); } function enableSortable() { $(function() { $(\'ul#selected_filters\').sortable({ axis: \'y\', update: function() { updPositions(); }, placeholder: \'ui-state-highlight\' }); $(\'ul#selected_filters\').disableSelection(); }); } $(document).ready(function() { launch(); }); </script> </div> <div id="layered-step-3"> <div id="error-filter-name" class="error"> <img src="../img/admin/error.png" alt="" title="" />'.$this->l('Errors:').' <ul> <li>'.$this->l('Filter template name required (cannot be empty)').'</li> </ul> </div> <h2>'.$this->l('Step 3/3 - Name your template').'</h2> <p>'.$this->l('Template name:').' <input type="text" id="layered_tpl_name" onkeyup="if ($(this).val() != \'\') { $(\'#error-filter-name\').hide(); } else { $(\'#error-filter-name\').show(); }" name="layered_tpl_name" maxlength="64" value="'.sprintf($this->l('My template %s'), date('Y-m-d')).'" style="width: 200px; font-size: 11px;" /> <span style="font-size: 10px; font-style: italic;">('.$this->l('only as a reminder').')</span></p> <hr size="1" noshade /> <p class="alert">'.$this->l('No filters selected, the blocklayered will be disable for the categories seleted.').'</p> <br /> <center><input type="submit" class="button" name="SubmitFilter" value="'.$this->l('Save this filter template').'" /></center> </div> <input type="hidden" name="id_layered_filter" id="id_layered_filter" value="0" /> <input type="hidden" name="n_existing" id="n_existing" value="'.(int)count($filters_templates).'" /> </form> </fieldset><br /> <fieldset class="width4"> <legend><img src="../img/admin/cog.gif" alt="" /> '.$this->l('Configuration').'</legend> <form action="'.Tools::safeOutput($_SERVER['REQUEST_URI']).'" method="post"> <table border="0" style="font-size: 11px; width: 100%; margin: 0 auto;" class="table"> <tr> <th style="text-align: center;">'.$this->l('Option').'</th> <th style="text-align: center; width: 200px;">'.$this->l('Value').'</th> </tr> <tr> <td style="text-align: right;">'.$this->l('Hide filter values with no product is matching').'</td> <td style="text-align: center;"> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_hide_0_values" value="1" '.(Configuration::get('PS_LAYERED_HIDE_0_VALUES') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_hide_0_values" value="0" '.(!Configuration::get('PS_LAYERED_HIDE_0_VALUES') ? 'checked="checked"' : '').' /> </td> </tr> <tr> <td style="text-align: right;">'.$this->l('Show the number of matching products').'</td> <td style="text-align: center;"> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_show_qties" value="1" '.(Configuration::get('PS_LAYERED_SHOW_QTIES') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_show_qties" value="0" '.(!Configuration::get('PS_LAYERED_SHOW_QTIES') ? 'checked="checked"' : '').' /> </td> </tr> <tr> <td style="text-align: right;">'.$this->l('Show products from subcategories').'</td> <td style="text-align: center;"> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_full_tree" value="1" '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_full_tree" value="0" '.(!Configuration::get('PS_LAYERED_FULL_TREE') ? 'checked="checked"' : '').' /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Category filter depth (0 for no limits, 1 by default)').'</td> <td> <input type="text" name="ps_layered_filter_category_depth" value="'.((Configuration::get('PS_LAYERED_FILTER_CATEGORY_DEPTH') !== false) ? Configuration::get('PS_LAYERED_FILTER_CATEGORY_DEPTH') : 1).'" /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Use tax to filter price').'</td> <td> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_filter_price_usetax" value="1" '.(Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_filter_price_usetax" value="0" '.(!Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX') ? 'checked="checked"' : '').' /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Allow indexing robots (google, yahoo, bing, ...) to use condition filter').'</td> <td> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_filter_index_condition" value="1" '.(Configuration::get('PS_LAYERED_FILTER_INDEX_CDT') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_filter_index_condition" value="0" '.(!Configuration::get('PS_LAYERED_FILTER_INDEX_CDT') ? 'checked="checked"' : '').' /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Allow indexing robots (google, yahoo, bing, ...) to use availability filter').'</td> <td> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_filter_index_availability" value="1" '.(Configuration::get('PS_LAYERED_FILTER_INDEX_QTY') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_filter_index_availability" value="0" '.(!Configuration::get('PS_LAYERED_FILTER_INDEX_QTY') ? 'checked="checked"' : '').' /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Allow indexing robots (google, yahoo, bing, ...) to use manufacturer filter').'</td> <td> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_filter_index_manufacturer" value="1" '.(Configuration::get('PS_LAYERED_FILTER_INDEX_MNF') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_filter_index_manufacturer" value="0" '.(!Configuration::get('PS_LAYERED_FILTER_INDEX_MNF') ? 'checked="checked"' : '').' /> </td> </tr> <tr style="text-align: center;"> <td style="text-align: right;">'.$this->l('Allow indexing robots (google, yahoo, bing, ...) to use category filter').'</td> <td> <img src="../img/admin/enabled.gif" alt="'.$this->l('Yes').'" title="'.$this->l('Yes').'" /> '.$this->l('Yes').' <input type="radio" name="ps_layered_filter_index_category" value="1" '.(Configuration::get('PS_LAYERED_FILTER_INDEX_CAT') ? 'checked="checked"' : '').' /> <img src="../img/admin/disabled.gif" alt="'.$this->l('No').'" title="'.$this->l('No').'" style="margin-left: 10px;" /> '.$this->l('No').' <input type="radio" name="ps_layered_filter_index_category" value="0" '.(!Configuration::get('PS_LAYERED_FILTER_INDEX_CAT') ? 'checked="checked"' : '').' /> </td> </tr> </table> <p style="text-align: center;"><input type="submit" class="button" name="submitLayeredSettings" value="'.$this->l('Save configuration').'" /></p> </form> </fieldset>'; return $html; } private function getSelectedFilters() { $id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)); if ($id_parent == 1) return; // Force attributes selection (by url '.../2-mycategory/color-blue' or by get parameter 'selected_filters') if (strpos($_SERVER['SCRIPT_FILENAME'], 'blocklayered-ajax.php') === false || Tools::getValue('selected_filters') !== false) { if (Tools::getValue('selected_filters')) $url = Tools::getValue('selected_filters'); else $url = preg_replace('/\/(?:\w*)\/(?:[0-9]+[-\w]*)([^\?]*)\??.*/', '$1', Tools::safeOutput($_SERVER['REQUEST_URI'], true)); $url_attributes = explode('/', ltrim($url, '/')); $selected_filters = array('category' => array()); if (!empty($url_attributes)) { foreach ($url_attributes as $url_attribute) { $url_parameters = explode('-', $url_attribute); $attribute_name = array_shift($url_parameters); if ($attribute_name == 'page') $this->page = (int)$url_parameters[0]; else if (in_array($attribute_name, array('price', 'weight'))) $selected_filters[$attribute_name] = array($url_parameters[0], $url_parameters[1]); else { foreach ($url_parameters as $url_parameter) { $data = Db::getInstance()->getValue('SELECT data FROM `'._DB_PREFIX_.'layered_friendly_url` WHERE `url_key` = \''.md5('/'.$attribute_name.'-'.$url_parameter).'\''); if ($data) foreach (self::unSerialize($data) as $key_params => $params) { if (!isset($selected_filters[$key_params])) $selected_filters[$key_params] = array(); foreach ($params as $key_param => $param) { if (!isset($selected_filters[$key_params][$key_param])) $selected_filters[$key_params][$key_param] = array(); $selected_filters[$key_params][$key_param] = $param; } } } } } return $selected_filters; } } /* Analyze all the filters selected by the user and store them into a tab */ $selected_filters = array('category' => array(), 'manufacturer' => array(), 'quantity' => array(), 'condition' => array()); foreach ($_GET as $key => $value) if (substr($key, 0, 8) == 'layered_') { preg_match('/^(.*)_([0-9]+|new|used|refurbished|slider)$/', substr($key, 8, strlen($key) - 8), $res); if (isset($res[1])) { $tmp_tab = explode('_', $value); $value = $tmp_tab[0]; $id_key = false; if (isset($tmp_tab[1])) $id_key = $tmp_tab[1]; if ($res[1] == 'condition' && in_array($value, array('new', 'used', 'refurbished'))) $selected_filters['condition'][] = $value; else if ($res[1] == 'quantity' && (!$value || $value == 1)) $selected_filters['quantity'][] = $value; else if (in_array($res[1], array('category', 'manufacturer'))) { if (!isset($selected_filters[$res[1].($id_key ? '_'.$id_key : '')])) $selected_filters[$res[1].($id_key ? '_'.$id_key : '')] = array(); $selected_filters[$res[1].($id_key ? '_'.$id_key : '')][] = (int)$value; } else if (in_array($res[1], array('id_attribute_group', 'id_feature'))) { if (!isset($selected_filters[$res[1]])) $selected_filters[$res[1]] = array(); $selected_filters[$res[1]][(int)$value] = $id_key.'_'.(int)$value; } else if ($res[1] == 'weight') $selected_filters[$res[1]] = $tmp_tab; else if ($res[1] == 'price') $selected_filters[$res[1]] = $tmp_tab; } } return $selected_filters; } public function getProductByFilters($selected_filters = array()) { global $cookie; if (!empty($this->products)) return $this->products; /* If the current category isn't defined or if it's homepage, we have nothing to display */ $id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)); if ($id_parent == 1) return false; $alias_where = 'p'; if (version_compare(_PS_VERSION_,'1.5','>')) $alias_where = 'product_shop'; $query_filters_where = ' AND '.$alias_where.'.`active` = 1'; $query_filters_from = ''; $parent = new Category((int)$id_parent); if (!count($selected_filters['category'])) { if (Configuration::get('PS_LAYERED_FULL_TREE')) $query_filters_from .= ' INNER JOIN '._DB_PREFIX_.'category_product cp ON p.id_product = cp.id_product INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1)'; else $query_filters_from .= ' INNER JOIN '._DB_PREFIX_.'category_product cp ON p.id_product = cp.id_product INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND c.id_category = '.(int)$id_parent.' AND c.active = 1)'; } foreach ($selected_filters as $key => $filter_values) { if (!count($filter_values)) continue; preg_match('/^(.*[^_0-9])/', $key, $res); $key = $res[1]; switch ($key) { case 'id_feature': $sub_queries = array(); foreach ($filter_values as $filter_value) { $filter_value_array = explode('_', $filter_value); if (!isset($sub_queries[$filter_value_array[0]])) $sub_queries[$filter_value_array[0]] = array(); $sub_queries[$filter_value_array[0]][] = 'fp.`id_feature_value` = '.(int)$filter_value_array[1]; } foreach ($sub_queries as $sub_query) { $query_filters_where .= ' AND p.id_product IN (SELECT `id_product` FROM `'._DB_PREFIX_.'feature_product` fp WHERE '; $query_filters_where .= implode(' OR ', $sub_query).') '; } break; case 'id_attribute_group': $sub_queries = array(); foreach ($filter_values as $filter_value) { $filter_value_array = explode('_', $filter_value); if (!isset($sub_queries[$filter_value_array[0]])) $sub_queries[$filter_value_array[0]] = array(); $sub_queries[$filter_value_array[0]][] = 'pac.`id_attribute` = '.(int)$filter_value_array[1]; } foreach ($sub_queries as $sub_query) { $query_filters_where .= ' AND p.id_product IN (SELECT pa.`id_product` FROM `'._DB_PREFIX_.'product_attribute_combination` pac LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (pa.`id_product_attribute` = pac.`id_product_attribute`)'; if (version_compare(_PS_VERSION_,'1.5','>')) $query_filters_where .= Shop::addSqlAssociation('product_attribute', 'pa'); $query_filters_where .= 'WHERE '.implode(' OR ', $sub_query).') '; } break; case 'category': $query_filters_where .= ' AND p.id_product IN (SELECT id_product FROM '._DB_PREFIX_.'category_product cp WHERE '; foreach ($selected_filters['category'] as $id_category) $query_filters_where .= 'cp.`id_category` = '.(int)$id_category.' OR '; $query_filters_where = rtrim($query_filters_where, 'OR ').')'; break; case 'quantity': if (count($selected_filters['quantity']) == 2) break; if (version_compare(_PS_VERSION_,'1.5','>')) { $query_filters_where .= ' AND sa.quantity '.(!$selected_filters['quantity'][0] ? '<=' : '>').' 0 '; $query_filters_from .= 'LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON (sa.id_product = p.id_product AND sa.id_shop = '.(int)Context::getContext()->shop->id.') '; } else $query_filters_where .= ' AND p.quantity '.(!$selected_filters['quantity'][0] ? '<=' : '>').' 0 '; break; case 'manufacturer': $query_filters_where .= ' AND p.id_manufacturer IN ('.implode($selected_filters['manufacturer'], ',').')'; break; case 'condition': if (count($selected_filters['condition']) == 3) break; $query_filters_where .= ' AND '.$alias_where.'.condition IN ('; foreach ($selected_filters['condition'] as $cond) $query_filters_where .= '\''.$cond.'\','; $query_filters_where = rtrim($query_filters_where, ',').')'; break; case 'weight': if ($selected_filters['weight'][0] != 0 || $selected_filters['weight'][1] != 0) $query_filters_where .= ' AND p.`weight` BETWEEN '.(float)($selected_filters['weight'][0] - 0.001).' AND '.(float)($selected_filters['weight'][1] + 0.001); case 'price': if (isset($selected_filters['price'])) { if ($selected_filters['price'][0] !== '' || $selected_filters['price'][1] !== '') { $price_filter = array(); $price_filter['min'] = (float)($selected_filters['price'][0]); $price_filter['max'] = (float)($selected_filters['price'][1]); } } else $price_filter = false; break; } } if (version_compare(_PS_VERSION_,'1.5','>')) $id_currency = (int)Context::getContext()->currency->id; else $id_currency = (int)Currency::getCurrent()->id; $price_filter_query_in = ''; // All products with price range between price filters limits $price_filter_query_out = ''; // All products with a price filters limit on it price range if (isset($price_filter) && $price_filter) { $price_filter_query_in = 'INNER JOIN `'._DB_PREFIX_.'layered_price_index` psi ON ( psi.price_min >= '.(int)$price_filter['min'].' AND psi.price_max <= '.(int)$price_filter['max'].' AND psi.`id_product` = p.`id_product` AND psi.`id_currency` = '.$id_currency.' )'; $price_filter_query_out = 'INNER JOIN `'._DB_PREFIX_.'layered_price_index` psi ON ((psi.price_min < '.(int)$price_filter['min'].' AND psi.price_max > '.(int)$price_filter['min'].') OR (psi.price_max > '.(int)$price_filter['max'].' AND psi.price_min < '.(int)$price_filter['max'].')) AND psi.`id_product` = p.`id_product` AND psi.`id_currency` = '.$id_currency; } if (version_compare(_PS_VERSION_,'1.5','>')) $query_filters_from .= Shop::addSqlAssociation('product', 'p'); $all_products_out = self::query(' SELECT p.`id_product` id_product FROM `'._DB_PREFIX_.'product` p '.$price_filter_query_out.' '.$query_filters_from.' WHERE 1 '.$query_filters_where.' GROUP BY id_product'); $all_products_in = self::query(' SELECT p.`id_product` id_product FROM `'._DB_PREFIX_.'product` p '.$price_filter_query_in.' '.$query_filters_from.' WHERE 1 '.$query_filters_where.' GROUP BY id_product'); $product_id_list = array(); while ($product = DB::getInstance()->nextRow($all_products_in)) $product_id_list[] = (int)$product['id_product']; while ($product = DB::getInstance()->nextRow($all_products_out)) if (isset($price_filter) && $price_filter) { $price = (int)Product::getPriceStatic($product['id_product'], Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX')); // Cast to int because we don't care about cents if ($price < $price_filter['min'] || $price > $price_filter['max']) continue; $product_id_list[] = (int)$product['id_product']; } $this->nbr_products = count($product_id_list); if ($this->nbr_products == 0) $this->products = array(); else { $n = (int)Tools::getValue('n', Configuration::get('PS_PRODUCTS_PER_PAGE')); $join = ''; if (version_compare(_PS_VERSION_,'1.5','>')) $join = Shop::addSqlAssociation('product', 'p'); $this->products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT p.*, '.($alias_where == 'p' ? '' : 'product_shop.*,' ).' '.$alias_where.'.id_category_default, pl.*, i.id_image, il.legend, m.name manufacturer_name, DATEDIFF('.$alias_where.'.`date_add`, DATE_SUB(NOW(), INTERVAL '.(Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20).' DAY)) > 0 AS new FROM `'._DB_PREFIX_.'category_product` cp LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` '.$join.' LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product'.Shop::addSqlRestrictionOnLang('pl').') LEFT JOIN '._DB_PREFIX_.'image i ON (i.id_product = p.id_product AND i.cover = 1) LEFT JOIN '._DB_PREFIX_.'image_lang il ON (i.id_image = il.id_image AND il.id_lang = '.(int)($cookie->id_lang).') LEFT JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) WHERE '.$alias_where.'.`active` = 1 AND '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1 AND pl.id_lang = '.(int)$cookie->id_lang.' AND p.id_product IN ('.implode(',', $product_id_list).')' .' GROUP BY p.id_product ORDER BY '.Tools::getProductsOrder('by', Tools::getValue('orderby'), true).' '.Tools::getProductsOrder('way', Tools::getValue('orderway')). ' LIMIT '.(((int)$this->page - 1) * $n.','.$n)); } if (Tools::getProductsOrder('by', Tools::getValue('orderby'), true) == 'p.price') Tools::orderbyPrice($this->products, Tools::getProductsOrder('way', Tools::getValue('orderway'))); return $this->products; } private static function query($sql_query) { if (version_compare(_PS_VERSION_,'1.5','>')) return Db::getInstance(_PS_USE_SQL_SLAVE_)->query($sql_query); else return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql_query, false); } public function getFilterBlock($selected_filters = array()) { global $cookie; static $cache = null; if (version_compare(_PS_VERSION_,'1.5','>')) { $id_lang = Context::getContext()->language->id; $currency = Context::getContext()->currency; $id_shop = (int) Context::getContext()->shop->id; $alias = 'product_shop'; } else { $id_lang = (int)$cookie->id_lang; $currency = Currency::getCurrent(); $id_shop = 0; $alias = 'p'; } if (is_array($cache)) return $cache; $id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', 1)); if ($id_parent == 1) return; $parent = new Category((int)$id_parent, $id_lang); /* Get the filters for the current category */ $filters = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM '._DB_PREFIX_.'layered_category WHERE id_category = '.(int)$id_parent.' AND id_shop = '.$id_shop.' GROUP BY `type`, id_value ORDER BY position ASC'); // Remove all empty selected filters foreach ($selected_filters as $key => $value) switch ($key) { case 'price': case 'weight': if ($value[0] === '' && $value[1] === '') unset($selected_filters[$key]); break; default: if ($value == '') unset($selected_filters[$key]); break; } $filter_blocks = array(); foreach ($filters as $filter) { $sql_query = array('select' => '', 'from' => '', 'join' => '', 'where' => '', 'group' => '', 'second_query' => ''); switch ($filter['type']) { // conditions + quantities + weight + price case 'price': case 'weight': case 'condition': case 'quantity': if (version_compare(_PS_VERSION_,'1.5','>')) $sql_query['select'] = 'SELECT p.`id_product`, product_shop.`condition`, p.`id_manufacturer`, sa.`quantity`, p.`weight` '; else $sql_query['select'] = 'SELECT p.`id_product`, p.`condition`, p.`id_manufacturer`, p.`quantity`, p.`weight` '; $sql_query['from'] = ' FROM '._DB_PREFIX_.'product p '; $sql_query['join'] = ' INNER JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = p.id_product) INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1) '; if (version_compare(_PS_VERSION_,'1.5','>')) { $sql_query['join'] .= 'LEFT JOIN `'._DB_PREFIX_.'stock_available` sa ON (sa.id_product = p.id_product AND sa.id_shop = '.(int)$this->context->shop->id.') '; $sql_query['where'] = 'WHERE product_shop.`active` = 1 '; } else $sql_query['where'] = 'WHERE p.`active` = 1 '; $sql_query['group'] = ' GROUP BY p.id_product '; break; case 'manufacturer': $sql_query['select'] = 'SELECT m.name, COUNT(DISTINCT p.id_product) nbr, m.id_manufacturer '; $sql_query['from'] = ' FROM `'._DB_PREFIX_.'category_product` cp INNER JOIN `'._DB_PREFIX_.'category` c ON (c.id_category = cp.id_category) INNER JOIN '._DB_PREFIX_.'product p ON (p.id_product = cp.id_product) INNER JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) '; $sql_query['where'] = 'WHERE '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1 AND '.$alias.'.active = 1'; $sql_query['group'] = ' GROUP BY p.id_manufacturer '; if (!Configuration::get('PS_LAYERED_HIDE_0_VALUES')) { $sql_query['second_query'] = ' SELECT m.name, 0 nbr, m.id_manufacturer FROM `'._DB_PREFIX_.'category_product` cp '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product', 'cp') : '').' INNER JOIN `'._DB_PREFIX_.'category` c ON (c.id_category = cp.id_category) INNER JOIN '._DB_PREFIX_.'product p ON (p.id_product = cp.id_product) INNER JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) WHERE '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1 AND '.$alias.'.active = 1 GROUP BY p.id_manufacturer'; } break; case 'id_attribute_group':// attribute group $sql_query['select'] = ' SELECT COUNT(DISTINCT p.id_product) nbr, lpa.id_attribute_group, a.color, al.name attribute_name, agl.public_name attribute_group_name , lpa.id_attribute, ag.is_color_group, liagl.url_name name_url_name, liagl.meta_title name_meta_title, lial.url_name value_url_name, lial.meta_title value_meta_title'; $sql_query['from'] = ' FROM '._DB_PREFIX_.'layered_product_attribute lpa INNER JOIN '._DB_PREFIX_.'attribute a ON a.id_attribute = lpa.id_attribute INNER JOIN '._DB_PREFIX_.'attribute_lang al ON al.id_attribute = a.id_attribute AND al.id_lang = '.$id_lang.' INNER JOIN '._DB_PREFIX_.'product as p ON p.id_product = lpa.id_product INNER JOIN '._DB_PREFIX_.'attribute_group ag ON ag.id_attribute_group = lpa.id_attribute_group INNER JOIN '._DB_PREFIX_.'attribute_group_lang agl ON agl.id_attribute_group = lpa.id_attribute_group AND agl.id_lang = '.$id_lang.' LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value liagl ON (liagl.id_attribute_group = lpa.id_attribute_group AND liagl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial ON (lial.id_attribute = lpa.id_attribute AND lial.id_lang = '.$id_lang.') '; $sql_query['where'] = 'WHERE a.id_attribute_group = '.(int)$filter['id_value']; if (version_compare(_PS_VERSION_,'1.5','>')) $sql_query['where'] .= ' AND lpa.`id_shop` = '.(int)Context::getContext()->shop->id; $sql_query['where'] .= ' AND '.$alias.'.active = 1 AND p.id_product IN ( SELECT id_product FROM '._DB_PREFIX_.'category_product cp INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1)) '; $sql_query['group'] = ' GROUP BY lpa.id_attribute ORDER BY id_attribute_group, id_attribute '; if (!Configuration::get('PS_LAYERED_HIDE_0_VALUES')) { $sql_query['second_query'] = ' SELECT 0 nbr, lpa.id_attribute_group, a.color, al.name attribute_name, agl.public_name attribute_group_name , lpa.id_attribute, ag.is_color_group, liagl.url_name name_url_name, liagl.meta_title name_meta_title, lial.url_name value_url_name, lial.meta_title value_meta_title FROM '._DB_PREFIX_.'layered_product_attribute lpa '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product', 'lpa') : '').' INNER JOIN '._DB_PREFIX_.'attribute a ON a.id_attribute = lpa.id_attribute INNER JOIN '._DB_PREFIX_.'attribute_lang al ON al.id_attribute = a.id_attribute AND al.id_lang = '.$id_lang.' INNER JOIN '._DB_PREFIX_.'product as p ON p.id_product = lpa.id_product INNER JOIN '._DB_PREFIX_.'attribute_group ag ON ag.id_attribute_group = lpa.id_attribute_group INNER JOIN '._DB_PREFIX_.'attribute_group_lang agl ON agl.id_attribute_group = lpa.id_attribute_group AND agl.id_lang = '.$id_lang.' LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value liagl ON (liagl.id_attribute_group = lpa.id_attribute_group AND liagl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial ON (lial.id_attribute = lpa.id_attribute AND lial.id_lang = '.$id_lang.') WHERE '.$alias.'.active = 1 AND a.id_attribute_group = '.(int)$filter['id_value'].' '.(version_compare(_PS_VERSION_,'1.5','>') ? 'AND lpa.`id_shop` = '.(int)Context::getContext()->shop->id : '').' GROUP BY lpa.id_attribute ORDER BY id_attribute_group, id_attribute'; } break; case 'id_feature': $sql_query['select'] = 'SELECT fl.name feature_name, fp.id_feature, fv.id_feature_value, fvl.value, COUNT(DISTINCT p.id_product) nbr, lifl.url_name name_url_name, lifl.meta_title name_meta_title, lifvl.url_name value_url_name, lifvl.meta_title value_meta_title '; $sql_query['from'] = ' FROM '._DB_PREFIX_.'feature_product fp INNER JOIN '._DB_PREFIX_.'product p ON (p.id_product = fp.id_product) LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = fp.id_feature AND fl.id_lang = '.$id_lang.') INNER JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature_value = fp.id_feature_value AND (fv.custom IS NULL OR fv.custom = 0)) LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fp.id_feature_value AND fvl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_lang_value lifl ON (lifl.id_feature = fp.id_feature AND lifl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_value_lang_value lifvl ON (lifvl.id_feature_value = fp.id_feature_value AND lifvl.id_lang = '.$id_lang.') '; $sql_query['where'] = 'WHERE '.$alias.'.`active` = 1 AND fp.id_feature = '.(int)$filter['id_value'].' AND p.id_product IN ( SELECT id_product FROM '._DB_PREFIX_.'category_product cp INNER JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category AND '.(Configuration::get('PS_LAYERED_FULL_TREE') ? 'c.nleft >= '.(int)$parent->nleft.' AND c.nright <= '.(int)$parent->nright : 'c.id_category = '.(int)$id_parent).' AND c.active = 1)) '; $sql_query['group'] = 'GROUP BY fv.id_feature_value '; if (!Configuration::get('PS_LAYERED_HIDE_0_VALUES')) { $sql_query['second_query'] = ' SELECT fl.name feature_name, fp.id_feature, fv.id_feature_value, fvl.value, 0 nbr, lifl.url_name name_url_name, lifl.meta_title name_meta_title, lifvl.url_name value_url_name, lifvl.meta_title value_meta_title FROM '._DB_PREFIX_.'feature_product fp '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product', 'fp') : '').' INNER JOIN '._DB_PREFIX_.'product p ON (p.id_product = fp.id_product) LEFT JOIN '._DB_PREFIX_.'feature_lang fl ON (fl.id_feature = fp.id_feature AND fl.id_lang = '.$id_lang.') INNER JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature_value = fp.id_feature_value AND (fv.custom IS NULL OR fv.custom = 0)) LEFT JOIN '._DB_PREFIX_.'feature_value_lang fvl ON (fvl.id_feature_value = fp.id_feature_value AND fvl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_lang_value lifl ON (lifl.id_feature = fp.id_feature AND lifl.id_lang = '.$id_lang.') LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_value_lang_value lifvl ON (lifvl.id_feature_value = fp.id_feature_value AND lifvl.id_lang = '.$id_lang.') WHERE '.$alias.'.`active` = 1 AND fp.id_feature = '.(int)$filter['id_value'].' GROUP BY fv.id_feature_value'; } break; case 'category': $depth = Configuration::get('PS_LAYERED_FILTER_CATEGORY_DEPTH'); if ($depth === false) $depth = 1; $sql_query['select'] = ' SELECT c.id_category, c.id_parent, cl.name, (SELECT count(DISTINCT p.id_product) # '; $sql_query['from'] = ' FROM '._DB_PREFIX_.'category_product cp LEFT JOIN '._DB_PREFIX_.'product p ON (p.id_product = cp.id_product) '; $sql_query['where'] = ' WHERE cp.id_category = c.id_category AND '.$alias.'.active = 1 '; $sql_query['group'] = ') count_products FROM '._DB_PREFIX_.'category c LEFT JOIN '._DB_PREFIX_.'category_lang cl ON (cl.id_category = c.id_category AND cl.id_lang = '.$id_lang.') WHERE c.nleft > '.(int)$parent->nleft.' AND c.nright < '.(int)$parent->nright.' '.($depth ? 'AND c.level_depth <= '.($parent->level_depth+(int)$depth) : '').' GROUP BY c.id_category ORDER BY c.nleft, c.position'; } foreach ($filters as $filter_tmp) { $method_name = 'get'.ucfirst($filter_tmp['type']).'FilterSubQuery'; if (method_exists('BlockLayered', $method_name) && (!in_array($filter['type'], array('price', 'weight')) && $filter['type'] != $filter_tmp['type'] || $filter['type'] == $filter_tmp['type'])) { if ($filter['type'] == $filter_tmp['type'] && $filter['id_value'] == $filter_tmp['id_value']) $sub_query_filter = self::$method_name(array(), true); else { if (!is_null($filter_tmp['id_value'])) $selected_filters_cleaned = $this->cleanFilterByIdValue(@$selected_filters[$filter_tmp['type']], $filter_tmp['id_value']); else $selected_filters_cleaned = @$selected_filters[$filter_tmp['type']]; $sub_query_filter = self::$method_name($selected_filters_cleaned, $filter['type'] == $filter_tmp['type']); } foreach ($sub_query_filter as $key => $value) $sql_query[$key] .= $value; } } $products = false; if (!empty($sql_query['from'])) { if (version_compare(_PS_VERSION_,'1.5','>')) $sql_query['from'] .= Shop::addSqlAssociation('product', 'p'); $products = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql_query['select']."\n".$sql_query['from']."\n".$sql_query['join']."\n".$sql_query['where']."\n".$sql_query['group']); } foreach ($filters as $filter_tmp) { $method_name = 'filterProductsBy'.ucfirst($filter_tmp['type']); if (method_exists('BlockLayered', $method_name) && (!in_array($filter['type'], array('price', 'weight')) && $filter['type'] != $filter_tmp['type'] || $filter['type'] == $filter_tmp['type'])) if ($filter['type'] == $filter_tmp['type']) $products = self::$method_name(array(), $products); else $products = self::$method_name(@$selected_filters[$filter_tmp['type']], $products); } if (!empty($sql_query['second_query'])) { $res = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql_query['second_query']); if ($res) $products = array_merge($products, $res); } switch ($filter['type']) { case 'price': $price_array = array( 'type_lite' => 'price', 'type' => 'price', 'id_key' => 0, 'name' => $this->l('Price'), 'slider' => true, 'max' => '0', 'min' => null, 'values' => array ('1' => 0), 'unit' => $currency->sign, 'format' => $currency->format, 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); if (isset($products) && $products) foreach ($products as $product) { if (is_null($price_array['min'])) { $price_array['min'] = $product['price_min']; $price_array['values'][0] = $product['price_min']; } else if ($price_array['min'] > $product['price_min']) { $price_array['min'] = $product['price_min']; $price_array['values'][0] = $product['price_min']; } if ($price_array['max'] < $product['price_max']) { $price_array['max'] = $product['price_max']; $price_array['values'][1] = $product['price_max']; } } if ($price_array['max'] != $price_array['min'] && $price_array['min'] != null) { if ($filter['filter_type'] == 2) { $price_array['list_of_values'] = array(); $nbr_of_value = $filter['filter_show_limit']; if ($nbr_of_value < 2) $nbr_of_value = 4; $delta = ($price_array['max'] - $price_array['min']) / $nbr_of_value; $current_step = $price_array['min']; for ($i = 0; $i < $nbr_of_value; $i++) $price_array['list_of_values'][] = array( (int)($price_array['min'] + $i * $delta), (int)($price_array['min'] + ($i + 1) * $delta) ); } if (isset($selected_filters['price']) && isset($selected_filters['price'][0]) && isset($selected_filters['price'][1])) { $price_array['values'][0] = $selected_filters['price'][0]; $price_array['values'][1] = $selected_filters['price'][1]; } $filter_blocks[] = $price_array; } break; case 'weight': $weight_array = array( 'type_lite' => 'weight', 'type' => 'weight', 'id_key' => 0, 'name' => $this->l('Weight'), 'slider' => true, 'max' => '0', 'min' => null, 'values' => array ('1' => 0), 'unit' => Configuration::get('PS_WEIGHT_UNIT'), 'format' => 5, // Ex: xxxxx kg 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); if (isset($products) && $products) foreach ($products as $product) { if (is_null($weight_array['min'])) { $weight_array['min'] = $product['weight']; $weight_array['values'][0] = $product['weight']; } else if ($weight_array['min'] > $product['weight']) { $weight_array['min'] = $product['weight']; $weight_array['values'][0] = $product['weight']; } if ($weight_array['max'] < $product['weight']) { $weight_array['max'] = $product['weight']; $weight_array['values'][1] = $product['weight']; } } if ($weight_array['max'] != $weight_array['min'] && $weight_array['min'] != null) { if (isset($selected_filters['weight']) && isset($selected_filters['weight'][0]) && isset($selected_filters['weight'][1])) { $weight_array['values'][0] = $selected_filters['weight'][0]; $weight_array['values'][1] = $selected_filters['weight'][1]; } $filter_blocks[] = $weight_array; } break; case 'condition': $condition_array = array( 'new' => array('name' => $this->l('New'),'nbr' => 0), 'used' => array('name' => $this->l('Used'), 'nbr' => 0), 'refurbished' => array('name' => $this->l('Refurbished'), 'nbr' => 0) ); if (isset($products) && $products) foreach ($products as $product) if (isset($selected_filters['condition']) && in_array($product['condition'], $selected_filters['condition'])) $condition_array[$product['condition']]['checked'] = true; foreach ($condition_array as $key => $condition) if (isset($selected_filters['condition']) && in_array($key, $selected_filters['condition'])) $condition_array[$key]['checked'] = true; if (isset($products) && $products) foreach ($products as $product) if (isset($condition_array[$product['condition']])) $condition_array[$product['condition']]['nbr']++; $filter_blocks[] = array( 'type_lite' => 'condition', 'type' => 'condition', 'id_key' => 0, 'name' => $this->l('Condition'), 'values' => $condition_array, 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); break; case 'quantity': $quantity_array = array ( 0 => array('name' => $this->l('Not available'), 'nbr' => 0), 1 => array('name' => $this->l('In stock'), 'nbr' => 0)); foreach ($quantity_array as $key => $quantity) if (isset($selected_filters['quantity']) && in_array($key, $selected_filters['quantity'])) $quantity_array[$key]['checked'] = true; if (isset($products) && $products) foreach ($products as $product) $quantity_array[(int)($product['quantity'] > 0)]['nbr']++; $filter_blocks[] = array( 'type_lite' => 'quantity', 'type' => 'quantity', 'id_key' => 0, 'name' => $this->l('Availability'), 'values' => $quantity_array, 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); break; case 'manufacturer': if (isset($products) && $products) { $manufaturers_array = array(); foreach ($products as $manufacturer) { if (!isset($manufaturers_array[$manufacturer['id_manufacturer']])) $manufaturers_array[$manufacturer['id_manufacturer']] = array('name' => $manufacturer['name'], 'nbr' => $manufacturer['nbr']); if (isset($selected_filters['manufacturer']) && in_array((int)$manufacturer['id_manufacturer'], $selected_filters['manufacturer'])) $manufaturers_array[$manufacturer['id_manufacturer']]['checked'] = true; } $filter_blocks[] = array( 'type_lite' => 'manufacturer', 'type' => 'manufacturer', 'id_key' => 0, 'name' => $this->l('Manufacturer'), 'values' => $manufaturers_array, 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); } break; case 'id_attribute_group': $attributes_array = array(); if (isset($products) && $products) { foreach ($products as $attributes) { if (!isset($attributes_array[$attributes['id_attribute_group']])) $attributes_array[$attributes['id_attribute_group']] = array ( 'type_lite' => 'id_attribute_group', 'type' => 'id_attribute_group', 'id_key' => (int)$attributes['id_attribute_group'], 'name' => $attributes['attribute_group_name'], 'is_color_group' => (bool)$attributes['is_color_group'], 'values' => array(), 'url_name' => $attributes['name_url_name'], 'meta_title' => $attributes['name_meta_title'], 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); if (!isset($attributes_array[$attributes['id_attribute_group']]['values'][$attributes['id_attribute']])) $attributes_array[$attributes['id_attribute_group']]['values'][$attributes['id_attribute']] = array( 'color' => $attributes['color'], 'name' => $attributes['attribute_name'], 'nbr' => (int)$attributes['nbr'], 'url_name' => $attributes['value_url_name'], 'meta_title' => $attributes['value_meta_title'] ); if (isset($selected_filters['id_attribute_group'][$attributes['id_attribute']])) $attributes_array[$attributes['id_attribute_group']]['values'][$attributes['id_attribute']]['checked'] = true; } $filter_blocks = array_merge($filter_blocks, $attributes_array); } break; case 'id_feature': $feature_array = array(); if (isset($products) && $products) { foreach ($products as $feature) { if (!isset($feature_array[$feature['id_feature']])) $feature_array[$feature['id_feature']] = array( 'type_lite' => 'id_feature', 'type' => 'id_feature', 'id_key' => (int)$feature['id_feature'], 'values' => array(), 'name' => $feature['feature_name'], 'url_name' => $feature['name_url_name'], 'meta_title' => $feature['name_meta_title'], 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); if (!isset($feature_array[$feature['id_feature']]['values'][$feature['id_feature_value']])) $feature_array[$feature['id_feature']]['values'][$feature['id_feature_value']] = array( 'nbr' => (int)$feature['nbr'], 'name' => $feature['value'], 'url_name' => $feature['value_url_name'], 'meta_title' => $feature['value_meta_title'] ); if (isset($selected_filters['id_feature'][$feature['id_feature_value']])) $feature_array[$feature['id_feature']]['values'][$feature['id_feature_value']]['checked'] = true; } $filter_blocks = array_merge($filter_blocks, $feature_array); } break; case 'category': $tmp_array = array(); if (isset($products) && $products) { $categories_with_products_count = 0; foreach ($products as $category) { $tmp_array[$category['id_category']] = array( 'name' => $category['name'], 'nbr' => (int)$category['count_products'] ); if ((int)$category['count_products']) $categories_with_products_count++; if (isset($selected_filters['category']) && in_array($category['id_category'], $selected_filters['category'])) $tmp_array[$category['id_category']]['checked'] = true; } if ($categories_with_products_count || !Configuration::get('PS_LAYERED_HIDE_0_VALUES')) $filter_blocks[] = array ( 'type_lite' => 'category', 'type' => 'category', 'id_key' => 0, 'name' => $this->l('Categories'), 'values' => $tmp_array, 'filter_show_limit' => $filter['filter_show_limit'], 'filter_type' => $filter['filter_type'] ); } break; } } // All non indexable attribute and feature $non_indexable = array(); // Get all non indexable attribute groups foreach (Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT public_name FROM `'._DB_PREFIX_.'attribute_group_lang` agl LEFT JOIN `'._DB_PREFIX_.'layered_indexable_attribute_group` liag ON liag.id_attribute_group = agl.id_attribute_group WHERE indexable IS NULL OR indexable = 0 AND id_lang = '.$id_lang) as $attribute) $non_indexable[] = Tools::link_rewrite($attribute['public_name']); // Get all non indexable features foreach (Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT name FROM `'._DB_PREFIX_.'feature_lang` fl LEFT JOIN `'._DB_PREFIX_.'layered_indexable_feature` lif ON lif.id_feature = fl.id_feature WHERE indexable IS NULL OR indexable = 0 AND id_lang = '.$id_lang) as $attribute) $non_indexable[] = Tools::link_rewrite($attribute['name']); //generate SEO link $param_selected = ''; $param_product_url = ''; $option_checked_array = array(); $param_group_selected_array = array(); $title_values = array(); $meta_values = array(); //get filters checked by group foreach ($filter_blocks as $type_filter) { $filter_name = (!empty($type_filter['url_name']) ? $type_filter['url_name'] : $type_filter['name']); $filter_meta = (!empty($type_filter['meta_title']) ? $type_filter['meta_title'] : ''); $attr_key = $type_filter['type'].'_'.$type_filter['id_key']; $param_group_selected = ''; foreach ($type_filter['values'] as $key => $value) { if (is_array($value) && array_key_exists('checked', $value )) { $value_name = !empty($value['url_name']) ? $value['url_name'] : $value['name']; $value_meta = !empty($value['meta_title']) ? $value['meta_title'] : $value['name']; $param_group_selected .= '-'.str_replace('-', '_', Tools::link_rewrite($value_name)); $param_group_selected_array[Tools::link_rewrite($filter_name)][] = Tools::link_rewrite($value_name); if (!isset($title_values[$filter_name])) $title_values[$filter_name] = array(); $title_values[$filter_name][] = $value_name; if (!isset($meta_values[$attr_key])) $meta_values[$attr_key] = array('title' => $filter_meta, 'values' => array()); $meta_values[$attr_key]['values'][] = $value_meta; } else $param_group_selected_array[Tools::link_rewrite($filter_name)][] = array(); } if (!empty($param_group_selected)) { $param_selected .= '/'.str_replace('-', '_', Tools::link_rewrite($filter_name)).$param_group_selected; $option_checked_array[Tools::link_rewrite($filter_name)] = $param_group_selected; } // select only attribute and group attribute to display an unique product combination link if (!empty($param_group_selected) && $type_filter['type'] == 'id_attribute_group') $param_product_url .= '/'.str_replace('-', '_', Tools::link_rewrite($filter_name)).$param_group_selected; } if ($this->page > 1) $param_selected .= '/page-'.$this->page; $blacklist = array('weight', 'price'); if (!Configuration::get('PS_LAYERED_FILTER_INDEX_CDT')) $blacklist[] = 'condition'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_QTY')) $blacklist[] = 'quantity'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_MNF')) $blacklist[] = 'manufacturer'; if (!Configuration::get('PS_LAYERED_FILTER_INDEX_CAT')) $blacklist[] = 'category'; $global_nofollow = false; foreach ($filter_blocks as &$type_filter) { $filter_name = (!empty($type_filter['url_name']) ? $type_filter['url_name'] : $type_filter['name']); if (count($type_filter) > 0 && !isset($type_filter['slider'])) { foreach ($type_filter['values'] as $key => $values) { $nofollow = false; if (!empty($values['checked']) && in_array($type_filter['type'], $blacklist)) $global_nofollow = true; $option_checked_clone_array = $option_checked_array; // If not filters checked, add parameter $value_name = !empty($values['url_name']) ? $values['url_name'] : $values['name']; if (!in_array(Tools::link_rewrite($value_name), $param_group_selected_array[Tools::link_rewrite($filter_name)])) { // Update parameter filter checked before if (array_key_exists(Tools::link_rewrite($filter_name), $option_checked_array)) { $option_checked_clone_array[Tools::link_rewrite($filter_name)] = $option_checked_clone_array[Tools::link_rewrite($filter_name)].'-'.str_replace('-', '_', Tools::link_rewrite($value_name)); $nofollow = true; } else $option_checked_clone_array[Tools::link_rewrite($filter_name)] = '-'.str_replace('-', '_', Tools::link_rewrite($value_name)); } else { // Remove selected parameters $option_checked_clone_array[Tools::link_rewrite($filter_name)] = str_replace('-'.str_replace('-', '_', Tools::link_rewrite($value_name)), '', $option_checked_clone_array[Tools::link_rewrite($filter_name)]); if (empty($option_checked_clone_array[Tools::link_rewrite($filter_name)])) unset($option_checked_clone_array[Tools::link_rewrite($filter_name)]); } $parameters = ''; ksort($option_checked_clone_array); // Order parameters foreach ($option_checked_clone_array as $key_group => $value_group) $parameters .= '/'.str_replace('-', '_', $key_group).$value_group; // Check if there is an non indexable attribute or feature in the url foreach ($non_indexable as $value) if (strpos($parameters, '/'.$value) !== false) $nofollow = true; if (version_compare(_PS_VERSION_,'1.5','>')) $type_filter['values'][$key]['link'] = Context::getContext()->link->getCategoryLink($parent, null, null, ltrim($parameters, '/')); else { $link = new Link(); $link_base = $link->getCategoryLink($id_parent, Category::getLinkRewrite($id_parent, $id_lang), $id_lang); // Write link by mode rewriting if (!Configuration::get('PS_REWRITING_SETTINGS')) $type_filter['values'][$key]['link'] = $link_base.'&selected_filters='.$parameters; else $type_filter['values'][$key]['link'] = $link_base.$parameters; } $type_filter['values'][$key]['rel'] = ($nofollow) ? 'nofollow' : ''; } } } $n_filters = 0; if (isset($selected_filters['price'])) if ($price_array['min'] == $selected_filters['price'][0] && $price_array['max'] == $selected_filters['price'][1]) unset($selected_filters['price']); if (isset($selected_filters['weight'])) if ($weight_array['min'] == $selected_filters['weight'][0] && $weight_array['max'] == $selected_filters['weight'][1]) unset($selected_filters['weight']); foreach ($selected_filters as $filters) $n_filters += count($filters); $cache = array( 'layered_show_qties' => (int)Configuration::get('PS_LAYERED_SHOW_QTIES'), 'id_category_layered' => (int)$id_parent, 'selected_filters' => $selected_filters, 'n_filters' => (int)$n_filters, 'nbr_filterBlocks' => count($filter_blocks), 'filters' => $filter_blocks, 'title_values' => $title_values, 'meta_values' => $meta_values, 'current_friendly_url' => $param_selected, 'param_product_url' => $param_product_url, 'no_follow' => (!empty($param_selected) || $global_nofollow) ); return $cache; } public function cleanFilterByIdValue($attributes, $id_value) { $selected_filters = array(); if (is_array($attributes)) foreach ($attributes as $attribute) { $attribute_data = explode('_', $attribute); if ($attribute_data[0] == $id_value) $selected_filters[] = $attribute_data[1]; } return $selected_filters; } public function generateFiltersBlock($selected_filters) { global $smarty; if ($filter_block = $this->getFilterBlock($selected_filters)) { if ($filter_block['nbr_filterBlocks'] == 0) return false; $smarty->assign($filter_block); $smarty->assign('hide_0_values', Configuration::get('PS_LAYERED_HIDE_0_VALUES')); return $this->display(__FILE__, 'blocklayered.tpl'); } else return false; } private static function getPriceFilterSubQuery($filter_value) { if (version_compare(_PS_VERSION_,'1.5','>')) $id_currency = (int)Context::getContext()->currency->id; else $id_currency = (int)Currency::getCurrent()->id; if (isset($filter_value) && $filter_value) { $price_filter_query = ' INNER JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product AND psi.id_currency = '.(int)$id_currency.' AND psi.price_min <= '.(int)$filter_value[1].' AND psi.price_max >= '.(int)$filter_value[0].') '; } else { $price_filter_query = ' INNER JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product AND psi.id_currency = '.(int)$id_currency.') '; } return array('join' => $price_filter_query, 'select' => ', psi.price_min, psi.price_max'); } private static function filterProductsByPrice($filter_value, $product_collection) { if (empty($filter_value)) return $product_collection; foreach ($product_collection as $key => $product) { if (isset($filter_value) && $filter_value && isset($product['price_min']) && isset($product['id_product']) && ((int)$filter_value[0] > $product['price_min'] || (int)$filter_value[1] < $product['price_max'])) { $price = Product::getPriceStatic($product['id_product'], Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX')); if ($price < $filter_value[0] || $price > $filter_value[1]) continue; unset($product_collection[$key]); } } return $product_collection; } private static function getWeightFilterSubQuery($filter_value, $ignore_join) { if (isset($filter_value) && $filter_value) if ($filter_value[0] != 0 || $filter_value[1] != 0) return array('where' => ' AND p.`weight` BETWEEN '.(float)($filter_value[0] - 0.001).' AND '.(float)($filter_value[1] + 0.001).' '); return array(); } private static function getId_featureFilterSubQuery($filter_value, $ignore_join) { if (empty($filter_value)) return array(); $query_filters = ' AND p.id_product IN (SELECT id_product FROM '._DB_PREFIX_.'feature_product fp WHERE '; foreach ($filter_value as $filter_val) $query_filters .= 'fp.`id_feature_value` = '.(int)$filter_val.' OR '; $query_filters = rtrim($query_filters, 'OR ').') '; return array('where' => $query_filters); } private static function getId_attribute_groupFilterSubQuery($filter_value, $ignore_join) { if (empty($filter_value)) return array(); $query_filters = ' AND p.id_product IN (SELECT pa.`id_product` FROM `'._DB_PREFIX_.'product_attribute_combination` pac LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (pa.`id_product_attribute` = pac.`id_product_attribute`) WHERE '; foreach ($filter_value as $filter_val) $query_filters .= 'pac.`id_attribute` = '.(int)$filter_val.' OR '; $query_filters = rtrim($query_filters, 'OR ').') '; return array('where' => $query_filters); } private static function getCategoryFilterSubQuery($filter_value, $ignore_join) { if (empty($filter_value)) return array(); $query_filters_join = ''; $query_filters_where = ' AND p.id_product IN (SELECT id_product FROM '._DB_PREFIX_.'category_product cp WHERE '; foreach ($filter_value as $id_category) $query_filters_where .= 'cp.`id_category` = '.(int)$id_category.' OR '; $query_filters_where = rtrim($query_filters_where, 'OR ').') '; return array('where' => $query_filters_where, 'join' => $query_filters_join); } private static function getQuantityFilterSubQuery($filter_value, $ignore_join) { if (count($filter_value) == 2 || empty($filter_value)) return array(); $query_filters_join = ''; if (version_compare(_PS_VERSION_,'1.5','>')) { $query_filters = ' AND sav.quantity '.(!$filter_value[0] ? '<=' : '>').' 0 '; $query_filters_join = 'LEFT JOIN `'._DB_PREFIX_.'stock_available` sav ON (sav.id_product = p.id_product AND sav.id_shop = '.(int)Context::getContext()->shop->id.') '; } else $query_filters = ' AND p.quantity '.(!$filter_value[0] ? '<=' : '>').' 0 '; return array('where' => $query_filters, 'join' => $query_filters_join); } private static function getManufacturerFilterSubQuery($filter_value, $ignore_join) { if (empty($filter_value)) $query_filters = ''; else { array_walk($filter_value, create_function('&$id_manufacturer', '$id_manufacturer = (int)$id_manufacturer;')); $query_filters = ' AND p.id_manufacturer IN ('.implode($filter_value, ',').')'; } if ($ignore_join) return array('where' => $query_filters, 'select' => ', m.name'); else return array('where' => $query_filters, 'select' => ', m.name', 'join' => 'LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.id_manufacturer = p.id_manufacturer) '); } private static function getConditionFilterSubQuery($filter_value, $ignore_join) { if (count($filter_value) == 3 || empty($filter_value)) return array(); if (version_compare(_PS_VERSION_,'1.5','>')) $query_filters = ' AND product_shop.condition IN ('; else $query_filters = ' AND p.condition IN ('; foreach ($filter_value as $cond) $query_filters .= '\''.$cond.'\','; $query_filters = rtrim($query_filters, ',').') '; return array('where' => $query_filters); } public function ajaxCallBackOffice($category_box = array(), $id_layered_filter = null) { global $cookie; if (!empty($id_layered_filter)) { $layered_filter = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow('SELECT * FROM '._DB_PREFIX_.'layered_filter WHERE id_layered_filter = '.(int)$id_layered_filter); if ($layered_filter && isset($layered_filter['filters']) && !empty($layered_filter['filters'])) $layered_values = self::unSerialize($layered_filter['filters']); if (isset($layered_values['categories']) && count($layered_values['categories'])) foreach ($layered_values['categories'] as $id_category) $category_box[] = (int)$id_category; } /* Clean categoryBox before use */ if (isset($category_box) && is_array($category_box)) foreach ($category_box as &$value) $value = (int)$value; else $category_box = array(); $attribute_groups = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT ag.id_attribute_group, ag.is_color_group, agl.name, COUNT(DISTINCT(a.id_attribute)) n FROM '._DB_PREFIX_.'attribute_group ag LEFT JOIN '._DB_PREFIX_.'attribute_group_lang agl ON (agl.id_attribute_group = ag.id_attribute_group) LEFT JOIN '._DB_PREFIX_.'attribute a ON (a.id_attribute_group = ag.id_attribute_group) '.(count($category_box) ? ' LEFT JOIN '._DB_PREFIX_.'product_attribute_combination pac ON (pac.id_attribute = a.id_attribute) LEFT JOIN '._DB_PREFIX_.'product_attribute pa ON (pa.id_product_attribute = pac.id_product_attribute) '.(version_compare(_PS_VERSION_,'1.5','>') ? Shop::addSqlAssociation('product_attribute', 'pa') : '').' LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = pa.id_product)' : '').' WHERE agl.id_lang = '.(int)$cookie->id_lang. (count($category_box) ? ' AND cp.id_category IN ('.implode(',', $category_box).')' : '').' GROUP BY ag.id_attribute_group'); $features = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' SELECT fl.id_feature, fl.name, COUNT(DISTINCT(fv.id_feature_value)) n FROM '._DB_PREFIX_.'feature_lang fl LEFT JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature = fl.id_feature) '.(count($category_box) ? ' LEFT JOIN '._DB_PREFIX_.'feature_product fp ON (fp.id_feature = fv.id_feature) LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = fp.id_product)' : '').' WHERE (fv.custom IS NULL OR fv.custom = 0) AND fl.id_lang = '.(int)$cookie->id_lang. (count($category_box) ? ' AND cp.id_category IN ('.implode(',', $category_box).')' : '').' GROUP BY fl.id_feature'); $n_elements = count($attribute_groups) + count($features) + 4; if ($n_elements > 20) $n_elements = 20; $html = ' <div id="layered_container_right" style="width: 360px; float: left; margin-left: 20px; height: '.(int)(30 + $n_elements * 38).'px; overflow-y: auto;"> <h3>'.$this->l('Available filters').' <span id="num_avail_filters">(0)</span></h3> <ul id="all_filters"></ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_subcategories" name="layered_selection_subcategories" /> <span class="position"></span>'.$this->l('Sub-categories filter').' <select class="filter_show_limit" name="layered_selection_subcategories_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_subcategories_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li> </ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_stock" name="layered_selection_stock" /> <span class="position"></span>'.$this->l('Product stock filter').' <select class="filter_show_limit" name="layered_selection_stock_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_stock_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li> </ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_condition" name="layered_selection_condition" /> <span class="position"></span>'.$this->l('Product condition filter').' <select class="filter_show_limit" name="layered_selection_condition_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_condition_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li> </ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_manufacturer" name="layered_selection_manufacturer" /> <span class="position"></span>'.$this->l('Product manufacturer filter').' <select class="filter_show_limit" name="layered_selection_manufacturer_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_manufacturer_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li> </ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_weight_slider" name="layered_selection_weight_slider" /> <span class="position"></span>'.$this->l('Product weight filter (slider)').' <select class="filter_show_limit" name="layered_selection_weight_slider_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_weight_slider_filter_type"> <option value="0">'.$this->l('Slider').'</option> <option value="1">'.$this->l('Inputs area').'</option> <option value="2">'.$this->l('List of values').'</option> </select> </li> </ul> <ul> <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_price_slider" name="layered_selection_price_slider" /> <span class="position"></span>'.$this->l('Product price filter (slider)').' <select class="filter_show_limit" name="layered_selection_price_slider_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_price_slider_filter_type"> <option value="0">'.$this->l('Slider').'</option> <option value="1">'.$this->l('Inputs area').'</option> <option value="2">'.$this->l('List of values').'</option> </select> </li> </ul>'; if (count($attribute_groups)) { $html .= '<ul>'; foreach ($attribute_groups as $attribute_group) $html .= ' <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_ag_'.(int)$attribute_group['id_attribute_group'].'" name="layered_selection_ag_'.(int)$attribute_group['id_attribute_group'].'" /> <span class="position"></span> '.($attribute_group['n'] > 1 ? sprintf($this->l('Attribute group: %1$s (%2$d attributes)'), $attribute_group['name'], $attribute_group['n']) : sprintf($this->l('Attribute group: %1$s (%2$d attribute)'), $attribute_group['name'], $attribute_group['n'])).')'. ($attribute_group['is_color_group'] ? ' <img src="../img/admin/color_swatch.png" alt="" title="'.$this->l('This group will allow user to select a color').'" />' : '').' <select class="filter_show_limit" name="layered_selection_ag_'.(int)$attribute_group['id_attribute_group'].'_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_ag_'.(int)$attribute_group['id_attribute_group'].'_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li>'; $html .= '</ul>'; } if (count($features)) { $html .= '<ul>'; foreach ($features as $feature) $html .= ' <li class="ui-state-default layered_right"> <span class="ui-icon ui-icon-arrowthick-2-n-s"></span> <input type="checkbox" id="layered_selection_feat_'.(int)$feature['id_feature'].'" name="layered_selection_feat_'.(int)$feature['id_feature'].'" /> <span class="position"></span> '.($feature['n'] > 1 ? sprintf($this->l('Feature: %1$s (%2$d values)'), $feature['name'], $feature['n']) : sprintf($this->l('Feature: %1$s (%2$d value)'), $feature['name'], $feature['n'])).') <select class="filter_show_limit" name="layered_selection_feat_'.(int)$feature['id_feature'].'_filter_show_limit"> <option value="0">'.$this->l('No limit').'</option> <option value="4">4</option> <option value="5">5</option> <option value="10">10</option> <option value="20">20</option> </select> <select class="filter_type" name="layered_selection_feat_'.(int)$feature['id_feature'].'_filter_type"> <option value="0">'.$this->l('Checkbox').'</option> <option value="1">'.$this->l('Radio button').'</option> <option value="2">'.$this->l('Drop-down list').'</option> </select> </li>'; $html .= '</ul>'; } $html .= ' </div>'; if (isset($layered_values)) { $html .= ' <script type="text/javascript"> $(document).ready(function() { $(\'#selected_filters li\').remove(); '; foreach ($layered_values as $key => $layered_value) if ($key != 'categories' && $key != 'shop_list') $html .= ' $(\'#'.$key.'\').click(); $(\'select[name='.$key.'_filter_type]\').val('.$layered_value['filter_type'].'); $(\'select[name='.$key.'_filter_show_limit]\').val('.$layered_value['filter_show_limit'].'); '; if (isset($layered_values['categories']) && count($layered_values['categories'])) { $html .= ' function expandCategories(categories, iteration, id_category, init) { if (categories[iteration]) { category = $(\'#categories-treeview\').find(\'input[name="categoryBox[]"][value=\'+categories[iteration]+\']\'); if (category.length) { if (category.parent().hasClass(\'expandable\')) { $(\'#\'+categories[iteration]+\' .hitarea\').click(); } if (parseInt(categories[iteration]) == parseInt(id_category)) { $(\'#layered-cat-counter\').html(parseInt($(\'#layered-cat-counter\').html()) + 1); if ($(\'#categories-treeview\').find(\'input[name="categoryBox[]"][value=\'+id_category+\']:checked\').length == 0) { $(\'#categories-treeview\').find(\'input[name="categoryBox[]"][value=\'+id_category+\']\').click(); clickOnCategoryBox($(\'#categories-treeview\').find(\'input[name="categoryBox[]"][value=\'+id_category+\']\')); } collapseAllCategories(); } } else { setTimeout(function() { expandCategories(categories, iteration, id_category, false); }, 20 ); return; } $(\'#categories-treeview\').parent().parent().show(); expandCategories(categories, iteration+1, id_category); if (typeof(lock_treeview_hidding) == \'undefined\' || !lock_treeview_hidding) $(\'#categories-treeview\').parent().parent().hide(); } } $(\'#layered-cat-counter\').html(0); $(\'.nb_sub_cat_selected\').hide(); $(\'#categories-treeview\').find(\'input[name="categoryBox[]"]:checked\').each(function(i, it) { $(it).click(); updateNbSubCategorySelected($(it), false); });'; foreach ($layered_values['categories'] as $id_category) { if ($id_category != 1) // @todo do we need to use the root of the current shop ? { $category = new Category($id_category); $parent_list = array_reverse($category->getParentsCategories()); } else $parent_list = array(array('id_category' => 1)); $html .= 'var categories = []; '; foreach ($parent_list as $parent) { $html .= ' categories.push('.(int)$parent['id_category'].');'; } $html .= ' expandCategories(categories, 0, '.(int)$id_category.', false);'; } $html .= ' updCatCounter(); $(\'#scope_1\').attr(\'checked\', \'\'); $(\'#scope_2\').attr(\'checked\', \'checked\'); '; } else $html .= ' $(\'#scope_2\').attr(\'checked\', \'\'); $(\'#scope_1\').attr(\'checked\', \'checked\'); '; $html .= ' $(\'#layered_tpl_name\').val(\''.addslashes($layered_filter['name']).'\'); $(\'#id_layered_filter\').val(\''.(int)$layered_filter['id_layered_filter'].'\'); '; $html .= ' }); </script>'; } if (version_compare(_PS_VERSION_,'1.5','>') && !empty($id_layered_filter)) { if (Shop::isFeatureActive() && Shop::getContext() != Shop::CONTEXT_ALL) { $shops = Shop::getShops(true, null, true); if (count($shops) > 1) { $helper = new HelperForm(); $helper->id = (int)$id_layered_filter; $helper->table = 'layered_filter'; $helper->identifier = 'id_layered_filter'; $helper->base_folder = Tools::getValue('base_folder').'/themes/default/template/helpers/form/'; $html .= ' <div id="shop_association_ajax">'.$helper->renderAssoShop().'</div> <script type="text/javascript"> $(document).ready(function() { $(\'#shop_association\').html($(\'#shop_association_ajax\').html()); $(\'#shop_association_ajax\').remove(); // Initialize checkbox $(\'.input_shop\').each(function(k, v) { check_shop_group_status($(v).val()); check_all_shop(); }); }); </script>'; } } } return $html; } public function ajaxCall() { global $smarty; $selected_filters = $this->getSelectedFilters(); $this->getProducts($selected_filters, $products, $nb_products, $p, $n, $pages_nb, $start, $stop, $range); // Add pagination variable $nArray = (int)Configuration::get('PS_PRODUCTS_PER_PAGE') != 10 ? array((int)Configuration::get('PS_PRODUCTS_PER_PAGE'), 10, 20, 50) : array(10, 20, 50); // Clean duplicate values $nArray = array_unique($nArray); asort($nArray); $smarty->assign( array( 'homeSize' => Image::getSize(ImageType::getFormatedName('home')), 'nb_products' => $nb_products, 'category' => (object)array('id' => Tools::getValue('id_category_layered', 1)), 'pages_nb' => (int)($pages_nb), 'p' => (int)$p, 'n' => (int)$n, 'range' => (int)$range, 'start' => (int)$start, 'stop' => (int)$stop, 'n_array' => ((int)Configuration::get('PS_PRODUCTS_PER_PAGE') != 10) ? array((int)Configuration::get('PS_PRODUCTS_PER_PAGE'), 10, 20, 50) : array(10, 20, 50), 'comparator_max_item' => (int)(Configuration::get('PS_COMPARATOR_MAX_ITEM')), 'products' => $products, 'products_per_page' => (int)Configuration::get('PS_PRODUCTS_PER_PAGE'), 'static_token' => Tools::getToken(false), 'page_name' => 'category', 'nArray' => $nArray, ) ); // Prevent bug with old template where category.tpl contain the title of the category and category-count.tpl do not exists if (file_exists(_PS_THEME_DIR_.'category-count.tpl')) $category_count = $smarty->fetch(_PS_THEME_DIR_.'category-count.tpl'); else $category_count = ''; if ($nb_products == 0) $product_list = $this->display(__FILE__, 'blocklayered-no-products.tpl'); else $product_list = $smarty->fetch(_PS_THEME_DIR_.'product-list.tpl'); /* We are sending an array in jSon to the .js controller, it will update both the filters and the products zones */ return Tools::jsonEncode(array( 'filtersBlock' => utf8_encode($this->generateFiltersBlock($selected_filters)), 'productList' => utf8_encode($product_list), 'pagination' => $smarty->fetch(_PS_THEME_DIR_.'pagination.tpl'), 'categoryCount' => $category_count)); } public function getProducts($selected_filters, &$products, &$nb_products, &$p, &$n, &$pages_nb, &$start, &$stop, &$range) { global $cookie; $products = $this->getProductByFilters($selected_filters); $products = Product::getProductsProperties((int)$cookie->id_lang, $products); $nb_products = $this->nbr_products; $range = 2; /* how many pages around page selected */ $n = (int)Tools::getValue('n', Configuration::get('PS_PRODUCTS_PER_PAGE')); $p = $this->page; if ($p < 0) $p = 0; if ($p > ($nb_products / $n)) $p = ceil($nb_products / $n); $pages_nb = ceil($nb_products / (int)($n)); $start = (int)($p - $range); if ($start < 1) $start = 1; $stop = (int)($p + $range); if ($stop > $pages_nb) $stop = (int)($pages_nb); } public function rebuildLayeredStructure() { @set_time_limit(0); /* Set memory limit to 128M only if current is lower */ $memory_limit = @ini_get('memory_limit'); if (substr($memory_limit, -1) != 'G' && ((substr($memory_limit, -1) == 'M' && substr($memory_limit, 0, -1) < 128) || is_numeric($memory_limit) && (intval($memory_limit) < 131072))) @ini_set('memory_limit', '128M'); /* Delete and re-create the layered categories table */ Db::getInstance()->execute('DROP TABLE IF EXISTS '._DB_PREFIX_.'layered_category'); Db::getInstance()->execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'layered_category` ( `id_layered_category` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `id_shop` INT(11) UNSIGNED NOT NULL, `id_category` INT(10) UNSIGNED NOT NULL, `id_value` INT(10) UNSIGNED NULL DEFAULT \'0\', `type` ENUM(\'category\',\'id_feature\',\'id_attribute_group\',\'quantity\',\'condition\',\'manufacturer\',\'weight\',\'price\') NOT NULL, `position` INT(10) UNSIGNED NOT NULL, `filter_type` int(10) UNSIGNED NOT NULL DEFAULT 0, `filter_show_limit` int(10) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`id_layered_category`), KEY `id_category` (`id_category`,`type`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=latin1 AUTO_INCREMENT=1;'); /* MyISAM + latin1 = Smaller/faster */ Db::getInstance()->execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'layered_filter` ( `id_layered_filter` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, `name` VARCHAR(64) NOT NULL, `filters` TEXT NULL, `n_categories` INT(10) UNSIGNED NOT NULL, `date_add` DATETIME NOT NULL ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); Db::getInstance()->execute(' CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'layered_filter_shop` ( `id_layered_filter` INT(10) UNSIGNED NOT NULL, `id_shop` INT(11) UNSIGNED NOT NULL, PRIMARY KEY (`id_layered_filter`, `id_shop`), KEY `id_shop` (`id_shop`) ) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); } public function rebuildLayeredCache($products_ids = array(), $categories_ids = array()) { @set_time_limit(0); $filter_data = array('categories' => array()); /* Set memory limit to 128M only if current is lower */ $memory_limit = @ini_get('memory_limit'); if (substr($memory_limit, -1) != 'G' && ((substr($memory_limit, -1) == 'M' && substr($memory_limit, 0, -1) < 128) || is_numeric($memory_limit) && (intval($memory_limit) < 131072))) @ini_set('memory_limit', '128M'); $db = Db::getInstance(_PS_USE_SQL_SLAVE_); $n_categories = array(); $done_categories = array(); $alias = 'p'; $join_product_attribute = $join_product = ''; if (version_compare(_PS_VERSION_,'1.5','>')) { $alias = 'product_shop'; $join_product = Shop::addSqlAssociation('product', 'p'); $join_product_attribute = Shop::addSqlAssociation('product_attribute', 'pa'); } $attribute_groups = self::query(' SELECT a.id_attribute, a.id_attribute_group FROM '._DB_PREFIX_.'attribute a LEFT JOIN '._DB_PREFIX_.'product_attribute_combination pac ON (pac.id_attribute = a.id_attribute) LEFT JOIN '._DB_PREFIX_.'product_attribute pa ON (pa.id_product_attribute = pac.id_product_attribute) LEFT JOIN '._DB_PREFIX_.'product p ON (p.id_product = pa.id_product) '.$join_product.$join_product_attribute.' LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) WHERE c.active = 1'. (count($categories_ids) ? ' AND cp.id_category IN ('.implode(',', $categories_ids).')' : '').' AND '.$alias.'.active = 1'. (count($products_ids) ? ' AND p.id_product IN ('.implode(',', $products_ids).')' : '')); $attribute_groups_by_id = array(); while ($row = $db->nextRow($attribute_groups)) $attribute_groups_by_id[(int)$row['id_attribute']] = (int)$row['id_attribute_group']; $features = self::query(' SELECT fv.id_feature_value, fv.id_feature FROM '._DB_PREFIX_.'feature_value fv LEFT JOIN '._DB_PREFIX_.'feature_product fp ON (fp.id_feature_value = fv.id_feature_value) LEFT JOIN '._DB_PREFIX_.'product p ON (p.id_product = fp.id_product) '.$join_product.' LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) WHERE (fv.custom IS NULL OR fv.custom = 0) AND c.active = 1'.(count($categories_ids) ? ' AND cp.id_category IN ('.implode(',', $categories_ids).')' : '').' AND '.$alias.'.active = 1'.(count($products_ids) ? ' AND p.id_product IN ('.implode(',', $products_ids).')' : '')); $features_by_id = array(); while ($row = $db->nextRow($features)) $features_by_id[(int)$row['id_feature_value']] = (int)$row['id_feature']; $result = self::query(' SELECT p.id_product, GROUP_CONCAT(DISTINCT fv.id_feature_value) features, GROUP_CONCAT(DISTINCT cp.id_category) categories, GROUP_CONCAT(DISTINCT pac.id_attribute) attributes FROM '._DB_PREFIX_.'product p LEFT JOIN '._DB_PREFIX_.'category_product cp ON (cp.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'category c ON (c.id_category = cp.id_category) LEFT JOIN '._DB_PREFIX_.'feature_product fp ON (fp.id_product = p.id_product) LEFT JOIN '._DB_PREFIX_.'feature_value fv ON (fv.id_feature_value = fp.id_feature_value) LEFT JOIN '._DB_PREFIX_.'product_attribute pa ON (pa.id_product = p.id_product) '.$join_product.$join_product_attribute.' LEFT JOIN '._DB_PREFIX_.'product_attribute_combination pac ON (pac.id_product_attribute = pa.id_product_attribute) WHERE c.active = 1'.(count($categories_ids) ? ' AND cp.id_category IN ('.implode(',', $categories_ids).')' : ''). ' AND '.$alias.'.active = 1'. (count($products_ids) ? ' AND p.id_product IN ('.implode(',', $products_ids).')' : ''). ' AND (fv.custom IS NULL OR fv.custom = 0) GROUP BY p.id_product'); if (version_compare(_PS_VERSION_,'1.5','>')) $shop_list = Shop::getShops(false, null, true); else $shop_list = array(0); $to_insert = false; while ($product = $db->nextRow($result)) { $a = $c = $f = array(); if (!empty($product['attributes'])) $a = array_flip(explode(',', $product['attributes'])); if (!empty($product['categories'])) $c = array_flip(explode(',', $product['categories'])); if (!empty($product['features'])) $f = array_flip(explode(',', $product['features'])); $filter_data['shop_list'] = $shop_list; foreach ($shop_list as $id_shop) { foreach ($c as $id_category => $category) { if (!in_array($id_category, $filter_data['categories'])) $filter_data['categories'][] = $id_category; if (!isset($n_categories[(int)$id_category])) $n_categories[(int)$id_category] = 1; if (!isset($done_categories[(int)$id_category]['cat'])) { $filter_data['layered_selection_subcategories'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['cat'] = true; $to_insert = true; } foreach ($a as $k_attribute => $attribute) if (!isset($done_categories[(int)$id_category]['a'.(int)$attribute_groups_by_id[(int)$k_attribute]])) { $filter_data['layered_selection_ag_'.(int)$attribute_groups_by_id[(int)$k_attribute]] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['a'.(int)$attribute_groups_by_id[(int)$k_attribute]] = true; $to_insert = true; } foreach ($f as $k_feature => $feature) if (!isset($done_categories[(int)$id_category]['f'.(int)$features_by_id[(int)$k_feature]])) { $filter_data['layered_selection_feat_'.(int)$features_by_id[(int)$k_feature]] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['f'.(int)$features_by_id[(int)$k_feature]] = true; $to_insert = true; } if (!isset($done_categories[(int)$id_category]['q'])) { $filter_data['layered_selection_stock'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['q'] = true; $to_insert = true; } if (!isset($done_categories[(int)$id_category]['m'])) { $filter_data['layered_selection_manufacturer'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['m'] = true; $to_insert = true; } if (!isset($done_categories[(int)$id_category]['c'])) { $filter_data['layered_selection_condition'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['c'] = true; $to_insert = true; } if (!isset($done_categories[(int)$id_category]['w'])) { $filter_data['layered_selection_weight_slider'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['w'] = true; $to_insert = true; } if (!isset($done_categories[(int)$id_category]['p'])) { $filter_data['layered_selection_price_slider'] = array('filter_type' => 0, 'filter_show_limit' => 0); $done_categories[(int)$id_category]['p'] = true; $to_insert = true; } } } } if ($to_insert) { Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_filter(name, filters, n_categories, date_add) VALUES (\''.sprintf($this->l('My template %s'), date('Y-m-d')).'\', \''.pSQL(serialize($filter_data)).'\', '.count($filter_data['categories']).', NOW())'); if (version_compare(_PS_VERSION_,'1.5','>')) { $last_id = Db::getInstance()->Insert_ID(); Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'layered_filter_shop WHERE `id_layered_filter` = '.$last_id); foreach ($shop_list as $id_shop) Db::getInstance()->execute('INSERT INTO '._DB_PREFIX_.'layered_filter_shop (`id_layered_filter`, `id_shop`) VALUES('.$last_id.', '.(int)$id_shop.')'); } $this->buildLayeredCategories(); } } public function buildLayeredCategories() { // Get all filter template $res = Db::getInstance()->executeS('SELECT * FROM '._DB_PREFIX_.'layered_filter ORDER BY date_add DESC'); $categories = array(); // Remove all from layered_category Db::getInstance()->execute('TRUNCATE '._DB_PREFIX_.'layered_category'); if (!count($res)) // No filters templates defined, nothing else to do return true; $sql_to_insert = 'INSERT INTO '._DB_PREFIX_.'layered_category (id_category, id_shop, id_value, type, position, filter_show_limit, filter_type) VALUES '; $values = false; foreach ($res as $filter_template) { $data = self::unSerialize($filter_template['filters']); foreach ($data['categories'] as $id_category) { $n = 0; if (!in_array($id_category, $categories)) // Last definition, erase preivious categories defined { $categories[] = $id_category; foreach ($data as $key => $value) if (substr($key, 0, 17) == 'layered_selection') { $values = true; $type = $value['filter_type']; $limit = $value['filter_show_limit']; $n++; foreach ($data['shop_list'] as $id_shop) { if ($key == 'layered_selection_stock') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'quantity\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if ($key == 'layered_selection_subcategories') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'category\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if ($key == 'layered_selection_condition') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'condition\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if ($key == 'layered_selection_weight_slider') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'weight\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if ($key == 'layered_selection_price_slider') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'price\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if ($key == 'layered_selection_manufacturer') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', NULL,\'manufacturer\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if (substr($key, 0, 21) == 'layered_selection_ag_') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', '.(int)str_replace('layered_selection_ag_', '', $key).', \'id_attribute_group\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; else if (substr($key, 0, 23) == 'layered_selection_feat_') $sql_to_insert .= '('.(int)$id_category.', '.(int)$id_shop.', '.(int)str_replace('layered_selection_feat_', '', $key).', \'id_feature\','.(int)$n.', '.(int)$limit.', '.(int)$type.'),'; } } } } } if ($values) Db::getInstance()->execute(rtrim($sql_to_insert, ',')); } /** * Define our own Tools::unSerialize() (since 1.5), to be available in PrestaShop 1.4 */ protected static function unSerialize($serialized) { if (method_exists('Tools', 'unserialize')) return Tools::unSerialize($serialized); if (is_string($serialized) && (strpos($serialized, 'O:') === false || !preg_match('/(^|;|{|})O:[0-9]+:"/', $serialized))) return @unserialize($serialized); return false; } }
©
2018. | Recode by D7net