2017-06-07 16:31:24 +02:00
< ? 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 );
2017-09-22 17:55:15 +02:00
foreach ( $products as $key => $product )
{
$palier = Category :: getPalier ( $product [ 'id_category_default' ]);
$palier_attr = new Attribute ( $palier , ( int ) $this -> context -> language -> id );
$products [ $key ][ 'palier' ] = intval ( $palier_attr -> name );
$pad = Db :: getInstance () -> getValue ( '
SELECT pa . `id_product_attribute`
FROM `'._DB_PREFIX_.'product_attribute` pa
LEFT JOIN `'._DB_PREFIX_.'product_attribute_combination` pac ON pac . `id_product_attribute` = pa . `id_product_attribute`
WHERE pac . `id_attribute` = '.(int) $palier. '
AND pa . `id_product` = ' .(int)$product[' id_product ' ]
);
if ( $pad ) {
$products [ $key ][ 'price_palier' ] = Product :: getPriceStatic ( $product [ 'id_product' ], true , $pad ) / ( int ) $palier_attr -> name ;
} else {
$products [ $key ][ 'price_palier' ] = $product [ 'price' ];
}
}
2017-06-07 16:31:24 +02:00
$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 );
}
}