How can I modify the data that Finder downloads from my store? #
Finder periodically downloads products, categories, orders, and other data from your store in order to provide search results. If you need to adjust this information before it is downloaded (hide certain products, add content to a text field, exclude a feature that does not contribute anything to search, etc.), you can do so using the hooks that Finder triggers during this process, without modifying the Finder module or your actual catalog.
How do Finder hooks work? #
PrestaShop allows any module to “hook into” specific points in another module’s execution using hooks. Finder triggers a series of its own hooks just before querying the database and just after reading each type of data. A hook is always registered from a module’s install() method, so you need your own PrestaShop module to listen to them: you can add them to a module you already have installed in your store, or create a new one specifically for this purpose.
Creating a module to register the hooks #
It is a standard PrestaShop module, with nothing special about it: its own technical name, a class that extends Module, and the hooks you are interested in registered in install(). For each registered hook, implement a method named hook + the hook name:
<?php
if (!defined('_PS_VERSION_')) {
exit;
}
class MiTiendaFinderHooks extends Module
{
public function __construct()
{
$this->name = 'mitiendafinderhooks';
$this->tab = 'administration';
$this->version = '1.0.0';
$this->author = 'Mi tienda';
$this->need_instance = 0;
$this->bootstrap = true;
parent::__construct();
$this->displayName = 'Finder Settings';
$this->description = 'Custom settings for the data downloaded by Finder';
$this->ps_versions_compliancy = ['min' => '1.6', 'max' => '9.999'];
}
public function install()
{
return parent::install()
&& $this->registerHook('sbFinderAfterGetSourceProduct');
// add any other hooks you need here, see the list below
}
public function uninstall()
{
return parent::uninstall();
}
public function hookSbFinderAfterGetSourceProduct(array &$params)
{
// your logic here
}
}You can choose the module and class names freely. They only need to be compatible with the version of PrestaShop used by your store, written in plain PHP and without Composer dependencies. Once written, package it as a .zip file and install it from the back office like any other module, or upload the uncompressed folder to the modules folder of your store on the server.
Hooks available to exclude data before querying it #
These three hooks are triggered just before Finder builds the SQL query for each type of data. They allow you to exclude entire records by adding conditions to the query:
- sbFinderBeforeObjectModelNumRowsDBQuery
- sbFinderBeforeObjectModelPaginateDBQuery
- sbFinderBeforeObjectModelSearchByFiltersAndSourceIdDBQuery
All three receive the same parameters: $params[‘model’] (a string identifying what is being queried) and $params[‘query’] (a PrestaShop DbQuery object, passed by reference, to which you can add a where() condition). Possible values for model are: product, category, order, cms_category, cms, supplier, manufacturer, tag, attribute or product_attribute (depending on the PrestaShop version), attribute_group, carrier, cart_rule, country, feature, feature_value, currency and group.
The main table in the query always has the alias a (and, when the query joins language or shop tables, those aliases are l and s). For example, to completely exclude certain features:
public function hookSbFinderBeforeObjectModelNumRowsDBQuery(array &$params)
{
$this->excludeFeatures($params['model'], $params['query']);
}
public function hookSbFinderBeforeObjectModelPaginateDBQuery(array &$params)
{
$this->excludeFeatures($params['model'], $params['query']);
}
public function hookSbFinderBeforeObjectModelSearchByFiltersAndSourceIdDBQuery(array &$params)
{
$this->excludeFeatures($params['model'], $params['query']);
}
private function excludeFeatures(string $model, DbQuery $query)
{
$excludedIds = [12, 15]; // Feature IDs you do not want to index
if ($model === 'feature' && !empty($excludedIds)) {
$query->where('a.id_feature NOT IN (' . implode(', ', $excludedIds) . ')');
}
}Note: to exclude a data type, you need to register and handle all three hooks at the same time, because Finder uses them at different stages (counting results, paginating, and searching by filters).
Hooks available to modify data after it has been retrieved #
These hooks are triggered after Finder has read each type of data and before sending it, one for each data source:
- Products: sbFinderAfterGetSourceProduct
- Categories: sbFinderAfterGetSourceCategory
- Orders: sbFinderAfterGetSourceOrder
- Content categories (CMS): sbFinderAfterGetSourceCMSCategory
- Content pages (CMS): sbFinderAfterGetSourceCMS
- Suppliers: sbFinderAfterGetSourceSupplier
- Manufacturers: sbFinderAfterGetSourceManufacturer
- Tags: sbFinderAfterGetSourceTag
- Attributes: sbFinderAfterGetSourceAttribute
- Product combinations: sbFinderAfterGetSourceProductAttribute
- Attribute groups: sbFinderAfterGetSourceAttributeGroup
- Carriers: sbFinderAfterGetSourceCarrier
- Cart rules: sbFinderAfterGetSourceCartRule
- Countries: sbFinderAfterGetSourceCountry
- Features: sbFinderAfterGetSourceFeature
- Feature values: sbFinderAfterGetSourceFeatureValue
- Currencies: sbFinderAfterGetSourceCurrency
- Customer groups: sbFinderAfterGetSourceGroup
All of them receive $params[‘records’]: an array containing the records on that page, passed by reference, which you can iterate over and modify directly. Among other keys, each record contains meta_keys (for example, the original id_product), texts (an array with an {iso, name, value} entry for each translatable field and language), and platform_attributes (the remaining columns from the store: price, stock, whether it is active, images, features, etc., depending on the data type).
For example, adding additional information to a product’s short description in Spanish before Finder indexes it:
public function hookSbFinderAfterGetSourceProduct(array &$params)
{
$products = &$params['records'];
foreach ($products as &$product) {
$extra = $this->getExtraKeywordsForProduct($product);
if (empty($extra) || empty($product['texts'])) {
continue;
}
foreach ($product['texts'] as &$text) {
if ($text['name'] === 'description_short' && $text['iso'] === 'es') {
$text['value'] = trim($text['value'] . '. ' . implode(', ', $extra));
}
}
}
}For example, hiding a product from search results when it meets a store-specific condition, without disabling it in the catalog:
public function hookSbFinderAfterGetSourceProduct(array &$params)
{
$products = &$params['records'];
foreach ($products as &$product) {
if ($this->shouldBeHiddenFromSearch($product)) {
$product['platform_attributes']['active'] = false;
}
}
}Best practices #
- “After retrieving the data” hooks receive an entire page at once, not one record at a time. If you need to query the database inside the hook, do it once for all the IDs on the page (for example, using a WHERE id_product IN (…)) instead of running one query per product.
- Only modify keys that already exist in the record (texts, platform_attributes, etc.); do not change the general structure expected by Finder.
- To exclude data completely, it is more efficient to do so with the “before querying” hooks (so it is never downloaded) than to filter it afterwards with an “after retrieving the data” hook.
- Test your changes with a controlled product before deploying them to production.
Need help? #
If you have any questions after reading the documentation or need help with a specific use case, contact us.