Catalog Price Rules is a widely used Prestashop tool for mass creation of discounts. But if you have a lot of features and feature_values associated with them, one day this function can get unavailable for you. Let’s check why exactly you won’t be able to use it.
![]()
The reason is hidden in the AdminSpecificPriceRuleControllerCore::renderForm method, and more particularly here:
|
1 2 3 4 5 6 |
``` $features = Feature::getFeatures((int)$this->context->language->id); foreach ($features as &$feature) { $feature['values'] = FeatureValue::getFeatureValuesWithLang((int)$this->context->language->id, $feature['id_feature'], true); } ``` |
The thing is while loading the form, Prestashop tries to load all features and their values because Catalog Price Rules allows using Features as one of the conditions for a discount.

We solved this problem using asynchronous load of Feature Values.
To do so made a few corrections:
1.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
``` $features = Feature::getFeatures((int)$this->context->language->id); foreach ($features as &$feature) $feature['values'] = array(); /*FeatureValue::getFeatureValuesWithLang((int)$this->context->language->id, $feature['id_feature'], true);*/ // we simply create an empty array instead of loading all values /*override [begin]*/ //for created conditions we load features values $conditions = $this->object->getConditions(); foreach ($conditions as $condition) { foreach ($condition as $cond) { $f_value = array(); if ($cond['type'] == 'feature') { $f_value = FeatureValue::getFeatureValueWithLang((int)$this->context->language->id, $cond['id_feature'], $cond['value']); foreach ($features as &$feature) { if ($feature['id_feature'] == $f_value['id_feature']) { $feature['values'][] = $f_value; } } } } } /*override [end]*/ ``` |
2. The FeatureValue::getFeatureValueWithLang() class is a new method that gets values for a particular Feature.
class FeatureValue extends FeatureValueCore
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
{ public static function getFeatureValueWithLang($id_lang, $id_feature, $id_feature_value) { return Db::getInstance()->getRow(' SELECT * FROM `'._DB_PREFIX_.'feature_value` v LEFT JOIN `'._DB_PREFIX_.'feature_value_lang` vl ON (v.`id_feature_value` = vl.`id_feature_value` AND vl.`id_lang` = '.(int)$id_lang.') WHERE v.`id_feature` = '.(int)$id_feature.' AND v.`id_feature_value` = '.(int)$id_feature_value.' ORDER BY vl.`value` ASC '); } } |
3. The SpecificPriceRule::getConditions() class
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
``` class SpecificPriceRule extends SpecificPriceRuleCore { public function getConditions() { $conditions = Db::getInstance()->executeS(' SELECT g.*, c.* FROM '._DB_PREFIX_.'specific_price_rule_condition_group g LEFT JOIN '._DB_PREFIX_.'specific_price_rule_condition c ON (c.id_specific_price_rule_condition_group = g.id_specific_price_rule_condition_group) WHERE g.id_specific_price_rule='.(int)$this->id ); $conditions_group = array(); if ($conditions) { foreach ($conditions as &$condition) { if ($condition['type'] == 'attribute') $condition['id_attribute_group'] = Db::getInstance()->getValue('SELECT id_attribute_group FROM '._DB_PREFIX_.'attribute WHERE id_attribute='.(int)$condition['value']); elseif ($condition['type'] == 'feature') { $condition['id_feature'] = Db::getInstance()->getValue('SELECT id_feature FROM '._DB_PREFIX_.'feature_value WHERE id_feature_value='.(int)$condition['value']); $condition['value_name'] = Db::getInstance()->getValue('select value FROM `'._DB_PREFIX_.'feature_value_lang` where id_feature_value = '.(int)$condition['value'].' AND id_lang = ' . Context::getContext()->language->id); //override reason: get feature value } $conditions_group[(int)$condition['id_specific_price_rule_condition_group']][] = $condition; } } return $conditions_group; } } ``` |
4. Override of a theme file
/administration/themes/default/template/controllers/specific_price_rule/helpers/form/form.tpl
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
... //action when we change id_feature values, we load feature values asynchronously $('#id_feature').change(function() { $('.id_feature_value').hide(); $.ajax({ type: 'POST', url: currentIndex, headers: { "cache-control": "no-cache" }, async: true, data: 'token=' + token + '&ajax=1&action=getFeatureValues&id_feature=' + $('#id_feature').val(), cache: false, dataType: 'json', success: function(data) { //console.log(data); for (i = 0; i < data.length; i++) { $('#id_feature_' + $('#id_feature').val()).append($('<option>').text(data[i].value).attr('value', data[i].id_feature_value)); } } }); $('#id_feature_'+$(this).val()).show(); }); ``` |
5. New action in AdminSpecificPriceRuleController::ajaxProcessGetFeatureValues() controller that is used in /administration/themes/default/template/controllers/specific_price_rule/helpers/form/form.tpl
|
1 2 3 4 5 6 7 8 9 10 |
``` public function ajaxProcessGetFeatureValues() { $id_feature = Tools::getValue('id_feature'); $values = FeatureValue::getFeatureValuesWithLang((int)$this->context->language->id, $id_feature, true); die(Tools::jsonEncode($values)); } ``` |
Download all changed files here.
@Andrei, link is fixed
Hello,
Is it possible to fix the link, download is not working. Also i am having issues to understand exactly where you need to modify, could you please look maybe you havent specified clearly what file and where to add/modify.
Thank you