-
-
Save anonymous/d09d8af50de07aee6acebbf83ef006ea to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
* 2007-2016 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-2016 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 = '2.2.0'; | |
$this->author = 'PrestaShop'; | |
$this->need_instance = 0; | |
$this->bootstrap = true; | |
parent::__construct(); | |
$this->displayName = $this->l('Layered navigation block'); | |
$this->description = $this->l('Displays a block with layered navigation filters.'); | |
$this->ps_versions_compliancy = array('min' => '1.6', 'max' => '1.6.99.99'); | |
if ((int)Tools::getValue('p')) | |
$this->page = (int)Tools::getValue('p'); | |
} | |
public function install() | |
{ | |
if (parent::install() && $this->registerHook('header') && $this->registerHook('leftColumn') | |
&& $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') && $this->registerHook('leftColumn')) | |
{ | |
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); | |
Configuration::updateValue('PS_ATTRIBUTE_ANCHOR_SEPARATOR', '-'); | |
Configuration::updateValue('PS_LAYERED_FILTER_PRICE_ROUNDING', 1); | |
$this->rebuildLayeredStructure(); | |
$this->buildLayeredCategories(); | |
$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 | |
{ | |
self::fullPricesIndexProcess(); | |
$this->indexUrl(); | |
$this->indexAttribute(); | |
} | |
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'); | |
Configuration::deleteByName('PS_LAYERED_FILTER_PRICE_ROUNDING'); | |
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_lang_value'); | |
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_indexable_feature_value_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(128), | |
`meta_title` VARCHAR(128), | |
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(128), | |
`meta_title` VARCHAR(128), | |
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(128) NOT NULL, | |
`meta_title` VARCHAR(128), | |
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(128), | |
`meta_title` VARCHAR(128), | |
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", | |
PRIMARY KEY (`id_attribute`, `id_product`, `id_shop`), | |
UNIQUE KEY `id_attribute_group` (`id_attribute_group`,`id_attribute`,`id_product`, `id_shop`) | |
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8;'); | |
} | |
//ATTRIBUTES GROUP | |
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( | |
'DELETE FROM '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value | |
WHERE `id_attribute_group` = '.(int)$params['id_attribute_group'] | |
); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group (`id_attribute_group`, `indexable`) | |
VALUES ('.(int)$params['id_attribute_group'].', '.(int)Tools::getValue('layered_indexable').')' | |
); | |
foreach (Language::getLanguages(false) as $language) | |
{ | |
$seo_url = Tools::getValue('url_name_'.(int)$language['id_lang']); | |
if(empty($seo_url)) | |
$seo_url = Tools::getValue('name_'.(int)$language['id_lang']); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_group_lang_value | |
(`id_attribute_group`, `id_lang`, `url_name`, `meta_title`) | |
VALUES ( | |
'.(int)$params['id_attribute_group'].', '.(int)$language['id_lang'].', | |
\''.pSQL(Tools::link_rewrite($seo_url)).'\', | |
\''.pSQL(Tools::getValue('meta_title_'.(int)$language['id_lang']), true).'\' | |
)' | |
); | |
} | |
} | |
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 hookPostProcessAttributeGroup($params) | |
{ | |
$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))) | |
$params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), | |
Tools::getValue('url_name_'.$id_lang))); | |
} | |
} | |
public function hookAttributeGroupForm($params) | |
{ | |
$values = array(); | |
$is_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'] | |
); | |
if ($is_indexable === false) | |
$is_indexable = true; | |
if ($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'] | |
)) | |
foreach ($result as $data) | |
$values[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); | |
$this->context->smarty->assign(array( | |
'languages' => Language::getLanguages(false), | |
'default_form_language' => (int)$this->context->controller->default_form_language, | |
'values' => $values, | |
'is_indexable' =>(bool)$is_indexable | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'attribute_group_form_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'attribute_group_form.tpl'); | |
} | |
//ATTRIBUTES | |
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'] | |
); | |
foreach (Language::getLanguages(false) as $language) | |
{ | |
$seo_url = Tools::getValue('url_name_'.(int)$language['id_lang']); | |
if(empty($seo_url)) | |
$seo_url = Tools::getValue('name_'.(int)$language['id_lang']); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_attribute_lang_value | |
(`id_attribute`, `id_lang`, `url_name`, `meta_title`) | |
VALUES ( | |
'.(int)$params['id_attribute'].', '.(int)$language['id_lang'].', | |
\''.pSQL(Tools::link_rewrite($seo_url)).'\', | |
\''.pSQL(Tools::getValue('meta_title_'.(int)$language['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) | |
{ | |
$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))) | |
$params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), | |
Tools::getValue('url_name_'.$id_lang))); | |
} | |
} | |
public function hookAttributeForm($params) | |
{ | |
$values = array(); | |
if ($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'] | |
)) | |
foreach ($result as $data) | |
$values[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); | |
$this->context->smarty->assign(array( | |
'languages' => Language::getLanguages(false), | |
'default_form_language' => (int)$this->context->controller->default_form_language, | |
'values' => $values | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'attribute_form_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'attribute_form.tpl'); | |
} | |
//FEATURES | |
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( | |
'DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_lang_value | |
WHERE `id_feature` = '.(int)$params['id_feature'] | |
); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_feature | |
(`id_feature`, `indexable`) | |
VALUES ('.(int)$params['id_feature'].', '.(int)Tools::getValue('layered_indexable').')' | |
); | |
foreach (Language::getLanguages(false) as $language) | |
{ | |
$seo_url = Tools::getValue('url_name_'.(int)$language['id_lang']); | |
if(empty($seo_url)) | |
$seo_url = Tools::getValue('name_'.(int)$language['id_lang']); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_lang_value | |
(`id_feature`, `id_lang`, `url_name`, `meta_title`) | |
VALUES ( | |
'.(int)$params['id_feature'].', '.(int)$language['id_lang'].', | |
\''.pSQL(Tools::link_rewrite($seo_url)).'\', | |
\''.pSQL(Tools::getValue('meta_title_'.(int)$language['id_lang']), true).'\' | |
)' | |
); | |
} | |
} | |
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 hookPostProcessFeature($params) | |
{ | |
$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))) | |
$params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), | |
Tools::getValue('url_name_'.$id_lang))); | |
} | |
} | |
public function hookFeatureForm($params) | |
{ | |
$values = array(); | |
$is_indexable = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( | |
'SELECT `indexable` | |
FROM '._DB_PREFIX_.'layered_indexable_feature | |
WHERE `id_feature` = '.(int)$params['id_feature'] | |
); | |
if ($is_indexable === false) | |
$is_indexable = true; | |
if ($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'] | |
)) | |
foreach ($result as $data) | |
$values[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); | |
$this->context->smarty->assign(array( | |
'languages' => Language::getLanguages(false), | |
'default_form_language' => (int)$this->context->controller->default_form_language, | |
'values' => $values, | |
'is_indexable' =>(bool)$is_indexable | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'feature_form_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'feature_form.tpl'); | |
} | |
//FEATURES VALUE | |
public function hookAfterSaveFeatureValue($params) | |
{ | |
if (!$params['id_feature_value']) | |
return; | |
//Removing all indexed language data for this attribute value id | |
Db::getInstance()->execute( | |
'DELETE FROM '._DB_PREFIX_.'layered_indexable_feature_value_lang_value | |
WHERE `id_feature_value` = '.(int)$params['id_feature_value'] | |
); | |
foreach (Language::getLanguages(false) as $language) | |
{ | |
$seo_url = Tools::getValue('url_name_'.(int)$language['id_lang']); | |
if(empty($seo_url)) | |
$seo_url = Tools::getValue('name_'.(int)$language['id_lang']); | |
Db::getInstance()->execute( | |
'INSERT INTO '._DB_PREFIX_.'layered_indexable_feature_value_lang_value | |
(`id_feature_value`, `id_lang`, `url_name`, `meta_title`) | |
VALUES ( | |
'.(int)$params['id_feature_value'].', '.(int)$language['id_lang'].', | |
\''.pSQL(Tools::link_rewrite($seo_url)).'\', | |
\''.pSQL(Tools::getValue('meta_title_'.(int)$language['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) | |
{ | |
$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))) | |
$params['errors'][] = Tools::displayError(sprintf($this->l('"%s" is not a valid url'), | |
Tools::getValue('url_name_'.$id_lang))); | |
} | |
} | |
public function hookFeatureValueForm($params) | |
{ | |
$values = array(); | |
if ($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'] | |
)) | |
foreach ($result as $data) | |
$values[$data['id_lang']] = array('url_name' => $data['url_name'], 'meta_title' => $data['meta_title']); | |
$this->context->smarty->assign(array( | |
'languages' => Language::getLanguages(false), | |
'default_form_language' => (int)$this->context->controller->default_form_language, | |
'values' => $values | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'feature_value_form_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'feature_value_form.tpl'); | |
} | |
public function hookProductListAssign($params) | |
{ | |
if ((isset($this->context->controller->display_column_left) && !$this->context->controller->display_column_left) | |
&& (isset($this->context->controller->display_column_right) && !$this->context->controller->display_column_right)) | |
return false; | |
global $smarty; | |
if (!Configuration::getGlobalValue('PS_LAYERED_INDEXED')) | |
return; | |
$categories_count = Db::getInstance()->getValue(' | |
SELECT COUNT(*) | |
FROM '._DB_PREFIX_.'layered_category | |
WHERE id_category = '.(int)Tools::getValue('id_category', Tools::getValue('id_category_layered', Configuration::get('PS_HOME_CATEGORY'))).' | |
AND id_shop = '.(int) Context::getContext()->shop->id | |
); | |
if ($categories_count == 0) | |
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 hookLeftColumn($params) | |
{ | |
return $this->generateFiltersBlock($this->getSelectedFilters()); | |
} | |
public function hookRightColumn($params) | |
{ | |
return $this->hookLeftColumn($params); | |
} | |
public function hookHeader($params) | |
{ | |
if ((isset($this->context->controller->display_column_left) && !$this->context->controller->display_column_left) | |
&& (isset($this->context->controller->display_column_right) && !$this->context->controller->display_column_right)) | |
return false; | |
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', Configuration::get('PS_HOME_CATEGORY'))) == Configuration::get('PS_HOME_CATEGORY')) | |
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]); | |
$category_metas = Meta::getMetaTags($id_lang, 'category'); | |
$title = ''; | |
$keywords = ''; | |
if (is_array($filter_block['title_values'])) | |
foreach ($filter_block['title_values'] as $key => $val) | |
{ | |
$title .= ' > '.$key.' '.implode('/', $val); | |
$keywords .= $key.' '.implode('/', $val).', '; | |
} | |
$title = $category_title.$title; | |
if (!empty($title)) | |
$smarty->assign('meta_title', $title.' - '.Configuration::get('PS_SHOP_NAME')); | |
else | |
$smarty->assign('meta_title', $category_metas['meta_title']); | |
$smarty->assign('meta_description', $category_metas['meta_description']); | |
$keywords = substr(strtolower($keywords), 0, 1000); | |
if (!empty($keywords)) | |
$smarty->assign('meta_keywords', rtrim($category_title.', '.$keywords.', '.$category_metas['meta_keywords'], ', ')); | |
$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(_PS_CSS_DIR_.'jquery-ui-1.8.10.custom.css'); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$this->context->controller->addCSS(($this->_path).'blocklayered.css', 'all'); | |
else | |
$this->context->controller->addCSS(($this->_path).'blocklayered-15.css', 'all'); | |
$this->context->controller->addJQueryPlugin('scrollTo'); | |
$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) | |
{ | |
if ((isset($this->context->controller->display_column_left) && !$this->context->controller->display_column_left) | |
&& (isset($this->context->controller->display_column_right) && !$this->context->controller->display_column_right)) | |
return false; | |
// No filters => module disable | |
if ($filter_block = $this->getFilterBlock($this->getSelectedFilters())) | |
if ($filter_block['nbr_filterBlocks'] == 0) | |
return false; | |
if (Dispatcher::getInstance()->getController() == 'category') | |
$this->context->controller->addJS($this->_path.'blocklayered-footer.js'); | |
} | |
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 = Tools::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(); | |
} | |
/* | |
* 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, product_attribute_shop.`id_shop` | |
FROM '._DB_PREFIX_.'product_attribute pa'. | |
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 , 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($this->getAnchor(), '_', Tools::link_rewrite($param['name'])).$this->getAnchor().str_replace($this->getAnchor(), '_', 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()->insert('layered_friendly_url', array('url_key' => $url_key, 'data' => serialize($selected_filters), 'id_lang' => (int)$id_lang)); | |
$id_layered_friendly_url = Db::getInstance()->Insert_ID(); | |
} | |
} | |
} | |
if ($ajax) | |
return '{"result": 1}'; | |
else | |
return 1; | |
} | |
/* | |
* $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) | |
$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 AND ps.`visibility` IN ("both", "catalog"))'); | |
else | |
$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 AND ps.`visibility` IN ("both", "catalog")) | |
LEFT JOIN `'._DB_PREFIX_.'layered_price_index` psi ON (psi.id_product = p.id_product) | |
WHERE 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); | |
if (function_exists('memory_get_peak_usage')) | |
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); | |
else | |
do | |
{ | |
$cursor = (int)self::indexPricesUnbreakable((int)$cursor, $full, $smart); | |
$time_elapsed = microtime(true) - $start_time; | |
} | |
while ($cursor < $nb_products && $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 | |
{ | |
Configuration::updateGlobalValue('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) | |
$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 AND ps.`visibility` IN ("both", "catalog")) | |
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 | |
INNER JOIN `'._DB_PREFIX_.'product_shop` ps | |
ON (ps.`id_product` = p.`id_product` AND ps.`active` = 1 AND ps.`visibility` IN ("both", "catalog")) | |
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; | |
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 = Shop::getShops(false, null, true); | |
foreach ($shop_list as $id_shop) | |
{ | |
static $currency_list = null; | |
if (is_null($currency_list)) | |
$currency_list = Currency::getCurrencies(false, 1, new Shop($id_shop)); | |
$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')) | |
$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)$id_shop.') | |
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 translateWord($string, $id_lang ) | |
{ | |
static $_MODULES = array(); | |
global $_MODULE; | |
$file = _PS_MODULE_DIR_.$this->name.'/translations/'.Language::getIsoById($id_lang).'.php'; | |
if (!array_key_exists($id_lang, $_MODULES)) | |
{ | |
if (file_exists($file1 = _PS_MODULE_DIR_.$this->name.'/translations/'.Language::getIsoById($id_lang).'.php')) | |
{ | |
include($file1); | |
$_MODULES[$id_lang] = $_MODULE; | |
} | |
elseif (file_exists($file2 = _PS_MODULE_DIR_.$this->name.'/'.Language::getIsoById($id_lang).'.php')) | |
{ | |
include($file2); | |
$_MODULES[$id_lang] = $_MODULE; | |
} | |
else | |
return $string; | |
} | |
$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 getContent() | |
{ | |
global $cookie; | |
$message = ''; | |
if (Tools::isSubmit('SubmitFilter')) | |
{ | |
if (!Tools::getValue('layered_tpl_name')) | |
$message = $this->displayError($this->l('Filter template name required (cannot be empty)')); | |
elseif (!Tools::getValue('categoryBox')) | |
$message = $this->displayError($this->l('You must select at least one category.')); | |
else | |
{ | |
if (Tools::getValue('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']; | |
} | |
$id_layered_filter = (int)Tools::getValue('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); | |
Db::getInstance()->execute(' | |
DELETE FROM '._DB_PREFIX_.'layered_filter_shop | |
WHERE `id_layered_filter` = '.(int)$id_layered_filter | |
); | |
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 | |
); | |
} | |
} | |
$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'); | |
$id_layered_filter = (int)Db::getInstance()->Insert_ID(); | |
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'].')' | |
); | |
$this->buildLayeredCategories(); | |
$message = $this->displayConfirmation($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.'))); | |
} | |
} | |
} | |
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')); | |
Configuration::updateValue('PS_LAYERED_FILTER_PRICE_ROUNDING', (int)Tools::getValue('ps_layered_filter_price_rounding')); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$message = '<div class="alert alert-success">'.$this->l('Settings saved successfully').'</div>'; | |
else | |
$message = '<div class="conf">'.$this->l('Settings saved successfully').'</div>'; | |
} | |
else if (Tools::getValue('deleteFilterTemplate')) | |
{ | |
$layered_values = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue(' | |
SELECT filters | |
FROM '._DB_PREFIX_.'layered_filter | |
WHERE id_layered_filter = '.(int)Tools::getValue('id_layered_filter') | |
); | |
if ($layered_values) | |
{ | |
Db::getInstance()->execute(' | |
DELETE FROM '._DB_PREFIX_.'layered_filter | |
WHERE id_layered_filter = '.(int)Tools::getValue('id_layered_filter').' LIMIT 1' | |
); | |
$this->buildLayeredCategories(); | |
$message = $this->displayConfirmation($this->l('Filter template deleted, categories updated (reverted to default Filter template).')); | |
} | |
else | |
$message = $this->displayError($this->l('Filter template not found')); | |
} | |
$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) | |
WHERE agl.id_lang = '.(int)$cookie->id_lang.' | |
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) | |
WHERE (fv.custom IS NULL OR fv.custom = 0) AND fl.id_lang = '.(int)$cookie->id_lang.' | |
GROUP BY fl.id_feature' | |
); | |
if (Shop::isFeatureActive() && count(Shop::getShops(true, null, true)) > 1) | |
{ | |
$helper = new HelperForm(); | |
$helper->id = Tools::getValue('id_layered_filter', null); | |
$helper->table = 'layered_filter'; | |
$helper->identifier = 'id_layered_filter'; | |
$this->context->smarty->assign('asso_shops', $helper->renderAssoShop()); | |
} | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
{ | |
$tree_categories_helper = new HelperTreeCategories('categories-treeview'); | |
$tree_categories_helper->setRootCategory((Shop::getContext() == Shop::CONTEXT_SHOP ? Category::getRootCategory()->id_category : 0)) | |
->setUseCheckBox(true); | |
} | |
else | |
{ | |
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')); | |
$tree_categories_helper = new Helper(); | |
} | |
$module_url = Tools::getProtocol(Tools::usingSecureMode()).$_SERVER['HTTP_HOST'].$this->getPathUri(); | |
if (method_exists($this->context->controller, 'addJquery')) | |
{ | |
$this->context->controller->addJS($this->_path.'js/blocklayered_admin.js'); | |
if (version_compare(_PS_VERSION_, '1.6.0.3', '>=') === true) | |
$this->context->controller->addjqueryPlugin('sortable'); | |
elseif (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$this->context->controller->addJS(_PS_JS_DIR_.'jquery/plugins/jquery.sortable.js'); | |
else | |
$this->context->controller->addJS($this->_path.'js/jquery.sortable.js'); | |
} | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$this->context->controller->addCSS($this->_path.'css/blocklayered_admin_1.6.css'); | |
else | |
$this->context->controller->addCSS($this->_path.'css/blocklayered_admin.css'); | |
if (Tools::getValue('add_new_filters_template')) | |
{ | |
$this->context->smarty->assign(array( | |
'current_url' => $this->context->link->getAdminLink('AdminModules').'&configure=blocklayered&tab_module=front_office_features&module_name=blocklayered', | |
'uri' => $this->getPathUri(), | |
'id_layered_filter' => 0, | |
'template_name' => sprintf($this->l('My template - %s'), date('Y-m-d')), | |
'attribute_groups' => $attribute_groups, | |
'features' => $features, | |
'total_filters' => 6+count($attribute_groups)+count($features) | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$this->context->smarty->assign('categories_tree', $tree_categories_helper->render()); | |
else | |
$this->context->smarty->assign('categories_tree', $tree_categories_helper->renderCategoryTree( | |
$root_category, array(), 'categoryBox')); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'views/templates/admin/add_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'views/templates/admin/add.tpl'); | |
} | |
else if (Tools::getValue('edit_filters_template')) | |
{ | |
$template = Db::getInstance()->getRow(' | |
SELECT * | |
FROM `'._DB_PREFIX_.'layered_filter` | |
WHERE id_layered_filter = '.(int)Tools::getValue('id_layered_filter') | |
); | |
$filters = Tools::unSerialize($template['filters']); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
{ | |
$tree_categories_helper->setSelectedCategories($filters['categories']); | |
$this->context->smarty->assign('categories_tree', $tree_categories_helper->render()); | |
} | |
else | |
$this->context->smarty->assign('categories_tree',$tree_categories_helper->renderCategoryTree( | |
$root_category, $filters['categories'], 'categoryBox')); | |
$select_shops = $filters['shop_list']; | |
unset($filters['categories']); | |
unset($filters['shop_list']); | |
$this->context->smarty->assign(array( | |
'current_url' => $this->context->link->getAdminLink('AdminModules').'&configure=blocklayered&tab_module=front_office_features&module_name=blocklayered', | |
'uri' => $this->getPathUri(), | |
'id_layered_filter' => (int)Tools::getValue('id_layered_filter'), | |
'template_name' => $template['name'], | |
'attribute_groups' => $attribute_groups, | |
'features' => $features, | |
'filters' => Tools::jsonEncode($filters), | |
'total_filters' => 6+count($attribute_groups)+count($features) | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'views/templates/admin/add_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'views/templates/admin/add.tpl'); | |
} | |
else | |
{ | |
$this->context->smarty->assign(array( | |
'message' => $message, | |
'uri' => $this->getPathUri(), | |
'PS_LAYERED_INDEXED' => Configuration::getGlobalValue('PS_LAYERED_INDEXED'), | |
'current_url' => Tools::safeOutput(preg_replace('/&deleteFilterTemplate=[0-9]*&id_layered_filter=[0-9]*/', '', $_SERVER['REQUEST_URI'])), | |
'id_lang' => Context::getContext()->cookie->id_lang, | |
'token' => substr(Tools::encrypt('blocklayered/index'), 0, 10), | |
'base_folder' => urlencode(_PS_ADMIN_DIR_), | |
'price_indexer_url' => $module_url.'blocklayered-price-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10), | |
'full_price_indexer_url' => $module_url.'blocklayered-price-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&full=1', | |
'attribute_indexer_url' => $module_url.'blocklayered-attribute-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10), | |
'url_indexer_url' => $module_url.'blocklayered-url-indexer.php'.'?token='.substr(Tools::encrypt('blocklayered/index'), 0, 10).'&truncate=1', | |
'filters_templates' => Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT * FROM '._DB_PREFIX_.'layered_filter ORDER BY date_add DESC'), | |
'hide_values' => Configuration::get('PS_LAYERED_HIDE_0_VALUES'), | |
'show_quantities' => Configuration::get('PS_LAYERED_SHOW_QTIES'), | |
'full_tree' => Configuration::get('PS_LAYERED_FULL_TREE'), | |
'category_depth' => Configuration::get('PS_LAYERED_FILTER_CATEGORY_DEPTH'), | |
'price_use_tax' => (bool)Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX'), | |
'index_cdt' => Configuration::get('PS_LAYERED_FILTER_INDEX_CDT'), | |
'index_qty' => Configuration::get('PS_LAYERED_FILTER_INDEX_QTY'), | |
'index_mnf' => Configuration::get('PS_LAYERED_FILTER_INDEX_MNF'), | |
'index_cat' => Configuration::get('PS_LAYERED_FILTER_INDEX_CAT'), | |
'limit_warning' => $this->displayLimitPostWarning(21+count($attribute_groups)*3+count($features)*3), | |
'price_use_rounding' => (bool)Configuration::get('PS_LAYERED_FILTER_PRICE_ROUNDING') | |
)); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
return $this->display(__FILE__, 'views/templates/admin/view_1.6.tpl'); | |
else | |
return $this->display(__FILE__, 'views/templates/admin/view.tpl'); | |
} | |
} | |
public function displayLimitPostWarning($count) | |
{ | |
$return = array(); | |
if ((ini_get('suhosin.post.max_vars') && ini_get('suhosin.post.max_vars') < $count) || (ini_get('suhosin.request.max_vars') && ini_get('suhosin.request.max_vars') < $count)) | |
{ | |
$return['error_type'] = 'suhosin'; | |
$return['post.max_vars'] = ini_get('suhosin.post.max_vars'); | |
$return['request.max_vars'] = ini_get('suhosin.request.max_vars'); | |
$return['needed_limit'] = $count + 100; | |
} | |
elseif (ini_get('max_input_vars') && ini_get('max_input_vars') < $count) | |
{ | |
$return['error_type'] = 'conf'; | |
$return['max_input_vars'] = ini_get('max_input_vars'); | |
$return['needed_limit'] = $count + 100; | |
} | |
return $return; | |
} | |
private function getSelectedFilters() | |
{ | |
$home_category = Configuration::get('PS_HOME_CATEGORY'); | |
$id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', $home_category)); | |
if ($id_parent == $home_category) | |
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) | |
{ | |
/* Pagination uses - as separator, can be different from $this->getAnchor()*/ | |
if (strpos($url_attribute, 'page-') === 0) | |
$url_attribute = str_replace('-', $this->getAnchor(), $url_attribute); | |
$url_parameters = explode($this->getAnchor(), $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($this->filterVar($url_parameters[0]), $this->filterVar($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.$this->getAnchor().$url_parameter).'\''); | |
if ($data) | |
foreach (Tools::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] = $this->filterVar($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('_', $this->filterVar($value)); | |
$value = $this->filterVar($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; | |
$home_category = Configuration::get('PS_HOME_CATEGORY'); | |
/* 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', $home_category)); | |
if ($id_parent == $home_category) | |
return false; | |
$alias_where = 'p'; | |
if (version_compare(_PS_VERSION_,'1.5','>')) | |
$alias_where = 'product_shop'; | |
$query_filters_where = ' AND '.$alias_where.'.`active` = 1 AND '.$alias_where.'.`visibility` IN ("both", "catalog")'; | |
$query_filters_from = ''; | |
$parent = new Category((int)$id_parent); | |
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`)'. | |
Shop::addSqlAssociation('product_attribute', 'pa').' | |
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; | |
$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 '.StockAvailable::addSqlShopRestriction(null, null, 'sa').') '; | |
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 .= '\''.pSQL($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); | |
break; | |
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; | |
} | |
} | |
$context = Context::getContext(); | |
$id_currency = (int)$context->currency->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['max'].' | |
AND psi.price_max >= '.(int)$price_filter['min'].' | |
AND psi.`id_product` = p.`id_product` | |
AND psi.`id_shop` = '.(int)$context->shop->id.' | |
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_shop` = '.(int)$context->shop->id.' | |
AND psi.`id_currency` = '.$id_currency; | |
} | |
$query_filters_from .= Shop::addSqlAssociation('product', 'p'); | |
Db::getInstance()->execute('DROP TEMPORARY TABLE IF EXISTS '._DB_PREFIX_.'cat_filter_restriction', false); | |
if (empty($selected_filters['category'])) | |
{ | |
/* Create the table which contains all the id_product in a cat or a tree */ | |
Db::getInstance()->execute('CREATE TEMPORARY TABLE '._DB_PREFIX_.'cat_filter_restriction ENGINE=MEMORY | |
SELECT cp.id_product, MIN(cp.position) position FROM '._DB_PREFIX_.'category c | |
STRAIGHT_JOIN '._DB_PREFIX_.'category_product cp 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) | |
STRAIGHT_JOIN `'._DB_PREFIX_.'product` p ON (p.id_product=cp.id_product) | |
'.$price_filter_query_in.' | |
'.$query_filters_from.' | |
WHERE 1 '.$query_filters_where.' | |
GROUP BY cp.id_product ORDER BY position, id_product', false); | |
} else { | |
$categories = array_map('intval', $selected_filters['category']); | |
Db::getInstance()->execute('CREATE TEMPORARY TABLE '._DB_PREFIX_.'cat_filter_restriction ENGINE=MEMORY | |
SELECT cp.id_product, MIN(cp.position) position FROM '._DB_PREFIX_.'category_product cp | |
STRAIGHT_JOIN `'._DB_PREFIX_.'product` p ON (p.id_product=cp.id_product) | |
'.$price_filter_query_in.' | |
'.$query_filters_from.' | |
WHERE cp.`id_category` IN ('.implode(',', $categories).') '.$query_filters_where.' | |
GROUP BY cp.id_product ORDER BY position, id_product', false); | |
} | |
Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'cat_filter_restriction ADD PRIMARY KEY (id_product), ADD KEY (position, id_product) USING BTREE', false); | |
if (isset($price_filter) && $price_filter) { | |
static $ps_layered_filter_price_usetax = null; | |
static $ps_layered_filter_price_rounding = null; | |
if ($ps_layered_filter_price_usetax === null) { | |
$ps_layered_filter_price_usetax = Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX'); | |
} | |
if ($ps_layered_filter_price_rounding === null) { | |
$ps_layered_filter_price_rounding = Configuration::get('PS_LAYERED_FILTER_PRICE_ROUNDING'); | |
} | |
if (empty($selected_filters['category'])) { | |
$all_products_out = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' | |
SELECT p.`id_product` id_product | |
FROM `'._DB_PREFIX_.'product` p JOIN '._DB_PREFIX_.'category_product cp USING (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) | |
'.$price_filter_query_out.' | |
'.$query_filters_from.' | |
WHERE 1 '.$query_filters_where.' GROUP BY cp.id_product'); | |
} else { | |
$all_products_out = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS(' | |
SELECT p.`id_product` id_product | |
FROM `'._DB_PREFIX_.'product` p JOIN '._DB_PREFIX_.'category_product cp USING (id_product) | |
'.$price_filter_query_out.' | |
'.$query_filters_from.' | |
WHERE cp.`id_category` IN ('.implode(',', $categories).') '.$query_filters_where.' GROUP BY cp.id_product'); | |
} | |
/* for this case, price could be out of range, so we need to compute the real price */ | |
foreach($all_products_out as $product) { | |
$price = Product::getPriceStatic($product['id_product'], $ps_layered_filter_price_usetax); | |
if ($ps_layered_filter_price_rounding) { | |
$price = (int)$price; | |
} | |
if ($price < $price_filter['min'] || $price > $price_filter['max']) { | |
// out of range price, exclude the product | |
$product_id_delete_list[] = (int)$product['id_product']; | |
} | |
} | |
if (!empty($product_id_delete_list)) { | |
Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'cat_filter_restriction WHERE id_product IN ('.implode(',', $product_id_delete_list).')', false); | |
} | |
} | |
$this->nbr_products = Db::getInstance()->getValue('SELECT COUNT(*) FROM '._DB_PREFIX_.'cat_filter_restriction', false); | |
if ($this->nbr_products == 0) | |
$this->products = array(); | |
else | |
{ | |
$product_per_page = isset($this->context->cookie->nb_item_per_page) ? (int)$this->context->cookie->nb_item_per_page : Configuration::get('PS_PRODUCTS_PER_PAGE'); | |
$default_products_per_page = max(1, (int)Configuration::get('PS_PRODUCTS_PER_PAGE')); | |
$n = $default_products_per_page; | |
if (isset($this->context->cookie->nb_item_per_page)) { | |
$n = (int)$this->context->cookie->nb_item_per_page; | |
} | |
if ((int)Tools::getValue('n')) { | |
$n = (int)Tools::getValue('n'); | |
} | |
$nb_day_new_product = (Validate::isUnsignedInt(Configuration::get('PS_NB_DAYS_NEW_PRODUCT')) ? Configuration::get('PS_NB_DAYS_NEW_PRODUCT') : 20); | |
if (version_compare(_PS_VERSION_, '1.6.1', '>=') === true) | |
{ | |
$this->products = Db::getInstance()->executeS(' | |
SELECT | |
p.*, | |
'.($alias_where == 'p' ? '' : 'product_shop.*,' ).' | |
'.$alias_where.'.id_category_default, | |
pl.*, | |
image_shop.`id_image` id_image, | |
il.legend, | |
m.name manufacturer_name, | |
'.(Combination::isFeatureActive() ? 'product_attribute_shop.id_product_attribute id_product_attribute,' : '').' | |
DATEDIFF('.$alias_where.'.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00", INTERVAL '.(int)$nb_day_new_product.' DAY)) > 0 AS new, | |
stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity'.(Combination::isFeatureActive() ? ', product_attribute_shop.minimal_quantity AS product_attribute_minimal_quantity' : '').' | |
FROM '._DB_PREFIX_.'cat_filter_restriction cp | |
LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` | |
'.Shop::addSqlAssociation('product', 'p'). | |
(Combination::isFeatureActive() ? | |
' LEFT JOIN `'._DB_PREFIX_.'product_attribute_shop` product_attribute_shop | |
ON (p.`id_product` = product_attribute_shop.`id_product` AND product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id.')':'').' | |
LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product'.Shop::addSqlRestrictionOnLang('pl').' AND pl.id_lang = '.(int)$cookie->id_lang.') | |
LEFT JOIN `'._DB_PREFIX_.'image_shop` image_shop | |
ON (image_shop.`id_product` = p.`id_product` AND image_shop.cover=1 AND image_shop.id_shop='.(int)$context->shop->id.') | |
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`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) | |
'.Product::sqlStock('p', 0).' | |
WHERE '.$alias_where.'.`active` = 1 AND '.$alias_where.'.`visibility` IN ("both", "catalog") | |
ORDER BY '.Tools::getProductsOrder('by', Tools::getValue('orderby'), true).' '.Tools::getProductsOrder('way', Tools::getValue('orderway')).' , cp.id_product'. | |
' LIMIT '.(((int)$this->page - 1) * $n.','.$n), true, false); | |
} | |
else | |
{ | |
$this->products = Db::getInstance()->executeS(' | |
SELECT | |
p.*, | |
'.($alias_where == 'p' ? '' : 'product_shop.*,' ).' | |
'.$alias_where.'.id_category_default, | |
pl.*, | |
MAX(image_shop.`id_image`) id_image, | |
il.legend, | |
m.name manufacturer_name, | |
'.(Combination::isFeatureActive() ? 'MAX(product_attribute_shop.id_product_attribute) id_product_attribute,' : '').' | |
DATEDIFF('.$alias_where.'.`date_add`, DATE_SUB("'.date('Y-m-d').' 00:00:00", INTERVAL '.(int)$nb_day_new_product.' DAY)) > 0 AS new, | |
stock.out_of_stock, IFNULL(stock.quantity, 0) as quantity'.(Combination::isFeatureActive() ? ', MAX(product_attribute_shop.minimal_quantity) AS product_attribute_minimal_quantity' : '').' | |
FROM '._DB_PREFIX_.'cat_filter_restriction cp | |
LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = cp.`id_product` | |
'.Shop::addSqlAssociation('product', 'p'). | |
(Combination::isFeatureActive() ? | |
'LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (p.`id_product` = pa.`id_product`) | |
'.Shop::addSqlAssociation('product_attribute', 'pa', false, 'product_attribute_shop.`default_on` = 1 AND product_attribute_shop.id_shop='.(int)$context->shop->id):'').' | |
LEFT JOIN '._DB_PREFIX_.'product_lang pl ON (pl.id_product = p.id_product'.Shop::addSqlRestrictionOnLang('pl').' AND pl.id_lang = '.(int)$cookie->id_lang.') | |
LEFT JOIN `'._DB_PREFIX_.'image` i ON (i.`id_product` = p.`id_product`)'. | |
Shop::addSqlAssociation('image', 'i', false, 'image_shop.cover=1').' | |
LEFT JOIN `'._DB_PREFIX_.'image_lang` il ON (image_shop.`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) | |
'.Product::sqlStock('p', 0).' | |
WHERE '.$alias_where.'.`active` = 1 AND '.$alias_where.'.`visibility` IN ("both", "catalog") | |
GROUP BY product_shop.id_product | |
ORDER BY '.Tools::getProductsOrder('by', Tools::getValue('orderby'), true).' '.Tools::getProductsOrder('way', Tools::getValue('orderway')).' , cp.id_product'. | |
' LIMIT '.(((int)$this->page - 1) * $n.','.$n), true, false); | |
} | |
} | |
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) | |
{ | |
return Db::getInstance(_PS_USE_SQL_SLAVE_)->query($sql_query); | |
} | |
public function getFilterBlock($selected_filters = array()) | |
{ | |
global $cookie; | |
static $cache = null; | |
$context = Context::getContext(); | |
$id_lang = $context->language->id; | |
$currency = $context->currency; | |
$id_shop = (int) $context->shop->id; | |
$alias = 'product_shop'; | |
if (is_array($cache)) | |
return $cache; | |
$home_category = Configuration::get('PS_HOME_CATEGORY'); | |
$id_parent = (int)Tools::getValue('id_category', Tools::getValue('id_category_layered', $home_category)); | |
if ($id_parent == $home_category) | |
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 type, id_value, filter_show_limit, filter_type 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' | |
); | |
/* Create the table which contains all the id_product in a cat or a tree */ | |
Db::getInstance()->execute('DROP TEMPORARY TABLE IF EXISTS '._DB_PREFIX_.'cat_restriction', false); | |
Db::getInstance()->execute('CREATE TEMPORARY TABLE '._DB_PREFIX_.'cat_restriction ENGINE=MEMORY | |
SELECT DISTINCT cp.id_product, p.id_manufacturer, product_shop.condition, p.weight FROM '._DB_PREFIX_.'category c | |
STRAIGHT_JOIN '._DB_PREFIX_.'category_product cp 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) | |
STRAIGHT_JOIN '._DB_PREFIX_.'product_shop product_shop ON (product_shop.id_product = cp.id_product | |
AND product_shop.id_shop = '.(int)$context->shop->id.') | |
STRAIGHT_JOIN '._DB_PREFIX_.'product p ON (p.id_product=cp.id_product) | |
WHERE product_shop.`active` = 1 AND product_shop.`visibility` IN ("both", "catalog")', false); | |
Db::getInstance()->execute('ALTER TABLE '._DB_PREFIX_.'cat_restriction ADD PRIMARY KEY (id_product), | |
ADD KEY `id_manufacturer` (`id_manufacturer`,`id_product`) USING BTREE, | |
ADD KEY `condition` (`condition`,`id_product`) USING BTREE, | |
ADD KEY `weight` (`weight`,`id_product`) USING BTREE', false); | |
// 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']) | |
{ | |
case 'price': | |
$sql_query['select'] = 'SELECT p.`id_product`, psi.price_min, psi.price_max '; | |
// price slider is not filter dependent | |
$sql_query['from'] = ' | |
FROM '._DB_PREFIX_.'cat_restriction p'; | |
$sql_query['join'] = 'INNER JOIN `'._DB_PREFIX_.'layered_price_index` psi | |
ON (psi.id_product = p.id_product AND psi.id_currency = '.(int)$context->currency->id.' AND psi.id_shop='.(int)$context->shop->id.')'; | |
$sql_query['where'] = 'WHERE 1'; | |
break; | |
case 'weight': | |
$sql_query['select'] = 'SELECT p.`id_product`, p.`weight` '; | |
// price slider is not filter dependent | |
$sql_query['from'] = ' | |
FROM '._DB_PREFIX_.'cat_restriction p'; | |
$sql_query['where'] = 'WHERE 1'; | |
break; | |
case 'condition': | |
$sql_query['select'] = 'SELECT p.`id_product`, product_shop.`condition` '; | |
$sql_query['from'] = ' | |
FROM '._DB_PREFIX_.'cat_restriction p'; | |
$sql_query['where'] = 'WHERE 1'; | |
$sql_query['from'] .= Shop::addSqlAssociation('product', 'p'); | |
break; | |
case 'quantity': | |
$sql_query['select'] = 'SELECT p.`id_product`, sa.`quantity`, sa.`out_of_stock` '; | |
$sql_query['from'] = ' | |
FROM '._DB_PREFIX_.'cat_restriction p'; | |
$sql_query['join'] .= 'LEFT JOIN `'._DB_PREFIX_.'stock_available` sa | |
ON (sa.id_product = p.id_product AND sa.id_product_attribute=0 '.StockAvailable::addSqlShopRestriction(null, null, 'sa').') '; | |
$sql_query['where'] = 'WHERE 1'; | |
break; | |
case 'manufacturer': | |
$sql_query['select'] = 'SELECT COUNT(DISTINCT p.id_product) nbr, m.id_manufacturer, m.name '; | |
$sql_query['from'] = ' | |
FROM '._DB_PREFIX_.'cat_restriction p | |
INNER JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) '; | |
$sql_query['where'] = 'WHERE 1'; | |
$sql_query['group'] = ' GROUP BY p.id_manufacturer ORDER BY m.name'; | |
if (!Configuration::get('PS_LAYERED_HIDE_0_VALUES')) | |
{ | |
$sql_query['second_query'] = ' | |
SELECT m.name, 0 nbr, m.id_manufacturer | |
FROM '._DB_PREFIX_.'cat_restriction p | |
INNER JOIN '._DB_PREFIX_.'manufacturer m ON (m.id_manufacturer = p.id_manufacturer) | |
WHERE 1 | |
GROUP BY p.id_manufacturer ORDER BY m.name'; | |
} | |
break; | |
case 'id_attribute_group':// attribute group | |
$sql_query['select'] = ' | |
SELECT COUNT(DISTINCT lpa.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 = '.(int)$id_lang.' | |
INNER JOIN '._DB_PREFIX_.'cat_restriction 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 = '.(int)$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 = '.(int)$id_lang.') | |
LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial | |
ON (lial.id_attribute = lpa.id_attribute AND lial.id_lang = '.(int)$id_lang.') '; | |
$sql_query['where'] = 'WHERE lpa.id_attribute_group = '.(int)$filter['id_value']; | |
$sql_query['where'] .= ' AND lpa.`id_shop` = '.(int)$context->shop->id; | |
$sql_query['group'] = ' | |
GROUP BY lpa.id_attribute | |
ORDER BY ag.`position` ASC, a.`position` ASC'; | |
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'. | |
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 = '.(int)$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 = '.(int)$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 = '.(int)$id_lang.') | |
LEFT JOIN '._DB_PREFIX_.'layered_indexable_attribute_lang_value lial | |
ON (lial.id_attribute = lpa.id_attribute AND lial.id_lang = '.(int)$id_lang.') | |
WHERE lpa.id_attribute_group = '.(int)$filter['id_value'].' | |
AND lpa.`id_shop` = '.(int)$context->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_.'cat_restriction 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 fp.id_feature = '.(int)$filter['id_value']; | |
$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'. | |
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 = '.(int)$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 = '.(int)$id_lang.') | |
LEFT JOIN '._DB_PREFIX_.'layered_indexable_feature_lang_value lifl | |
ON (lifl.id_feature = fp.id_feature AND lifl.id_lang = '.(int)$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 = '.(int)$id_lang.') | |
WHERE fp.id_feature = '.(int)$filter['id_value'].' | |
GROUP BY fv.id_feature_value'; | |
} | |
break; | |
case 'category': | |
if (Group::isFeatureActive()) | |
$this->user_groups = ($this->context->customer->isLogged() ? $this->context->customer->getGroups() : array(Configuration::get('PS_UNIDENTIFIED_GROUP'))); | |
$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 AND '.$alias.'.`visibility` IN ("both", "catalog")'; | |
$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_shop` = '.(int)Context::getContext()->shop->id.' and cl.id_lang = '.(int)$id_lang.') '; | |
if (Group::isFeatureActive()) | |
$sql_query['group'] .= 'RIGHT JOIN '._DB_PREFIX_.'category_group cg ON (cg.id_category = c.id_category AND cg.`id_group` IN ('.implode(', ', $this->user_groups).')) '; | |
$sql_query['group'] .= 'WHERE c.nleft > '.(int)$parent->nleft.' | |
AND c.nright < '.(int)$parent->nright.' | |
'.($depth ? 'AND c.level_depth <= '.($parent->level_depth+(int)$depth) : '').' | |
AND c.active = 1 | |
GROUP BY c.id_category ORDER BY c.nleft, c.position'; | |
$sql_query['from'] .= Shop::addSqlAssociation('product', 'p'); | |
} | |
foreach ($filters as $filter_tmp) | |
{ | |
$method_name = 'get'.ucfirst($filter_tmp['type']).'FilterSubQuery'; | |
if (method_exists('BlockLayered', $method_name) && | |
($filter['type'] != 'price' && $filter['type'] != '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'])) | |
{ | |
$products = Db::getInstance()->executeS($sql_query['select']."\n".$sql_query['from']."\n".$sql_query['join']."\n".$sql_query['where']."\n".$sql_query['group'], true, false); | |
} | |
// price & weight have slidebar, so it's ok to not complete recompute the product list | |
if (!empty($selected_filters['price']) && $filter['type'] != 'price' && $filter['type'] != 'weight') { | |
$products = self::filterProductsByPrice(@$selected_filters['price'], $products); | |
} | |
if (!empty($sql_query['second_query'])) | |
{ | |
$res = Db::getInstance()->executeS($sql_query['second_query']); | |
if ($res) | |
$products = array_merge($products, $res); | |
} | |
switch ($filter['type']) | |
{ | |
case 'price': | |
if ($this->showPriceFilter()) { | |
$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) | |
{ | |
//If oosp move all not available quantity to available quantity | |
if ((int)$product['quantity'] > 0 || Product::isAvailableWhenOutOfStock($product['out_of_stock'])) | |
$quantity_array[1]['nbr']++; | |
else | |
$quantity_array[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; | |
} | |
//Natural sort | |
foreach ($feature_array as $key => $value) | |
{ | |
$temp = array(); | |
foreach ($feature_array[$key]['values'] as $keyint => $valueint) | |
$temp[$keyint] = $valueint['name']; | |
natcasesort($temp); | |
$temp2 = array(); | |
foreach ($temp as $keytemp => $valuetemp) | |
$temp2[$keytemp] = $feature_array[$key]['values'][$keytemp]; | |
$feature_array[$key]['values'] = $temp2; | |
} | |
$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 = '.(int)$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 = '.(int)$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'] : $type_filter['name']); | |
$attr_key = $type_filter['type'].'_'.$type_filter['id_key']; | |
$param_group_selected = ''; | |
$lower_filter = strtolower($type_filter['type']); | |
$filter_name_rewritten = Tools::link_rewrite($filter_name); | |
if (($lower_filter == 'price' || $lower_filter == 'weight') | |
&& (float)$type_filter['values'][0] > (float)$type_filter['min'] | |
&& (float)$type_filter['values'][1] > (float)$type_filter['max']) | |
{ | |
$param_group_selected .= $this->getAnchor().str_replace($this->getAnchor(), '_', $type_filter['values'][0]) | |
.$this->getAnchor().str_replace($this->getAnchor(), '_', $type_filter['values'][1]); | |
$param_group_selected_array[$filter_name_rewritten][] = $filter_name_rewritten; | |
if (!isset($title_values[$filter_meta])) | |
$title_values[$filter_meta] = array(); | |
$title_values[$filter_meta][] = $filter_meta; | |
if (!isset($meta_values[$attr_key])) | |
$meta_values[$attr_key] = array('title' => $filter_meta, 'values' => array()); | |
$meta_values[$attr_key]['values'][] = $filter_meta; | |
} | |
else | |
{ | |
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 .= $this->getAnchor().str_replace($this->getAnchor(), '_', Tools::link_rewrite($value_name)); | |
$param_group_selected_array[$filter_name_rewritten][] = Tools::link_rewrite($value_name); | |
if (!isset($title_values[$filter_meta])) | |
$title_values[$filter_meta] = array(); | |
$title_values[$filter_meta][] = $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[$filter_name_rewritten][] = array(); | |
} | |
} | |
if (!empty($param_group_selected)) | |
{ | |
$param_selected .= '/'.str_replace($this->getAnchor(), '_', $filter_name_rewritten).$param_group_selected; | |
$option_checked_array[$filter_name_rewritten] = $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($this->getAnchor(), '_', $filter_name_rewritten).$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; | |
$categorie_link = Context::getContext()->link->getCategoryLink($parent, null, null); | |
foreach ($filter_blocks as &$type_filter) | |
{ | |
$filter_name = (!empty($type_filter['url_name']) ? $type_filter['url_name'] : $type_filter['name']); | |
$filter_link_rewrite = Tools::link_rewrite($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[$filter_link_rewrite])) | |
{ | |
// Update parameter filter checked before | |
if (array_key_exists($filter_link_rewrite, $option_checked_array)) | |
{ | |
$option_checked_clone_array[$filter_link_rewrite] = $option_checked_clone_array[$filter_link_rewrite].$this->getAnchor().str_replace($this->getAnchor(), '_', Tools::link_rewrite($value_name)); | |
if (in_array($type_filter['type'], $blacklist)) | |
$nofollow = true; | |
} | |
else | |
$option_checked_clone_array[$filter_link_rewrite] = $this->getAnchor().str_replace($this->getAnchor(), '_', Tools::link_rewrite($value_name)); | |
} | |
else | |
{ | |
// Remove selected parameters | |
$option_checked_clone_array[$filter_link_rewrite] = str_replace($this->getAnchor().str_replace($this->getAnchor(), '_', Tools::link_rewrite($value_name)), '', $option_checked_clone_array[$filter_link_rewrite]); | |
if (empty($option_checked_clone_array[$filter_link_rewrite])) | |
unset($option_checked_clone_array[$filter_link_rewrite]); | |
} | |
$parameters = ''; | |
ksort($option_checked_clone_array); // Order parameters | |
foreach ($option_checked_clone_array as $key_group => $value_group) | |
$parameters .= '/'.str_replace($this->getAnchor(), '_', $key_group).$value_group; | |
// Add nofollow if any blacklisted filters ins in parameters | |
foreach ($filter_blocks as $filter) | |
{ | |
$name = Tools::link_rewrite((!empty($filter['url_name']) ? $filter['url_name'] : $filter['name'])); | |
if (in_array($filter['type'], $blacklist) && strpos($parameters, $name.'-') !== false) | |
$nofollow = true; | |
} | |
// 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; | |
$type_filter['values'][$key]['link'] = $categorie_link.'#'.ltrim($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; | |
$translate = array(); | |
$translate['price'] = $this->l('price'); | |
$translate['weight'] = $this->l('weight'); | |
$smarty->assign($filter_block); | |
$smarty->assign(array( | |
'hide_0_values' => Configuration::get('PS_LAYERED_HIDE_0_VALUES'), | |
'blocklayeredSliderName' => $translate, | |
'col_img_dir' => _PS_COL_IMG_DIR_ | |
)); | |
return $this->display(__FILE__, 'blocklayered.tpl'); | |
} | |
else | |
return false; | |
} | |
private static function getPriceFilterSubQuery($filter_value, $ignore_join = false) | |
{ | |
$id_currency = (int)Context::getContext()->currency->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].' AND psi.id_shop='.(int)Context::getContext()->shop->id.') '; | |
return array('join' => $price_filter_query); | |
} | |
return array(); | |
} | |
private static function filterProductsByPrice($filter_value, $product_collection) | |
{ | |
static $ps_layered_filter_price_usetax = null; | |
static $ps_layered_filter_price_rounding = null; | |
if (empty($filter_value)) | |
return $product_collection; | |
if ($ps_layered_filter_price_usetax === null) { | |
$ps_layered_filter_price_usetax = Configuration::get('PS_LAYERED_FILTER_PRICE_USETAX'); | |
} | |
if ($ps_layered_filter_price_rounding === null) { | |
$ps_layered_filter_price_rounding = Configuration::get('PS_LAYERED_FILTER_PRICE_ROUNDING'); | |
} | |
foreach ($product_collection as $key => $product) | |
{ | |
if (isset($filter_value) && $filter_value && isset($product['price_min']) && isset($product['id_product']) | |
&& (($product['price_min'] < (int)$filter_value[0] && $product['price_max'] > (int)$filter_value[0]) | |
|| ($product['price_max'] > (int)$filter_value[1] && $product['price_min'] < (int)$filter_value[1]))) | |
{ | |
$price = Product::getPriceStatic($product['id_product'], $ps_layered_filter_price_usetax); | |
if ($ps_layered_filter_price_rounding) { | |
$price = (int)$price; | |
} | |
if ($price < $filter_value[0] || $price > $filter_value[1]) { | |
unset($product_collection[$key]); | |
} | |
} | |
} | |
return $product_collection; | |
} | |
private static function getWeightFilterSubQuery($filter_value, $ignore_join = false) | |
{ | |
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 = false) | |
{ | |
if (empty($filter_value)) | |
return array(); | |
$query_filters = ' AND EXISTS (SELECT * FROM '._DB_PREFIX_.'feature_product fp WHERE fp.id_product = p.id_product AND '; | |
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 = false) | |
{ | |
if (empty($filter_value)) | |
return array(); | |
$query_filters = ' | |
AND EXISTS (SELECT * | |
FROM `'._DB_PREFIX_.'product_attribute_combination` pac | |
LEFT JOIN `'._DB_PREFIX_.'product_attribute` pa ON (pa.`id_product_attribute` = pac.`id_product_attribute`) | |
WHERE pa.id_product = p.id_product AND '; | |
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 = false) | |
{ | |
if (empty($filter_value)) | |
return array(); | |
$query_filters_where = ' AND EXISTS (SELECT * FROM '._DB_PREFIX_.'category_product cp WHERE id_product = p.id_product AND '; | |
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); | |
} | |
private static function getQuantityFilterSubQuery($filter_value, $ignore_join = false) | |
{ | |
if (count($filter_value) == 2 || empty($filter_value)) | |
return array(); | |
$query_filters_join = ''; | |
$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.') '; | |
return array('where' => $query_filters, 'join' => $query_filters_join); | |
} | |
private static function getManufacturerFilterSubQuery($filter_value, $ignore_join = false) | |
{ | |
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); | |
else | |
return array('where' => $query_filters, 'join' => 'LEFT JOIN `'._DB_PREFIX_.'manufacturer` m ON (m.id_manufacturer = p.id_manufacturer) '); | |
} | |
private static function getConditionFilterSubQuery($filter_value, $ignore_join = false) | |
{ | |
if (count($filter_value) == 3 || empty($filter_value)) | |
return array(); | |
$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 ajaxCall() | |
{ | |
global $smarty, $cookie; | |
$selected_filters = $this->getSelectedFilters(); | |
$filter_block = $this->getFilterBlock($selected_filters); | |
$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); | |
Hook::exec( | |
'actionProductListModifier', | |
array( | |
'nb_products' => &$nb_products, | |
'cat_products' => &$products, | |
) | |
); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$this->context->controller->addColorsToProductList($products); | |
$category = new Category(Tools::getValue('id_category_layered', Configuration::get('PS_HOME_CATEGORY')), (int)$cookie->id_lang); | |
// Generate meta title and meta description | |
$category_title = (empty($category->meta_title) ? $category->name : $category->meta_title); | |
$category_metas = Meta::getMetaTags((int)$cookie->id_lang, 'category'); | |
$title = ''; | |
$keywords = ''; | |
if (is_array($filter_block['title_values'])) | |
foreach ($filter_block['title_values'] as $key => $val) | |
{ | |
$title .= ' > '.$key.' '.implode('/', $val); | |
$keywords .= $key.' '.implode('/', $val).', '; | |
} | |
$title = $category_title.$title; | |
if (!empty($title)) | |
$meta_title = $title; | |
else | |
$meta_title = $category_metas['meta_title']; | |
$meta_description = $category_metas['meta_description']; | |
$keywords = Tools::substr(Tools::strtolower($keywords), 0, 1000); | |
if (!empty($keywords)) | |
$meta_keywords = rtrim($category_title.', '.$keywords.', '.$category_metas['meta_keywords'], ', '); | |
$smarty->assign( | |
array( | |
'homeSize' => Image::getSize(ImageType::getFormatedName('home')), | |
'nb_products' => $nb_products, | |
'category' => $category, | |
'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, | |
'compareProducts' => CompareProduct::getCompareProducts((int)$this->context->cookie->id_compare) | |
) | |
); | |
// 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'); | |
$vars = array( | |
'filtersBlock' => utf8_encode($this->generateFiltersBlock($selected_filters)), | |
'productList' => utf8_encode($product_list), | |
'pagination' => $smarty->fetch(_PS_THEME_DIR_.'pagination.tpl'), | |
'categoryCount' => $category_count, | |
'meta_title' => $meta_title.' - '.Configuration::get('PS_SHOP_NAME'), | |
'heading' => $meta_title, | |
'meta_keywords' => isset($meta_keywords) ? $meta_keywords : null, | |
'meta_description' => $meta_description, | |
'current_friendly_url' => ((int)$n == (int)$nb_products) ? '#/show-all': '#'.$filter_block['current_friendly_url'], | |
'filters' => $filter_block['filters'], | |
'nbRenderedProducts' => (int)$nb_products, | |
'nbAskedProducts' => (int)$n | |
); | |
if (version_compare(_PS_VERSION_, '1.6.0', '>=') === true) | |
$vars = array_merge($vars, array('pagination_bottom' => $smarty->assign('paginationId', 'bottom') | |
->fetch(_PS_THEME_DIR_.'pagination.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($vars); | |
} | |
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 */ | |
$product_per_page = isset($this->context->cookie->nb_item_per_page) ? (int)$this->context->cookie->nb_item_per_page : Configuration::get('PS_PRODUCTS_PER_PAGE'); | |
$n = (int)Tools::getValue('n', Configuration::get('PS_PRODUCTS_PER_PAGE')); | |
if ($n <= 0) | |
$n = 1; | |
$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); | |
foreach ($products as &$product) | |
{ | |
if ($product['id_product_attribute'] && isset($product['product_attribute_minimal_quantity'])) | |
$product['minimal_quantity'] = $product['product_attribute_minimal_quantity']; | |
} | |
} | |
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 = ''; | |
$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 AND '.$alias.'.`visibility` IN ("both", "catalog") | |
'.(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 AND '.$alias.'.`visibility` IN ("both", "catalog") '.(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 AND '.$alias.'.`visibility` IN ("both", "catalog") | |
'.(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'); | |
$shop_list = Shop::getShops(false, null, true); | |
$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 ($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; | |
} | |
if (is_array($attribute_groups_by_id) && count($attribute_groups_by_id) > 0) | |
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; | |
} | |
if (is_array($attribute_groups_by_id) && count($attribute_groups_by_id) > 0) | |
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())'); | |
$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 = Tools::unSerialize($filter_template['filters']); | |
foreach ($data['shop_list'] as $id_shop) | |
{ | |
if (!isset($categories[$id_shop])) | |
$categories[$id_shop] = array(); | |
foreach ($data['categories'] as $id_category) | |
{ | |
$n = 0; | |
if (!in_array($id_category, $categories[$id_shop])) // Last definition, erase preivious categories defined | |
{ | |
$categories[$id_shop][] = $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++; | |
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, ',')); | |
} | |
protected function getAnchor() | |
{ | |
static $anchor = null; | |
if ($anchor === null) | |
if (!$anchor = Configuration::get('PS_ATTRIBUTE_ANCHOR_SEPARATOR')) | |
$anchor = '-'; | |
return $anchor; | |
} | |
protected function showPriceFilter() | |
{ | |
return Group::getCurrent()->show_prices; | |
} | |
protected function filterVar($value) | |
{ | |
if (version_compare(_PS_VERSION_, '1.6.0.7', '>=') === true) | |
return Tools::purifyHTML($value); | |
else | |
return filter_var($value, FILTER_SANITIZE_STRING); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment