Skip to content

Commit

Permalink
Add highlights feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Hlavtox committed Jul 17, 2023
1 parent c674d75 commit 263ed3a
Show file tree
Hide file tree
Showing 6 changed files with 212 additions and 3 deletions.
13 changes: 12 additions & 1 deletion ps_facetedsearch.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,9 @@ protected function getDefaultFilters()
'label' => 'Product price filter (slider)',
'slider' => true,
],
'layered_selection_highlights' => [
'label' => 'Product highlights filter',
],
];
}

Expand Down Expand Up @@ -990,7 +993,7 @@ public function rebuildLayeredStructure()
`controller` VARCHAR(64) 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\',\'availability\',\'condition\',\'manufacturer\',\'weight\',\'price\') NOT NULL,
`type` ENUM(\'category\',\'id_feature\',\'id_attribute_group\',\'availability\',\'condition\',\'manufacturer\',\'weight\',\'price\',\'highlights\') 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,
Expand Down Expand Up @@ -1191,6 +1194,12 @@ public function rebuildLayeredCache($productsIds = [], $categoriesIds = [], $reb
$doneCategories[(int) $idCategory]['p'] = true;
$toInsert = true;
}

if (!isset($doneCategories[(int) $idCategory]['q'])) {
$filterData['layered_selection_highlights'] = ['filter_type' => Converter::WIDGET_TYPE_CHECKBOX, 'filter_show_limit' => 0];
$doneCategories[(int) $idCategory]['e'] = true;
$toInsert = true;
}
}
}

Expand Down Expand Up @@ -1295,6 +1304,8 @@ public function buildLayeredCategories()
} elseif (substr($key, 0, 23) == 'layered_selection_feat_') {
$sqlInsert .= '(' . (int) $idCategory . ', \'' . $controller . '\', ' . (int) $idShop . ', ' . (int) str_replace('layered_selection_feat_', '', $key) . ',
\'id_feature\',' . (int) $n . ', ' . (int) $limit . ', ' . (int) $type . '),';
} elseif ($key == 'layered_selection_highlights') {
$sqlInsert .= '(' . (int) $idCategory . ', \'' . $controller . '\', ' . (int) $idShop . ', NULL,\'highlights\',' . (int) $n . ', ' . (int) $limit . ', ' . (int) $type . '),';
}

++$nbSqlValuesToInsert;
Expand Down
96 changes: 96 additions & 0 deletions src/Filters/Block.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ public function getFilterBlock(
case 'availability':
$filterBlocks[] = $this->getAvailabilitiesBlock($filter, $selectedFilters);
break;
case 'highlights':
$filterBlocks[] = $this->getHighlightsBlock($filter, $selectedFilters);
break;
case 'manufacturer':
$filterBlocks[] = $this->getManufacturersBlock($filter, $selectedFilters, $idLang);
break;
Expand Down Expand Up @@ -524,6 +527,99 @@ private function getAvailabilitiesBlock($filter, $selectedFilters)
return $quantityBlock;
}

/**
* Gets block for extra product properties like "new", "on sale" and "discounted"
*
* @param array $filter
* @param array $selectedFilters
*
* @return array
*/
private function getHighlightsBlock($filter, $selectedFilters)
{
// Prepare array with options
$highlightsOptions = [];

// Products on sale - available everywhere
$highlightsOptions['sale'] = [
'name' => $this->context->getTranslator()->trans(
'On sale',
[],
'Modules.Facetedsearch.Shop'
),
'nbr' => 0,
];
$filteredSearchAdapter = $this->searchAdapter->getFilteredSearchAdapter('on_sale');
$filteredSearchAdapter->addFilter('on_sale', [1], '=');
// We need to add the field to initial population of the filter, because we won't be joining any additional tables
$filteredSearchAdapter->getInitialPopulation()->addSelectField('on_sale');
$highlightsOptions['sale']['nbr'] = $filteredSearchAdapter->count();

// New products - available everywhere except that page
if ($this->query->getQueryType() != 'new-products') {
$highlightsOptions['new'] = [
'name' => $this->context->getTranslator()->trans(
'New product',
[],
'Modules.Facetedsearch.Shop'
),
'nbr' => 0,
];
$filteredSearchAdapter = $this->searchAdapter->getFilteredSearchAdapter('date_add');
$timeCondition = date(
'Y-m-d 00:00:00',
strtotime(
((int) Configuration::get('PS_NB_DAYS_NEW_PRODUCT') > 0 ?
'-' . ((int) Configuration::get('PS_NB_DAYS_NEW_PRODUCT') - 1) . ' days' :
'+ 1 days')
)
);
$filteredSearchAdapter->addFilter('date_add', ["'" . $timeCondition . "'"], '>');
// We need to add the field to initial population of the filter, because we won't be joining any additional tables
$filteredSearchAdapter->getInitialPopulation()->addSelectField('date_add');
$highlightsOptions['new']['nbr'] = $filteredSearchAdapter->count();
}

// Discounted products - available everywhere except that page
if ($this->query->getQueryType() != 'prices-drop') {
$highlightsOptions['discount'] = [
'name' => $this->context->getTranslator()->trans(
'Discounted',
[],
'Modules.Facetedsearch.Shop'
),
'nbr' => 0,
];
$filteredSearchAdapter = $this->searchAdapter->getFilteredSearchAdapter('reduction');
$filteredSearchAdapter->addFilter('reduction', [0], '>');
// No need to add any selects here, because the initial population doesn't change
// and the where condition will operate over externally joined table
$highlightsOptions['discount']['nbr'] = $filteredSearchAdapter->count();
}

// If some filters are selected, we mark them as such
if (isset($selectedFilters['highlights'])) {
// We loop through selected filters and assign it to our options and remove the rest
foreach ($highlightsOptions as $key => $values) {
if (in_array($key, $selectedFilters['highlights'], true)) {
$highlightsOptions[$key]['checked'] = true;
}
}
}

$conditionBlock = [
'type_lite' => 'highlights',
'type' => 'highlights',
'id_key' => 0,
'name' => $this->context->getTranslator()->trans('Highlights', [], 'Modules.Facetedsearch.Shop'),
'values' => $highlightsOptions,
'filter_show_limit' => (int) $filter['filter_show_limit'],
'filter_type' => $filter['filter_type'],
];

return $conditionBlock;
}

/**
* Get the manufacturers filter block
*
Expand Down
35 changes: 35 additions & 0 deletions src/Filters/Converter.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class Converter
const TYPE_MANUFACTURER = 'manufacturer';
const TYPE_PRICE = 'price';
const TYPE_WEIGHT = 'weight';
const TYPE_HIGHLIGHTS = 'highlights';

const PROPERTY_URL_NAME = 'url_name';
const PROPERTY_COLOR = 'color';
Expand Down Expand Up @@ -114,6 +115,7 @@ public function getFacetsFromFilterBlocks(array $filterBlocks)
switch ($filterBlock['type']) {
case self::TYPE_CATEGORY:
case self::TYPE_CONDITION:
case self::TYPE_HIGHLIGHTS:
case self::TYPE_MANUFACTURER:
case self::TYPE_AVAILABILITY:
case self::TYPE_ATTRIBUTE_GROUP:
Expand Down Expand Up @@ -348,6 +350,37 @@ public function createFacetedSearchFiltersFromQuery(ProductSearchQuery $query)
}
}
break;
case self::TYPE_HIGHLIGHTS:
if (!isset($facetAndFiltersLabels[$filterLabel])) {
// No need to filter if no information
continue 2;
}

$highlightsOptions = [
$this->context->getTranslator()->trans(
'New product',
[],
'Modules.Facetedsearch.Shop'
) => 'new',
$this->context->getTranslator()->trans(
'On sale',
[],
'Modules.Facetedsearch.Shop'
) => 'sale',
$this->context->getTranslator()->trans(
'Discounted',
[],
'Modules.Facetedsearch.Shop'
) => 'discount',
];

$searchFilters[$filter['type']] = [];
foreach ($highlightsOptions as $highlightsOption => $optionId) {
if (isset($facetAndFiltersLabels[$filterLabel]) && in_array($highlightsOption, $facetAndFiltersLabels[$filterLabel])) {
$searchFilters[$filter['type']][] = $optionId;
}
}
break;
case self::TYPE_FEATURE:
$features = $this->dataAccessor->getFeatures($idLang);
foreach ($features as $feature) {
Expand Down Expand Up @@ -468,6 +501,8 @@ private function convertFilterTypeToLabel($filterType)
return $this->context->getTranslator()->trans('Weight', [], 'Modules.Facetedsearch.Shop');
case self::TYPE_CONDITION:
return $this->context->getTranslator()->trans('Condition', [], 'Modules.Facetedsearch.Shop');
case self::TYPE_HIGHLIGHTS:
return $this->context->getTranslator()->trans('Highlights', [], 'Modules.Facetedsearch.Shop');
case self::TYPE_AVAILABILITY:
return $this->context->getTranslator()->trans('Availability', [], 'Modules.Facetedsearch.Shop');
case self::TYPE_MANUFACTURER:
Expand Down
36 changes: 34 additions & 2 deletions src/Product/Search.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function initSearch($selectedFilters)
// Add filters that the user has selected for current query
$this->addSearchFilters($selectedFilters);

// Adds filters that specific for category page
// Adds filters that specific for this controller
$this->addControllerSpecificFilters();

// Add group by and flush it, let's go
Expand Down Expand Up @@ -169,6 +169,28 @@ private function addSearchFilters($selectedFilters)
$this->addFilter('id_category', $filterValues);
break;

case 'highlights':
if (in_array('new', $filterValues)) {
$timeCondition = date(
'Y-m-d 00:00:00',
strtotime(
((int) Configuration::get('PS_NB_DAYS_NEW_PRODUCT') > 0 ?
'-' . ((int) Configuration::get('PS_NB_DAYS_NEW_PRODUCT') - 1) . ' days' :
'+ 1 days')
)
);
// Reset filter to prevent two same filters if we are on new products page
$this->getSearchAdapter()->addFilter('date_add', ["'" . $timeCondition . "'"], '>');
}
if (in_array('discount', $filterValues)) {
// Reset filter to prevent two same filters if we are on "prices-drop" page
$this->getSearchAdapter()->addFilter('reduction', [0], '>');
}
if (in_array('sale', $filterValues)) {
$this->getSearchAdapter()->addFilter('on_sale', [1], '=');
}
break;

case 'availability':
/*
* $filterValues options can have following values:
Expand Down Expand Up @@ -311,7 +333,7 @@ private function addControllerSpecificFilters()
{
// Category page
if ($this->query->getQueryType() == 'category') {
// If any category filter was user selected, we don't have anything to do here
// We check if some specific filter of this type wasn't added before
if (!empty($this->getSearchAdapter()->getFilter('id_category'))) {
return;
}
Expand Down Expand Up @@ -356,6 +378,11 @@ private function addControllerSpecificFilters()
* If there is a zero set to disable this feature, it creates unreachable condition.
*/
if ($this->query->getQueryType() == 'new-products') {
// We check if some specific filter of this type wasn't added before
if (!empty($this->getSearchAdapter()->getFilter('date_add'))) {
return;
}

$timeCondition = date(
'Y-m-d 00:00:00',
strtotime(
Expand All @@ -382,6 +409,11 @@ private function addControllerSpecificFilters()
* We are selecting products that have a specific price created meeting certain conditions.
*/
if ($this->query->getQueryType() == 'prices-drop') {
// We check if some specific filter of this type wasn't added before
if (!empty($this->getSearchAdapter()->getFilter('reduction'))) {
return;
}

$this->getSearchAdapter()->addFilter('reduction', [0], '>');
}

Expand Down
5 changes: 5 additions & 0 deletions upgrade/upgrade-3.13.0.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@

function upgrade_module_3_13_0(Ps_Facetedsearch $module)
{
// Add new filter type into database
Db::getInstance()->execute(
'ALTER TABLE `' . _DB_PREFIX_ . 'layered_category`
CHANGE `type` `type` ENUM(\'category\',\'id_feature\',\'id_attribute_group\',\'availability\',\'condition\',\'manufacturer\',\'weight\',\'price\',\'highlights\') NOT NULL;');

$newHooks = [
'actionFeatureValueFormBuilderModifier',
'actionAfterCreateFeatureValueFormHandler',
Expand Down
30 changes: 30 additions & 0 deletions views/templates/admin/add.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,36 @@
</div>
</div>
</li>

<li class="filter_list_item row" draggable="true">
<div class="col-lg-2">
<label class="switch-light prestashop-switch fixed-width-lg">
<input name="layered_selection_highlights" id="layered_selection_highlights" type="checkbox" />
<span>
<span>{l s='Yes' d='Admin.Global'}</span>
<span>{l s='No' d='Admin.Global'}</span>
</span>
<a class="slide-button btn"></a>
</label>
</div>
<div class="col-lg-4">
<span class="module_name">{l s='Product highlights filter' d='Modules.Facetedsearch.Admin'}</span>
</div>
<div class="col-lg-3 pull-right">
<label class="control-label col-lg-6">{l s='Filter result limit:' d='Modules.Facetedsearch.Admin'}</label>
<div class="col-lg-6">
{call get_limit_select element="layered_selection_highlights"}
</div>
</div>
<div class="col-lg-3 pull-right">
<label class="control-label col-lg-6">{l s='Filter style:' d='Modules.Facetedsearch.Admin'}</label>
<div class="col-lg-6">
<input type="hidden" name="layered_selection_highlights" value="0">
<p class="form-control-static">{l s='Checkbox' d='Modules.Facetedsearch.Admin'}</p>
</div>
</div>
</li>

<li class="filter_list_item row" draggable="true">
<div class="col-lg-2">
<label class="switch-light prestashop-switch fixed-width-lg">
Expand Down

0 comments on commit 263ed3a

Please sign in to comment.