From d11636746de937347c3156cc9180b0bbf210c2ab Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Tue, 7 Mar 2023 14:17:48 +0530 Subject: [PATCH 01/20] Added personalization tag and usertoken in autocomplete search request --- view/frontend/web/insights.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/view/frontend/web/insights.js b/view/frontend/web/insights.js index fa948757c..7a396e3a0 100644 --- a/view/frontend/web/insights.js +++ b/view/frontend/web/insights.js @@ -67,6 +67,17 @@ requirejs([ return allWidgetConfiguration; }); + + algolia.registerHook('beforeAutocompleteProductSourceOptions', function(options) { + if (algoliaConfig.ccAnalytics.enabled) { + options.clickAnalytics = true; + } + if (algoliaConfig.personalization.enabled) { + options.enablePersonalization = true; + options.userToken = algoliaAnalytics.getUserToken(); + } + return options; + }); this.hasAddedParameters = true; From 83e64ffcd82c395dde43888ac7f0c922ef78a57a Mon Sep 17 00:00:00 2001 From: Marcus Schwarz Date: Thu, 9 Mar 2023 12:27:49 +0100 Subject: [PATCH 02/20] Use getTable from ModuleDataSetupInterface to get table name with prefix --- Setup/Patch/Schema/RecommendConfigPatch.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Setup/Patch/Schema/RecommendConfigPatch.php b/Setup/Patch/Schema/RecommendConfigPatch.php index aa364b30f..47d002397 100644 --- a/Setup/Patch/Schema/RecommendConfigPatch.php +++ b/Setup/Patch/Schema/RecommendConfigPatch.php @@ -62,7 +62,7 @@ public function apply() $this->moduleDataSetup->getConnection()->startSetup(); $connection = $this->moduleDataSetup->getConnection(); - $table = $connection->getTableName('core_config_data'); + $table = $this->moduleDataSetup->getTable('core_config_data'); foreach ($movedConfigDirectives as $from => $to) { try { $connection->query('UPDATE ' . $table . ' SET path = "' . $to . '" WHERE path = "' . $from . '"'); From 27e3f945e41207748ec3df5d9c959886a7837980 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Tue, 14 Mar 2023 20:22:13 +0530 Subject: [PATCH 03/20] section.label undefined issue in autocomplete menu --- .../web/internals/template/autocomplete/suggestions.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/frontend/web/internals/template/autocomplete/suggestions.js b/view/frontend/web/internals/template/autocomplete/suggestions.js index 10bf5cfdb..6d4225e3c 100644 --- a/view/frontend/web/internals/template/autocomplete/suggestions.js +++ b/view/frontend/web/internals/template/autocomplete/suggestions.js @@ -4,8 +4,8 @@ define([], function () { return html`

${algoliaConfig.translations.noResults}

`; }, - getHeaderHtml: function ({section}) { - return section.label; + getHeaderHtml: function ({html}) { + return html`

${algoliaConfig.translations.suggestions}

`; }, getItemHtml: function ({item, html}) { From 517105e74939df2a98206c5afaa0e68fa72a9f2a Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Tue, 21 Mar 2023 19:06:24 -0400 Subject: [PATCH 04/20] Apply config setting to limit sources from querySuggestionsPlugin --- view/frontend/web/autocomplete.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/view/frontend/web/autocomplete.js b/view/frontend/web/autocomplete.js index f6a6594ac..e00157c39 100755 --- a/view/frontend/web/autocomplete.js +++ b/view/frontend/web/autocomplete.js @@ -405,6 +405,17 @@ define( transformSource({ source }) { return { ...source, + getItems(arg) { + const getItems = source.getItems(arg); + return { + ...getItems, + transformResponse(res) { + console.log("Cap at:", data.hitsPerPage); + const transformed = getItems.transformResponse(res).slice(0, data.hitsPerPage); + return transformed; + } + } + }, getItemUrl({ item }) { return getNavigatorUrl(algoliaConfig.resultPageUrl+`?q=${item.query}`); }, From b368a53049a36bc9c50ac0f6d3641e224d90d3d6 Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Tue, 21 Mar 2023 19:08:05 -0400 Subject: [PATCH 05/20] Remove log statement --- view/frontend/web/autocomplete.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/view/frontend/web/autocomplete.js b/view/frontend/web/autocomplete.js index e00157c39..7dd28ec8b 100755 --- a/view/frontend/web/autocomplete.js +++ b/view/frontend/web/autocomplete.js @@ -410,9 +410,8 @@ define( return { ...getItems, transformResponse(res) { - console.log("Cap at:", data.hitsPerPage); - const transformed = getItems.transformResponse(res).slice(0, data.hitsPerPage); - return transformed; + // Cap results to algoliaConfig.autocomplete.nbOfQueriesSuggestions + return getItems.transformResponse(res).slice(0, data.hitsPerPage); } } }, From d2267f8360545ddfc95b098b351f82045e6ae733 Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Tue, 21 Mar 2023 20:34:03 -0400 Subject: [PATCH 06/20] Add label for default suggestions header --- view/frontend/web/autocomplete.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/view/frontend/web/autocomplete.js b/view/frontend/web/autocomplete.js index 7dd28ec8b..4476c9128 100755 --- a/view/frontend/web/autocomplete.js +++ b/view/frontend/web/autocomplete.js @@ -280,7 +280,8 @@ define( name: section.name, hitsPerPage: section.hitsPerPage, paramName: suggestions_index, - options + options, + label: section.label }; } else { /** If is not products, categories, pages or suggestions, it's additional section **/ From ce8f82838473cb5590a08ddfdf91029feeb01724 Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Tue, 21 Mar 2023 23:22:10 -0400 Subject: [PATCH 07/20] Clean up formatting --- Helper/Entity/ProductHelper.php | 82 +++++++++++++++++---------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/Helper/Entity/ProductHelper.php b/Helper/Entity/ProductHelper.php index 814f8805a..0214afae2 100755 --- a/Helper/Entity/ProductHelper.php +++ b/Helper/Entity/ProductHelper.php @@ -167,23 +167,24 @@ class ProductHelper * @param ImageHelper $imageHelper */ public function __construct( - Config $eavConfig, - ConfigHelper $configHelper, - AlgoliaHelper $algoliaHelper, - Logger $logger, - StoreManagerInterface $storeManager, - ManagerInterface $eventManager, - Visibility $visibility, - Stock $stockHelper, + Config $eavConfig, + ConfigHelper $configHelper, + AlgoliaHelper $algoliaHelper, + Logger $logger, + StoreManagerInterface $storeManager, + ManagerInterface $eventManager, + Visibility $visibility, + Stock $stockHelper, StockRegistryInterface $stockRegistry, - CurrencyHelper $currencyManager, - CategoryHelper $categoryHelper, - PriceManager $priceManager, - Type $productType, - CollectionFactory $productCollectionFactory, - GroupCollection $groupCollection, - ImageHelper $imageHelper - ) { + CurrencyHelper $currencyManager, + CategoryHelper $categoryHelper, + PriceManager $priceManager, + Type $productType, + CollectionFactory $productCollectionFactory, + GroupCollection $groupCollection, + ImageHelper $imageHelper + ) + { $this->eavConfig = $eavConfig; $this->configHelper = $configHelper; $this->algoliaHelper = $algoliaHelper; @@ -295,7 +296,8 @@ public function getProductCollectionQuery( $productIds = null, $onlyVisible = true, $includeNotVisibleIndividually = false - ) { + ) + { $productCollection = $this->productCollectionFactory->create(); $products = $productCollection ->setStoreId($storeId) @@ -401,12 +403,12 @@ public function setSettings($indexName, $indexNameTmp, $storeId, $saveToTmpIndic $attributesForFaceting = $this->getAttributesForFaceting($storeId); $indexSettings = [ - 'searchableAttributes' => $searchableAttributes, - 'customRanking' => $customRanking, + 'searchableAttributes' => $searchableAttributes, + 'customRanking' => $customRanking, 'unretrievableAttributes' => $unretrievableAttributes, - 'attributesForFaceting' => $attributesForFaceting, - 'maxValuesPerFacet' => (int) $this->configHelper->getMaxValuesPerFacet($storeId), - 'removeWordsIfNoResults' => $this->configHelper->getRemoveWordsIfNoResult($storeId), + 'attributesForFaceting' => $attributesForFaceting, + 'maxValuesPerFacet' => (int)$this->configHelper->getMaxValuesPerFacet($storeId), + 'removeWordsIfNoResults' => $this->configHelper->getRemoveWordsIfNoResult($storeId), ]; // Additional index settings from event observer @@ -419,7 +421,7 @@ public function setSettings($indexName, $indexNameTmp, $storeId, $saveToTmpIndic $this->eventManager->dispatch( 'algolia_products_index_before_set_settings', [ - 'store_id' => $storeId, + 'store_id' => $storeId, 'index_settings' => $transport, ] ); @@ -485,7 +487,7 @@ public function setSettings($indexName, $indexNameTmp, $storeId, $saveToTmpIndic } else { foreach ($sortingIndices as $values) { $replicaName = $values['name']; - array_unshift($customRanking,$values['ranking'][0]); + array_unshift($customRanking, $values['ranking'][0]); $replicaSetting['customRanking'] = $customRanking; $this->algoliaHelper->setSettings($replicaName, $replicaSetting, false, false); $this->logger->log('Setting settings to "' . $replicaName . '" replica.'); @@ -578,12 +580,12 @@ public function getObject(Product $product) ]; $customData = [ - 'objectID' => $product->getId(), - 'name' => $product->getName(), - 'url' => $product->getUrlModel()->getUrl($product, $urlParams), - 'visibility_search' => (int) (in_array($visibility, $visibleInSearch)), - 'visibility_catalog' => (int) (in_array($visibility, $visibleInCatalog)), - 'type_id' => $product->getTypeId(), + 'objectID' => $product->getId(), + 'name' => $product->getName(), + 'url' => $product->getUrlModel()->getUrl($product, $urlParams), + 'visibility_search' => (int)(in_array($visibility, $visibleInSearch)), + 'visibility_catalog' => (int)(in_array($visibility, $visibleInCatalog)), + 'type_id' => $product->getTypeId(), ]; $additionalAttributes = $this->getAdditionalAttributes($product->getStoreId()); @@ -886,7 +888,7 @@ protected function addStockQty($defaultData, $customData, $additionalAttributes, $stockItem = $this->stockRegistry->getStockItem($product->getId()); if ($stockItem) { - $customData['stock_qty'] = (int) $stockItem->getQty(); + $customData['stock_qty'] = (int)$stockItem->getQty(); } } @@ -1065,7 +1067,8 @@ protected function addNonNullValue( Product $product, $attribute, AttributeResource $attributeResource - ) { + ) + { $valueText = null; if (!is_array($value) && $attributeResource->usesSource()) { @@ -1165,7 +1168,7 @@ protected function getAttributesForFaceting($storeId) if ($this->configHelper->isCustomerGroupsEnabled($storeId)) { foreach ($this->groupCollection as $group) { - $group_id = (int) $group->getData('customer_group_id'); + $group_id = (int)$group->getData('customer_group_id'); $attributesForFaceting[] = 'price.' . $currency_code . '.group_' . $group_id; } @@ -1338,10 +1341,10 @@ public function canProductBeReindexed($product, $storeId, $isChildProduct = fals } if ($isChildProduct === false && !in_array($product->getVisibility(), [ - Visibility::VISIBILITY_BOTH, - Visibility::VISIBILITY_IN_SEARCH, - Visibility::VISIBILITY_IN_CATALOG, - ])) { + Visibility::VISIBILITY_BOTH, + Visibility::VISIBILITY_IN_SEARCH, + Visibility::VISIBILITY_IN_CATALOG, + ])) { throw (new ProductNotVisibleException()) ->withProduct($product) ->withStoreId($storeId); @@ -1381,10 +1384,11 @@ public function productIsInStock($product, $storeId) * @param $replica * @return array */ - protected function handleVirtualReplica($replicas, $indexName) { + protected function handleVirtualReplica($replicas, $indexName) + { $virtualReplicaArray = []; foreach ($replicas as $replica) { - $virtualReplicaArray[] = 'virtual('.$replica.')'; + $virtualReplicaArray[] = 'virtual(' . $replica . ')'; } return $virtualReplicaArray; } From 5c235fcff1145458c32a2c758bfb4f0cf0ff939b Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Wed, 22 Mar 2023 09:40:04 -0400 Subject: [PATCH 08/20] Add support to override attribute value uniqueness indexing behaviors --- Helper/Entity/ProductHelper.php | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/Helper/Entity/ProductHelper.php b/Helper/Entity/ProductHelper.php index 0214afae2..09ad43c1c 100755 --- a/Helper/Entity/ProductHelper.php +++ b/Helper/Entity/ProductHelper.php @@ -982,7 +982,7 @@ protected function addNullValue($customData, $subProducts, $attribute, Attribute } if (is_array($values) && count($values) > 0) { - $customData[$attributeName] = array_values(array_unique($values)); + $customData[$attributeName] = $this->getSanitizedArrayValues($values, $attributeName); } if (count($subProductImages) > 0) { @@ -993,12 +993,27 @@ protected function addNullValue($customData, $subProducts, $attribute, Attribute } /** - * @param $valueText - * @param Product $subProduct - * @param AttributeResource $attributeResource + * By default Algolia will remove all redundant attribute values that are fetched from the child simple products. + * + * Overridable via Preference to allow implementer to enforce their own uniqueness rules while leveraging existing indexing code. + * e.g. $values = (in_array($attributeName, self::NON_UNIQUE_ATTRIBUTES)) ? $values : array_unique($values); + * + * @param array $values + * @param string $attributeName + * @return array + */ + protected function getSanitizedArrayValues(array $values, string $attributeName): array + { + return array_values(array_unique($values)); + } + + /** + * @param string|array $valueText - bit of a misnomer - essentially the retrieved values to be indexed for a given product's attribute + * @param Product $subProduct - the simple product to index + * @param AttributeResource $attributeResource - the attribute being indexed * @return array */ - protected function getValues($valueText, Product $subProduct, AttributeResource $attributeResource) + protected function getValues($valueText, Product $subProduct, AttributeResource $attributeResource): array { $values = []; From ed4f25fff7ae949be9160d2704e9b476dbc91450 Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Wed, 22 Mar 2023 11:21:48 -0400 Subject: [PATCH 09/20] Clean up formatting --- view/frontend/web/autocomplete.js | 903 +++++++++++++++--------------- 1 file changed, 454 insertions(+), 449 deletions(-) diff --git a/view/frontend/web/autocomplete.js b/view/frontend/web/autocomplete.js index 4476c9128..6ff41a6fd 100755 --- a/view/frontend/web/autocomplete.js +++ b/view/frontend/web/autocomplete.js @@ -1,522 +1,527 @@ define( ['algoliaBundle', 'pagesHtml', 'categoriesHtml', 'productsHtml', 'suggestionsHtml', 'additionalHtml', 'domReady!'], - function(algoliaBundle, pagesHtml, categoriesHtml, productsHtml, suggestionsHtml, additionalHtml) { + function (algoliaBundle, pagesHtml, categoriesHtml, productsHtml, suggestionsHtml, additionalHtml) { - const DEFAULT_HITS_PER_SECTION = 2; + const DEFAULT_HITS_PER_SECTION = 2; - let suggestionSection = false; - let algoliaFooter; + let suggestionSection = false; + let algoliaFooter; - /** We have nothing to do here if autocomplete is disabled **/ - if (!algoliaConfig.autocomplete.enabled) { - return; - } + /** We have nothing to do here if autocomplete is disabled **/ + if (!algoliaConfig.autocomplete.enabled) { + return; + } - algoliaBundle.$(function ($) { - /** - * Initialise Algolia client - * Docs: https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/ - **/ - const algolia_client = algoliaBundle.algoliasearch(algoliaConfig.applicationId, algoliaConfig.apiKey); - algolia_client.addAlgoliaAgent('Magento2 integration (' + algoliaConfig.extensionVersion + ')'); + algoliaBundle.$(function ($) { + /** + * Initialise Algolia client + * Docs: https://www.algolia.com/doc/api-client/getting-started/instantiate-client-index/ + **/ + const algolia_client = algoliaBundle.algoliasearch(algoliaConfig.applicationId, algoliaConfig.apiKey); + algolia_client.addAlgoliaAgent('Magento2 integration (' + algoliaConfig.extensionVersion + ')'); - const searchClient = algoliaBundle.algoliasearch(algoliaConfig.applicationId, algoliaConfig.apiKey); + const searchClient = algoliaBundle.algoliasearch(algoliaConfig.applicationId, algoliaConfig.apiKey); - // autocomplete code moved from common.js to autocomplete.js - const transformAutocompleteHit = function (hit, price_key, helper) { - if (Array.isArray(hit.categories)) - hit.categories = hit.categories.join(', '); + // autocomplete code moved from common.js to autocomplete.js + const transformAutocompleteHit = function (hit, price_key, helper) { + if (Array.isArray(hit.categories)) + hit.categories = hit.categories.join(', '); - if (hit._highlightResult.categories_without_path && Array.isArray(hit.categories_without_path)) { - hit.categories_without_path = $.map(hit._highlightResult.categories_without_path, function (category) { - return category.value; - }); + if (hit._highlightResult.categories_without_path && Array.isArray(hit.categories_without_path)) { + hit.categories_without_path = $.map(hit._highlightResult.categories_without_path, function (category) { + return category.value; + }); - hit.categories_without_path = hit.categories_without_path.join(', '); - } + hit.categories_without_path = hit.categories_without_path.join(', '); + } - let matchedColors = []; + let matchedColors = []; - // TODO: Adapt this migrated code from common.js - helper not utilized - if (helper && algoliaConfig.useAdaptiveImage === true) { - if (hit.images_data && helper.state.facetsRefinements.color) { - matchedColors = helper.state.facetsRefinements.color.slice(0); // slice to clone - } + // TODO: Adapt this migrated code from common.js - helper not utilized + if (helper && algoliaConfig.useAdaptiveImage === true) { + if (hit.images_data && helper.state.facetsRefinements.color) { + matchedColors = helper.state.facetsRefinements.color.slice(0); // slice to clone + } - if (hit.images_data && helper.state.disjunctiveFacetsRefinements.color) { - matchedColors = helper.state.disjunctiveFacetsRefinements.color.slice(0); // slice to clone + if (hit.images_data && helper.state.disjunctiveFacetsRefinements.color) { + matchedColors = helper.state.disjunctiveFacetsRefinements.color.slice(0); // slice to clone + } } - } - if (Array.isArray(hit.color)) { - let colors = []; + if (Array.isArray(hit.color)) { + let colors = []; - $.each(hit._highlightResult.color, function (i, color) { - if (color.matchLevel === undefined || color.matchLevel === 'none') { - return; - } + $.each(hit._highlightResult.color, function (i, color) { + if (color.matchLevel === undefined || color.matchLevel === 'none') { + return; + } - colors.push(color.value); + colors.push(color.value); - if (algoliaConfig.useAdaptiveImage === true) { - const matchedColor = color.matchedWords.join(' '); - if (hit.images_data && color.fullyHighlighted && color.fullyHighlighted === true) { - matchedColors.push(matchedColor); + if (algoliaConfig.useAdaptiveImage === true) { + const matchedColor = color.matchedWords.join(' '); + if (hit.images_data && color.fullyHighlighted && color.fullyHighlighted === true) { + matchedColors.push(matchedColor); + } } - } - }); + }); - colors = colors.join(', '); - hit._highlightResult.color = { value: colors }; - } - else { - if (hit._highlightResult.color && hit._highlightResult.color.matchLevel === 'none') { - hit._highlightResult.color = { value: '' }; + colors = colors.join(', '); + hit._highlightResult.color = {value: colors}; + } else { + if (hit._highlightResult.color && hit._highlightResult.color.matchLevel === 'none') { + hit._highlightResult.color = {value: ''}; + } } - } - - if (algoliaConfig.useAdaptiveImage === true) { - $.each(matchedColors, function (i, color) { - color = color.toLowerCase(); - if (hit.images_data[color]) { - hit.image_url = hit.images_data[color]; - hit.thumbnail_url = hit.images_data[color]; + if (algoliaConfig.useAdaptiveImage === true) { + $.each(matchedColors, function (i, color) { + color = color.toLowerCase(); - return false; - } - }); - } + if (hit.images_data[color]) { + hit.image_url = hit.images_data[color]; + hit.thumbnail_url = hit.images_data[color]; - if (hit._highlightResult.color && hit._highlightResult.color.value && hit.categories_without_path) { - if (hit.categories_without_path.indexOf('') === -1 && hit._highlightResult.color.value.indexOf('') !== -1) { - hit.categories_without_path = ''; + return false; + } + }); } - } - if (Array.isArray(hit._highlightResult.name)) - hit._highlightResult.name = hit._highlightResult.name[0]; - - if (Array.isArray(hit.price)) { - hit.price = hit.price[0]; - if (hit['price'] !== undefined && price_key !== '.' + algoliaConfig.currencyCode + '.default' && hit['price'][algoliaConfig.currencyCode][price_key.substr(1) + '_formated'] !== hit['price'][algoliaConfig.currencyCode]['default_formated']) { - hit['price'][algoliaConfig.currencyCode][price_key.substr(1) + '_original_formated'] = hit['price'][algoliaConfig.currencyCode]['default_formated']; + if (hit._highlightResult.color && hit._highlightResult.color.value && hit.categories_without_path) { + if (hit.categories_without_path.indexOf('') === -1 && hit._highlightResult.color.value.indexOf('') !== -1) { + hit.categories_without_path = ''; + } } - if (hit['price'][algoliaConfig.currencyCode]['default_original_formated'] - && hit['price'][algoliaConfig.currencyCode]['special_to_date']) { - const priceExpiration = hit['price'][algoliaConfig.currencyCode]['special_to_date']; + if (Array.isArray(hit._highlightResult.name)) + hit._highlightResult.name = hit._highlightResult.name[0]; - if (algoliaConfig.now > priceExpiration + 1) { - hit['price'][algoliaConfig.currencyCode]['default_formated'] = hit['price'][algoliaConfig.currencyCode]['default_original_formated']; - hit['price'][algoliaConfig.currencyCode]['default_original_formated'] = false; + if (Array.isArray(hit.price)) { + hit.price = hit.price[0]; + if (hit['price'] !== undefined && price_key !== '.' + algoliaConfig.currencyCode + '.default' && hit['price'][algoliaConfig.currencyCode][price_key.substr(1) + '_formated'] !== hit['price'][algoliaConfig.currencyCode]['default_formated']) { + hit['price'][algoliaConfig.currencyCode][price_key.substr(1) + '_original_formated'] = hit['price'][algoliaConfig.currencyCode]['default_formated']; } - } - } - // Add to cart parameters - const action = algoliaConfig.instant.addToCartParams.action + 'product/' + hit.objectID + '/'; + if (hit['price'][algoliaConfig.currencyCode]['default_original_formated'] + && hit['price'][algoliaConfig.currencyCode]['special_to_date']) { + const priceExpiration = hit['price'][algoliaConfig.currencyCode]['special_to_date']; - const correctFKey = getCookie('form_key'); + if (algoliaConfig.now > priceExpiration + 1) { + hit['price'][algoliaConfig.currencyCode]['default_formated'] = hit['price'][algoliaConfig.currencyCode]['default_original_formated']; + hit['price'][algoliaConfig.currencyCode]['default_original_formated'] = false; + } + } + } - if(correctFKey != "" && algoliaConfig.instant.addToCartParams.formKey != correctFKey) { - algoliaConfig.instant.addToCartParams.formKey = correctFKey; - } + // Add to cart parameters + const action = algoliaConfig.instant.addToCartParams.action + 'product/' + hit.objectID + '/'; - hit.addToCart = { - 'action': action, - 'uenc': AlgoliaBase64.mageEncode(action), - 'formKey': algoliaConfig.instant.addToCartParams.formKey - }; + const correctFKey = getCookie('form_key'); - if (hit.__autocomplete_queryID) { + if (correctFKey != "" && algoliaConfig.instant.addToCartParams.formKey != correctFKey) { + algoliaConfig.instant.addToCartParams.formKey = correctFKey; + } - hit.urlForInsights = hit.url; + hit.addToCart = { + 'action': action, + 'uenc': AlgoliaBase64.mageEncode(action), + 'formKey': algoliaConfig.instant.addToCartParams.formKey + }; - if (algoliaConfig.ccAnalytics.enabled - && algoliaConfig.ccAnalytics.conversionAnalyticsMode !== 'disabled') { - const insightsDataUrlString = $.param({ - queryID: hit.__autocomplete_queryID, - objectID: hit.objectID, - indexName: hit.__autocomplete_indexName - }); - if (hit.url.indexOf('?') > -1) { - hit.urlForInsights += insightsDataUrlString - } else { - hit.urlForInsights += '?' + insightsDataUrlString; + if (hit.__autocomplete_queryID) { + + hit.urlForInsights = hit.url; + + if (algoliaConfig.ccAnalytics.enabled + && algoliaConfig.ccAnalytics.conversionAnalyticsMode !== 'disabled') { + const insightsDataUrlString = $.param({ + queryID: hit.__autocomplete_queryID, + objectID: hit.objectID, + indexName: hit.__autocomplete_indexName + }); + if (hit.url.indexOf('?') > -1) { + hit.urlForInsights += insightsDataUrlString + } else { + hit.urlForInsights += '?' + insightsDataUrlString; + } } } - } - return hit; - }; - - const getAutocompleteSource = function (section, algolia_client, i) { - let options = { - hitsPerPage: section.hitsPerPage || DEFAULT_HITS_PER_SECTION, - analyticsTags: 'autocomplete', - clickAnalytics: true, - distinct: true + return hit; }; - let source; - - if (section.name === "products") { - options.facets = ['categories.level0']; - options.numericFilters = 'visibility_search=1'; - options.ruleContexts = ['magento_filters', '']; // Empty context to keep backward compatibility for already created rules in dashboard - - options = algolia.triggerHooks('beforeAutocompleteProductSourceOptions', options); - - source = { - name: section.name, - hitsPerPage: section.hitsPerPage, - paramName:algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), - options, - templates: { - noResults({html}) { - return productsHtml.getNoResultHtml({html}); - }, - header({items, html}) { - return productsHtml.getHeaderHtml({items, html}) - }, - item({ item, components, html }) { - if(suggestionSection){ - $('.aa-Panel').addClass('productColumn2'); - $('.aa-Panel').removeClass('productColumn1'); - }else{ - $('.aa-Panel').removeClass('productColumn2'); - $('.aa-Panel').addClass('productColumn1'); - } - if(algoliaFooter && algoliaFooter !== undefined && algoliaFooter !== null && $('#algoliaFooter').length === 0){ - $('.aa-PanelLayout').append(algoliaFooter); - } - const _data = transformAutocompleteHit(item, algoliaConfig.priceKey); - return productsHtml.getItemHtml({ item: _data, components, html }); - }, - footer({items, html}) { - const resultDetails = {}; - if (items.length) { - const firstItem = items[0]; - resultDetails.allDepartmentsUrl = algoliaConfig.resultPageUrl + '?q=' + encodeURIComponent(firstItem.query); - resultDetails.nbHits = firstItem.nbHits; - - if (algoliaConfig.facets.find(facet => facet.attribute === 'categories')) { - let allCategories = []; - if (typeof firstItem.allCategories !== 'undefined') { - allCategories = Object.keys(firstItem.allCategories).map(key => { - const url = resultDetails.allDepartmentsUrl + '&categories=' + encodeURIComponent(key); - return { - name: key, - value: firstItem.allCategories[key], - url - }; - }); + const getAutocompleteSource = function (section, algolia_client, i) { + let options = { + hitsPerPage: section.hitsPerPage || DEFAULT_HITS_PER_SECTION, + analyticsTags: 'autocomplete', + clickAnalytics: true, + distinct: true + }; + + let source; + + if (section.name === "products") { + options.facets = ['categories.level0']; + options.numericFilters = 'visibility_search=1'; + options.ruleContexts = ['magento_filters', '']; // Empty context to keep backward compatibility for already created rules in dashboard + + options = algolia.triggerHooks('beforeAutocompleteProductSourceOptions', options); + + source = { + name: section.name, + hitsPerPage: section.hitsPerPage, + paramName: algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), + options, + templates: { + noResults({html}) { + return productsHtml.getNoResultHtml({html}); + }, + header({items, html}) { + return productsHtml.getHeaderHtml({items, html}) + }, + item({item, components, html}) { + if (suggestionSection) { + $('.aa-Panel').addClass('productColumn2'); + $('.aa-Panel').removeClass('productColumn1'); + } else { + $('.aa-Panel').removeClass('productColumn2'); + $('.aa-Panel').addClass('productColumn1'); + } + if (algoliaFooter && algoliaFooter !== undefined && algoliaFooter !== null && $('#algoliaFooter').length === 0) { + $('.aa-PanelLayout').append(algoliaFooter); + } + const _data = transformAutocompleteHit(item, algoliaConfig.priceKey); + return productsHtml.getItemHtml({item: _data, components, html}); + }, + footer({items, html}) { + const resultDetails = {}; + if (items.length) { + const firstItem = items[0]; + resultDetails.allDepartmentsUrl = algoliaConfig.resultPageUrl + '?q=' + encodeURIComponent(firstItem.query); + resultDetails.nbHits = firstItem.nbHits; + + if (algoliaConfig.facets.find(facet => facet.attribute === 'categories')) { + let allCategories = []; + if (typeof firstItem.allCategories !== 'undefined') { + allCategories = Object.keys(firstItem.allCategories).map(key => { + const url = resultDetails.allDepartmentsUrl + '&categories=' + encodeURIComponent(key); + return { + name: key, + value: firstItem.allCategories[key], + url + }; + }); + } + //reverse value sort apparently... + allCategories.sort((a, b) => b.value - a.value); + resultDetails.allCategories = allCategories.slice(0, 2); } - //reverse value sort apparently... - allCategories.sort((a, b) => b.value - a.value); - resultDetails.allCategories = allCategories.slice(0, 2); } + return productsHtml.getFooterHtml({html, ...resultDetails}); } - return productsHtml.getFooterHtml({ html, ...resultDetails }); } + }; + } else if (section.name === "categories") { + if (section.name === "categories" && algoliaConfig.showCatsNotIncludedInNavigation === false) { + options.numericFilters = 'include_in_menu=1'; } - }; - } - else if (section.name === "categories") - { - if (section.name === "categories" && algoliaConfig.showCatsNotIncludedInNavigation === false) { - options.numericFilters = 'include_in_menu=1'; - } - source = { - name: section.name || i, - hitsPerPage: section.hitsPerPage, - paramName:algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), - options, - templates: { - noResults({html}) { - return categoriesHtml.getNoResultHtml({html}); - }, - header({html, items}) { - return categoriesHtml.getHeaderHtml({section, html, items}); - }, - item({ item, components, html }) { - return categoriesHtml.getItemHtml({item, components, html}); - }, - footer({html, items}) { - return categoriesHtml.getFooterHtml({section, html, items}); + source = { + name: section.name || i, + hitsPerPage: section.hitsPerPage, + paramName: algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), + options, + templates: { + noResults({html}) { + return categoriesHtml.getNoResultHtml({html}); + }, + header({html, items}) { + return categoriesHtml.getHeaderHtml({section, html, items}); + }, + item({item, components, html}) { + return categoriesHtml.getItemHtml({item, components, html}); + }, + footer({html, items}) { + return categoriesHtml.getFooterHtml({section, html, items}); + } } - } - }; - } - else if (section.name === "pages") - { - source = { - name: section.name || i, - hitsPerPage: section.hitsPerPage, - paramName:algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), - options, - templates: { - noResults({html}) { - return pagesHtml.getNoResultHtml({html}); - }, - header({html, items}) { - return pagesHtml.getHeaderHtml({section, html, items}); - }, - item({item, components, html}) { - return pagesHtml.getItemHtml({item, components, html}); - }, - footer({html, items}) { - return pagesHtml.getFooterHtml({section, html, items}); + }; + } else if (section.name === "pages") { + source = { + name: section.name || i, + hitsPerPage: section.hitsPerPage, + paramName: algolia_client.initIndex(algoliaConfig.indexName + "_" + section.name), + options, + templates: { + noResults({html}) { + return pagesHtml.getNoResultHtml({html}); + }, + header({html, items}) { + return pagesHtml.getHeaderHtml({section, html, items}); + }, + item({item, components, html}) { + return pagesHtml.getItemHtml({item, components, html}); + }, + footer({html, items}) { + return pagesHtml.getFooterHtml({section, html, items}); + } } - } - }; - } - else if (section.name === "suggestions") - { - const suggestions_index = algolia_client.initIndex(algoliaConfig.indexName + "_suggestions"); - source = { - displayKey: 'query', - name: section.name, - hitsPerPage: section.hitsPerPage, - paramName: suggestions_index, - options, - label: section.label - }; - } else { - /** If is not products, categories, pages or suggestions, it's additional section **/ - source = { - paramName: algolia_client.initIndex(algoliaConfig.indexName + "_section_" + section.name), - displayKey: 'value', - name: section.name || i, - hitsPerPage: section.hitsPerPage, - options, - templates: { - noResults({html}) { - return additionalHtml.getNoResultHtml({html}); - }, - header({html, items}) { - return additionalHtml.getHeaderHtml({section, html, items}); - }, - item({ item, components, html }) { - return additionalHtml.getItemHtml({item, components, html, section}); - }, - footer({html, items}) { - return additionalHtml.getFooterHtml({section, html, items}); + }; + } else if (section.name === "suggestions") { + const suggestions_index = algolia_client.initIndex(algoliaConfig.indexName + "_suggestions"); + source = { + displayKey: 'query', + name: section.name, + hitsPerPage: section.hitsPerPage, + paramName: suggestions_index, + options, + label: section.label + }; + } else { + /** If is not products, categories, pages or suggestions, it's additional section **/ + source = { + paramName: algolia_client.initIndex(algoliaConfig.indexName + "_section_" + section.name), + displayKey: 'value', + name: section.name || i, + hitsPerPage: section.hitsPerPage, + options, + templates: { + noResults({html}) { + return additionalHtml.getNoResultHtml({html}); + }, + header({html, items}) { + return additionalHtml.getHeaderHtml({section, html, items}); + }, + item({item, components, html}) { + return additionalHtml.getItemHtml({item, components, html, section}); + }, + footer({html, items}) { + return additionalHtml.getFooterHtml({section, html, items}); + } } - } - }; - } + }; + } - return source; - }; + return source; + }; - const getNavigatorUrl = function (url) { - if (algoliaConfig.autocomplete.isNavigatorEnabled) { - return url; + const getNavigatorUrl = function (url) { + if (algoliaConfig.autocomplete.isNavigatorEnabled) { + return url; + } } - } - /** Add products and categories that are required sections **/ - /** Add autocomplete menu sections **/ - if (algoliaConfig.autocomplete.nbOfProductsSuggestions > 0) { - algoliaConfig.autocomplete.sections.unshift({ hitsPerPage: algoliaConfig.autocomplete.nbOfProductsSuggestions, label: algoliaConfig.translations.products, name: "products"}); - } - - if (algoliaConfig.autocomplete.nbOfCategoriesSuggestions > 0) { - algoliaConfig.autocomplete.sections.unshift({ hitsPerPage: algoliaConfig.autocomplete.nbOfCategoriesSuggestions, label: algoliaConfig.translations.categories, name: "categories"}); - } - - if (algoliaConfig.autocomplete.nbOfQueriesSuggestions > 0) { - algoliaConfig.autocomplete.sections.unshift({ hitsPerPage: algoliaConfig.autocomplete.nbOfQueriesSuggestions, label: algoliaConfig.translations.suggestions, name: "suggestions"}); - } - - /** - * Setup the autocomplete search input - * For autocomplete feature is used Algolia's autocomplete.js library - * Docs: https://github.com/algolia/autocomplete.js - **/ - $(algoliaConfig.autocomplete.selector).each(function () { - let querySuggestionsPlugin = ""; - let sources = []; - let autocompleteConfig = []; - let options = { - container: algoliaConfig.autocomplete.selector, - placeholder: algoliaConfig.translations.placeholder, - debug: algoliaConfig.autocomplete.isDebugEnabled, - detachedMediaQuery: 'none', - onSubmit(data){ - if(data.state.query && data.state.query !== null && data.state.query !== ""){ - window.location.href = algoliaConfig.resultPageUrl+`?q=${data.state.query}`; - } - }, - getSources() { - return autocompleteConfig; - }, - }; + /** Add products and categories that are required sections **/ + /** Add autocomplete menu sections **/ + if (algoliaConfig.autocomplete.nbOfProductsSuggestions > 0) { + algoliaConfig.autocomplete.sections.unshift({ + hitsPerPage: algoliaConfig.autocomplete.nbOfProductsSuggestions, + label: algoliaConfig.translations.products, + name: "products" + }); + } - if (isMobile() === true) { - // Set debug to true, to be able to remove keyboard and be able to scroll in autocomplete menu - options.debug = true; + if (algoliaConfig.autocomplete.nbOfCategoriesSuggestions > 0) { + algoliaConfig.autocomplete.sections.unshift({ + hitsPerPage: algoliaConfig.autocomplete.nbOfCategoriesSuggestions, + label: algoliaConfig.translations.categories, + name: "categories" + }); } - if (algoliaConfig.removeBranding === false) { - algoliaFooter = ``; + if (algoliaConfig.autocomplete.nbOfQueriesSuggestions > 0) { + algoliaConfig.autocomplete.sections.unshift({ + hitsPerPage: algoliaConfig.autocomplete.nbOfQueriesSuggestions, + label: algoliaConfig.translations.suggestions, + name: "suggestions" + }); } - sources = algolia.triggerHooks('beforeAutocompleteSources', sources, algolia_client, algoliaBundle); - options = algolia.triggerHooks('beforeAutocompleteOptions', options); + /** + * Setup the autocomplete search input + * For autocomplete feature is used Algolia's autocomplete.js library + * Docs: https://github.com/algolia/autocomplete.js + **/ + $(algoliaConfig.autocomplete.selector).each(function () { + let querySuggestionsPlugin = ""; + let sources = []; + let autocompleteConfig = []; + let options = { + container: algoliaConfig.autocomplete.selector, + placeholder: algoliaConfig.translations.placeholder, + debug: algoliaConfig.autocomplete.isDebugEnabled, + detachedMediaQuery: 'none', + onSubmit(data) { + if (data.state.query && data.state.query !== null && data.state.query !== "") { + window.location.href = algoliaConfig.resultPageUrl + `?q=${data.state.query}`; + } + }, + getSources() { + return autocompleteConfig; + }, + }; - // Keep for backward compatibility - if (typeof algoliaHookBeforeAutocompleteStart === 'function') { - console.warn('Deprecated! You are using an old API for Algolia\'s front end hooks. ' + - 'Please, replace your hook method with new hook API. ' + - 'More information you can find on https://www.algolia.com/doc/integration/magento-2/customize/custom-front-end-events/'); + if (isMobile() === true) { + // Set debug to true, to be able to remove keyboard and be able to scroll in autocomplete menu + options.debug = true; + } - const hookResult = algoliaHookBeforeAutocompleteStart(sources, options, algolia_client); + if (algoliaConfig.removeBranding === false) { + algoliaFooter = ``; + } - sources = hookResult.shift(); - options = hookResult.shift(); - } + sources = algolia.triggerHooks('beforeAutocompleteSources', sources, algolia_client, algoliaBundle); + options = algolia.triggerHooks('beforeAutocompleteOptions', options); - /** Setup autocomplete data sources **/ - let i = 0; - $.each(algoliaConfig.autocomplete.sections, function (...[, section]) { - const source = getAutocompleteSource(section, algolia_client, i); + // Keep for backward compatibility + if (typeof algoliaHookBeforeAutocompleteStart === 'function') { + console.warn('Deprecated! You are using an old API for Algolia\'s front end hooks. ' + + 'Please, replace your hook method with new hook API. ' + + 'More information you can find on https://www.algolia.com/doc/integration/magento-2/customize/custom-front-end-events/'); - if (source) { - sources.push(source); - } + const hookResult = algoliaHookBeforeAutocompleteStart(sources, options, algolia_client); - /** TODO: Review this block - appears to only apply to Autocomplete v0 with Hogan templates which is now unsupported - * e.g. view/frontend/templates/autocomplete/menu.phtml **/ - /** Those sections have already specific placeholder, - * so do not use the default aa-dataset-{i} class to specify the placeholder **/ - if (section.name !== 'suggestions' && section.name !== 'products') { - i++; + sources = hookResult.shift(); + options = hookResult.shift(); } - }); - sources.forEach(function(data){ - if(data.name === "suggestions"){ - suggestionSection = true; - querySuggestionsPlugin = algoliaBundle.createQuerySuggestionsPlugin.createQuerySuggestionsPlugin({ - searchClient, - indexName: data.paramName.indexName, - transformSource({ source }) { - return { - ...source, - getItems(arg) { - const getItems = source.getItems(arg); - return { - ...getItems, - transformResponse(res) { - // Cap results to algoliaConfig.autocomplete.nbOfQueriesSuggestions - return getItems.transformResponse(res).slice(0, data.hitsPerPage); + /** Setup autocomplete data sources **/ + let i = 0; + $.each(algoliaConfig.autocomplete.sections, function (...[, section]) { + const source = getAutocompleteSource(section, algolia_client, i); + + if (source) { + sources.push(source); + } + + /** TODO: Review this block - appears to only apply to Autocomplete v0 with Hogan templates which is now unsupported + * e.g. view/frontend/templates/autocomplete/menu.phtml **/ + /** Those sections have already specific placeholder, + * so do not use the default aa-dataset-{i} class to specify the placeholder **/ + if (section.name !== 'suggestions' && section.name !== 'products') { + i++; + } + }); + + sources.forEach(function (data) { + if (data.name === "suggestions") { + suggestionSection = true; + querySuggestionsPlugin = algoliaBundle.createQuerySuggestionsPlugin.createQuerySuggestionsPlugin({ + searchClient, + indexName: data.paramName.indexName, + transformSource({source}) { + return { + ...source, + getItems(arg) { + const getItems = source.getItems(arg); + return { + ...getItems, + transformResponse(res) { + // Cap results to algoliaConfig.autocomplete.nbOfQueriesSuggestions + return getItems.transformResponse(res).slice(0, data.hitsPerPage); + } } - } - }, - getItemUrl({ item }) { - return getNavigatorUrl(algoliaConfig.resultPageUrl+`?q=${item.query}`); - }, - templates: { - noResults({html}) { - return suggestionsHtml.getNoResultHtml({html}); }, - header({html, items}) { - return suggestionsHtml.getHeaderHtml({section: data, html, items}); + getItemUrl({item}) { + return getNavigatorUrl(algoliaConfig.resultPageUrl + `?q=${item.query}`); }, - item({item, html}) { - return suggestionsHtml.getItemHtml({item, html}) + templates: { + noResults({html}) { + return suggestionsHtml.getNoResultHtml({html}); + }, + header({html, items}) { + return suggestionsHtml.getHeaderHtml({section: data, html, items}); + }, + item({item, html}) { + return suggestionsHtml.getItemHtml({item, html}) + }, + footer({html, items}) { + return suggestionsHtml.getFooterHtml({section: data, html, items}) + }, }, - footer({html, items}) { - return suggestionsHtml.getFooterHtml({section: data, html, items}) - }, - }, - }; - }, - }); - }else if(data.name === "products"){ - autocompleteConfig.unshift({ - sourceId: data.name, - getItemUrl({ item }) { - return getNavigatorUrl(item.url); - }, - getItems({ query }) { - return algoliaBundle.getAlgoliaResults({ - searchClient, - queries: [ - { - indexName: data.paramName.indexName, - query, - params: data.options, + }; + }, + }); + } else if (data.name === "products") { + autocompleteConfig.unshift({ + sourceId: data.name, + getItemUrl({item}) { + return getNavigatorUrl(item.url); + }, + getItems({query}) { + return algoliaBundle.getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: data.paramName.indexName, + query, + params: data.options, + }, + ], + // Stash additional data at item level + transformResponse({results, hits}) { + const resDetail = results[0]; + + return hits.map(res => { + return res.map(hit => { + return { + ...hit, + nbHits: resDetail.nbHits, + allCategories: resDetail.facets['categories.level0'], + query: resDetail.query + } + }) + }); }, - ], - // Stash additional data at item level - transformResponse({ results, hits }) { - const resDetail = results[0]; - - return hits.map(res => { - return res.map(hit => { - return { - ...hit, - nbHits: resDetail.nbHits, - allCategories: resDetail.facets['categories.level0'], - query: resDetail.query - } - }) - }); - }, - }); - }, - templates: data.templates, - }) - }else{ - autocompleteConfig.push({ - sourceId: data.name, - getItemUrl({ item }) { - return getNavigatorUrl(item.url); - }, - getItems({ query }) { - return algoliaBundle.getAlgoliaResults({ - searchClient, - queries: [ - { - indexName: data.paramName.indexName, - query, - params: data.options, + }); + }, + templates: data.templates, + }) + } else { + autocompleteConfig.push({ + sourceId: data.name, + getItemUrl({item}) { + return getNavigatorUrl(item.url); + }, + getItems({query}) { + return algoliaBundle.getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: data.paramName.indexName, + query, + params: data.options, + }, + ], + // Stash additional data at item level + transformResponse({results, hits}) { + const resDetail = results[0]; + + return hits.map(res => { + return res.map(hit => { + return { + ...hit, + query: resDetail.query + } + }) + }); }, - ], - // Stash additional data at item level - transformResponse({ results, hits }) { - const resDetail = results[0]; - - return hits.map(res => { - return res.map(hit => { - return { - ...hit, - query: resDetail.query - } - }) - }); - }, - - }); - }, - templates: data.templates, - }) - } - }); - options.plugins = [querySuggestionsPlugin]; - /** Bind autocomplete feature to the input */ - let algoliaAutocompleteInstance = algoliaBundle.autocomplete(options); - algoliaAutocompleteInstance = algolia.triggerHooks('afterAutocompleteStart', algoliaAutocompleteInstance); + }); + }, + templates: data.templates, + }) + } + }); + + options.plugins = [querySuggestionsPlugin]; + /** Bind autocomplete feature to the input */ + let algoliaAutocompleteInstance = algoliaBundle.autocomplete(options); + algoliaAutocompleteInstance = algolia.triggerHooks('afterAutocompleteStart', algoliaAutocompleteInstance); - //Autocomplete insight click conversion - if (algoliaConfig.ccAnalytics.enabled - && algoliaConfig.ccAnalytics.conversionAnalyticsMode !== 'disabled') { - $(document).on('click', '.algoliasearch-autocomplete-hit', function(){ + //Autocomplete insight click conversion + if (algoliaConfig.ccAnalytics.enabled + && algoliaConfig.ccAnalytics.conversionAnalyticsMode !== 'disabled') { + $(document).on('click', '.algoliasearch-autocomplete-hit', function () { const $this = $(this); if ($this.data('clicked')) return; @@ -529,11 +534,11 @@ define( algoliaInsights.trackClick(eventData); $this.attr('data-clicked', true); }); - } + } - if (algoliaConfig.autocomplete.isNavigatorEnabled) { - $("body").append(''); - } + if (algoliaConfig.autocomplete.isNavigatorEnabled) { + $("body").append(''); + } + }); }); }); -}); From b5923e93a66b82a4c02044e280fe3f6e8bbfd1a9 Mon Sep 17 00:00:00 2001 From: Eric Wright Date: Wed, 22 Mar 2023 11:22:44 -0400 Subject: [PATCH 10/20] Add callback to querySuggestionsPlugin to preclude need to transform results post request for limiting number of results --- view/frontend/web/autocomplete.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/view/frontend/web/autocomplete.js b/view/frontend/web/autocomplete.js index 6ff41a6fd..17f452783 100755 --- a/view/frontend/web/autocomplete.js +++ b/view/frontend/web/autocomplete.js @@ -408,19 +408,14 @@ define( querySuggestionsPlugin = algoliaBundle.createQuerySuggestionsPlugin.createQuerySuggestionsPlugin({ searchClient, indexName: data.paramName.indexName, + getSearchParams() { + return { + hitsPerPage: data.hitsPerPage + } + }, transformSource({source}) { return { ...source, - getItems(arg) { - const getItems = source.getItems(arg); - return { - ...getItems, - transformResponse(res) { - // Cap results to algoliaConfig.autocomplete.nbOfQueriesSuggestions - return getItems.transformResponse(res).slice(0, data.hitsPerPage); - } - } - }, getItemUrl({item}) { return getNavigatorUrl(algoliaConfig.resultPageUrl + `?q=${item.query}`); }, From 2c8cfe19b20c53fbfe3795b1bcc04a9eda429325 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Thu, 23 Mar 2023 14:14:50 +0530 Subject: [PATCH 11/20] Update Bubdle Product Price logic --- Helper/Entity/Product/PriceManager/Bundle.php | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Helper/Entity/Product/PriceManager/Bundle.php b/Helper/Entity/Product/PriceManager/Bundle.php index 1d99d819a..aa65c5828 100644 --- a/Helper/Entity/Product/PriceManager/Bundle.php +++ b/Helper/Entity/Product/PriceManager/Bundle.php @@ -19,13 +19,14 @@ class Bundle extends ProductWithChildren */ protected function addAdditionalData($product, $withTax, $subProducts, $currencyCode, $field) { $data = $this->getMinMaxPrices($product, $withTax, $subProducts, $currencyCode); - $dashedFormat = $this->getDashedPriceFormat($data['min_price'], $data['max'], $currencyCode); - if ($data['min_price'] !== $data['max']) { - $this->handleBundleNonEqualMinMaxPrices($field, $currencyCode, $data['min_price'], $data['max'], $dashedFormat); + $dashedFormat = $this->getDashedPriceFormat($data['min_price'], $data['max_price'], $currencyCode); + if ($data['min_price'] !== $data['max_price']) { + $this->handleBundleNonEqualMinMaxPrices($field, $currencyCode, $data['min_price'], $data['max_price'], $dashedFormat); } - $this->handleOriginalPrice($field, $currencyCode, $data['min_price'], $data['max'], $data['min_original'], $data['max_original']); + + $this->handleOriginalPrice($field, $currencyCode, $data['min_price'], $data['max_price'], $data['min_original'], $data['max_original']); if (!$this->customData[$field][$currencyCode]['default']) { - $this->handleZeroDefaultPrice($field, $currencyCode, $data['min_price'], $data['max']); + $this->handleZeroDefaultPrice($field, $currencyCode, $data['min_price'], $data['max_price']); } if ($this->areCustomersGroupsEnabled) { $groupedDashedFormat = $this->getBundleDashedPriceFormat($data['min'], $data['max'], $currencyCode); @@ -42,7 +43,7 @@ protected function addAdditionalData($product, $withTax, $subProducts, $currency */ protected function getMinMaxPrices(Product $product, $withTax, $subProducts, $currencyCode) { - $regularPrice = $product->getPriceInfo()->getPrice('regular_price')->getMinimalPrice()->getValue(); + $product->setData('website_id', $product->getStore()->getWebsiteId()); $minPrice = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getValue(); $minOriginalPrice = $product->getPriceInfo()->getPrice('regular_price')->getMinimalPrice()->getValue(); $maxOriginalPrice = $product->getPriceInfo()->getPrice('regular_price')->getMaximalPrice()->getValue(); @@ -50,17 +51,20 @@ protected function getMinMaxPrices(Product $product, $withTax, $subProducts, $cu $minArray = []; foreach ($this->groups as $group) { $groupId = (int) $group->getData('customer_group_id'); - foreach ($subProducts as $subProduct) { - $subProduct->setData('customer_group_id', $groupId); - $subProductFinalPrice = $this->getTaxPrice($product, $subProduct->getPriceModel()->getFinalPrice(1, $subProduct), $withTax); - $priceDiff = $subProduct->getPrice() - $subProductFinalPrice; - $minArray[$groupId][] = $regularPrice - $priceDiff; - } + $product->setData('customer_group_id', $groupId); + $minPrice = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getValue(); + $minArray[$groupId] = $product->getPriceInfo()->getPrice('final_price')->getMinimalPrice()->getValue(); + $maxArray[$groupId] = $product->getPriceInfo()->getPrice('final_price')->getMaximalPrice()->getValue(); + $product->setData('customer_group_id', null); } $minPriceArray = []; foreach ($minArray as $groupId => $min) { - $minPriceArray[$groupId] = min($min); + $minPriceArray[$groupId] = $min; + } + $maxPriceArray = []; + foreach ($maxArray as $groupId => $max) { + $maxPriceArray[$groupId] = $max; } if ($currencyCode !== $this->baseCurrencyCode) { @@ -70,15 +74,15 @@ protected function getMinMaxPrices(Product $product, $withTax, $subProducts, $cu foreach ($minPriceArray as $groupId => $price) { $minPriceArray[$groupId] = $this->convertPrice($price, $currencyCode); } - if ($min !== $max) { + if ($minPrice !== $max) { $max = $this->convertPrice($max, $currencyCode); } } - return [ 'min' => $minPriceArray, - 'max' => $max, + 'max' => $maxPriceArray, 'min_price' => $minPrice, + 'max_price' => $max, 'min_original' => $minOriginalPrice, 'max_original' => $maxOriginalPrice ]; @@ -117,10 +121,10 @@ protected function handleBundleNonEqualMinMaxPrices($field, $currencyCode, $min, protected function getBundleDashedPriceFormat($minPrices, $max, $currencyCode) { $dashedFormatPrice = []; foreach ($minPrices as $groupId => $min) { - if ($min === $max) { + if ($min === $max[$groupId]) { $dashedFormatPrice [$groupId] = ''; } - $dashedFormatPrice[$groupId] = $this->formatPrice($min, $currencyCode) . ' - ' . $this->formatPrice($max, $currencyCode); + $dashedFormatPrice[$groupId] = $this->formatPrice($min, $currencyCode) . ' - ' . $this->formatPrice($max[$groupId], $currencyCode); } return $dashedFormatPrice; } @@ -139,7 +143,7 @@ protected function setFinalGroupPricesBundle($field, $currencyCode, $min, $max, foreach ($this->groups as $group) { $groupId = (int) $group->getData('customer_group_id'); $this->customData[$field][$currencyCode]['group_' . $groupId] = $min[$groupId]; - if ($min === $max) { + if ($min[$groupId] === $max[$groupId]) { $this->customData[$field][$currencyCode]['group_' . $groupId . '_formated'] = $this->customData[$field][$currencyCode]['default_formated']; } else { @@ -147,4 +151,4 @@ protected function setFinalGroupPricesBundle($field, $currencyCode, $min, $max, } } } -} +} \ No newline at end of file From 5fb81ec8e5e4a65d93a949a0d4d275f943ed47b9 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Thu, 23 Mar 2023 14:24:57 +0530 Subject: [PATCH 12/20] Update Bundle Product Price logic --- Helper/Entity/Product/PriceManager/Bundle.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Helper/Entity/Product/PriceManager/Bundle.php b/Helper/Entity/Product/PriceManager/Bundle.php index aa65c5828..99d023fe2 100644 --- a/Helper/Entity/Product/PriceManager/Bundle.php +++ b/Helper/Entity/Product/PriceManager/Bundle.php @@ -49,6 +49,7 @@ protected function getMinMaxPrices(Product $product, $withTax, $subProducts, $cu $maxOriginalPrice = $product->getPriceInfo()->getPrice('regular_price')->getMaximalPrice()->getValue(); $max = $product->getPriceInfo()->getPrice('final_price')->getMaximalPrice()->getValue(); $minArray = []; + $maxArray = []; foreach ($this->groups as $group) { $groupId = (int) $group->getData('customer_group_id'); $product->setData('customer_group_id', $groupId); From e2849e72e8241a21fdb1cd044ae4f153cdccb667 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Mon, 27 Mar 2023 17:42:05 +0530 Subject: [PATCH 13/20] Removed Blank space from instant search page --- view/frontend/web/internals/instantsearch.v3.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/view/frontend/web/internals/instantsearch.v3.css b/view/frontend/web/internals/instantsearch.v3.css index cd08e5d0d..d789fe53d 100644 --- a/view/frontend/web/internals/instantsearch.v3.css +++ b/view/frontend/web/internals/instantsearch.v3.css @@ -70,8 +70,6 @@ input.ais-SearchBox-input { .ais-InfiniteHits, .ais-Hits { text-align: center; - padding-top: 30px; - padding-bottom: 30px; } .ais-InfiniteHits--empty, @@ -244,12 +242,13 @@ input.ais-SearchBox-input { /* Pagination */ .ais-Pagination-list { - margin: 2em 0; + margin: 1em 0; justify-content: center; } .ais-Pagination-item { padding: 1em; + margin-bottom: 0rem; } .ais-Pagination-item--selected { From d251407f1ab66dfa0e72a4e741063aea6c8c14f5 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Tue, 28 Mar 2023 17:19:51 +0530 Subject: [PATCH 14/20] Updated comment for non castable attributes --- etc/adminhtml/system.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml index 2c27234ae..6fbb41d99 100755 --- a/etc/adminhtml/system.xml +++ b/etc/adminhtml/system.xml @@ -1130,7 +1130,7 @@ Magento\Config\Model\Config\Backend\Serialized\ArraySerialized From c6ba7612c4da08181b514435d85b14fb3f70a305 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Fri, 31 Mar 2023 16:47:37 +0530 Subject: [PATCH 15/20] Fixed issue with wrong routing if searchBox is disable for search page --- view/frontend/web/internals/common.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/view/frontend/web/internals/common.js b/view/frontend/web/internals/common.js index 3b93b988e..e0b1913f0 100755 --- a/view/frontend/web/internals/common.js +++ b/view/frontend/web/internals/common.js @@ -338,8 +338,10 @@ requirejs(['algoliaBundle'], function(algoliaBundle) { var routeParameters = {}; if (algoliaConfig.isCategoryPage) { routeParameters['q'] = uiState[productIndexName].query; - } else { - routeParameters['q'] = uiState[productIndexName].query || '__empty__'; + } else if (algoliaConfig.isLandingPage){ + routeParameters['q'] = uiState[productIndexName].query || algoliaConfig.landingPage.query || '__empty__'; + } else{ + routeParameters['q'] = uiState[productIndexName].query || algoliaConfig.request.query || '__empty__'; } if (algoliaConfig.facets) { for(var i=0; i Date: Fri, 31 Mar 2023 20:11:45 +0530 Subject: [PATCH 16/20] Fixed the Landing page save issue --- Controller/Adminhtml/Landingpage/Save.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/Adminhtml/Landingpage/Save.php b/Controller/Adminhtml/Landingpage/Save.php index d22593352..f117bd864 100644 --- a/Controller/Adminhtml/Landingpage/Save.php +++ b/Controller/Adminhtml/Landingpage/Save.php @@ -99,7 +99,7 @@ public function execute() if (isset($data['algolia_configuration']) && $data['algolia_configuration'] != $data['configuration']) { $data['configuration'] = $data['algolia_configuration']; - if ($this->configHelper->isCustomerGroupsEnabled($data['store_id'])) { + if ($this->configHelper->isCustomerGroupsEnabled($data['store_id']) && isset($configuration['price'.$data['price_key']])) { $configuration = json_decode($data['algolia_configuration'], true); $priceConfig = $configuration['price'.$data['price_key']]; $customerGroups = $this->customerGroupCollectionFactory->create(); From 081d18a2f1aad23e7667a8598e1a21e805ff2bb6 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Tue, 4 Apr 2023 17:30:32 +0530 Subject: [PATCH 17/20] Updated release notes for 3.10.2 --- CHANGELOG.md | 18 ++++++++++++++++++ README.md | 2 +- composer.json | 2 +- etc/module.xml | 2 +- 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c4dce0c5..2db7396ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,23 @@ # CHANGE LOG +## 3.10.2 + +### UPDATES +- Ensured compatibility of the extension with Magento 2.4.6 +- Updated the code to allow for convenient customization of object serialization +- Updated comment for non-castable attribute in system configuration +- Code has added to address the problem with bundle product pricing when the value of the dynamic price attribute is disabled. +- Updated a function to include the userToken and enablePersonalization tag in the search request being sent + + +### Bug Fixes +- Resolved the issue of section.label in autocomplete +- Fixed the issue of nbOfQuerySuggestions in autocomplete +- Fixed the routing error if searchBox is disable for instant search page +- Resolved the deployment issue related to prefixing Magento database tables +- Fixed the landing page save issue if price filter is not selected in price filter +- Fixed the spacing issue in instant search page for pagination + ## 3.10.1 ### UPDATES diff --git a/README.md b/README.md index 7117a6888..0dc90bda0 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Algolia Search for Magento 2 ================== -![Latest version](https://img.shields.io/badge/latest-3.10.1-green) +![Latest version](https://img.shields.io/badge/latest-3.10.2-green) ![Magento 2](https://img.shields.io/badge/Magento-2.4.x-orange) ![PHP](https://img.shields.io/badge/PHP-8.1,7.4-blue) diff --git a/composer.json b/composer.json index 1ab8d835d..0a758a8b8 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,7 @@ "description": "Algolia Search integration for Magento 2", "type": "magento2-module", "license": ["MIT"], - "version": "3.10.1", + "version": "3.10.2", "require": { "magento/framework": "~102.0|~103.0", "algolia/algoliasearch-client-php": "3.2", diff --git a/etc/module.xml b/etc/module.xml index 395312434..2615c19a4 100755 --- a/etc/module.xml +++ b/etc/module.xml @@ -1,6 +1,6 @@ - + From 9864ee5ccb01edb84d5076d61b2052f28f9886ee Mon Sep 17 00:00:00 2001 From: mohitalgolia <101385480+mohitalgolia@users.noreply.github.com> Date: Tue, 4 Apr 2023 20:34:52 +0530 Subject: [PATCH 18/20] Revert "Fixed the Landing page save issue" --- Controller/Adminhtml/Landingpage/Save.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Controller/Adminhtml/Landingpage/Save.php b/Controller/Adminhtml/Landingpage/Save.php index f117bd864..d22593352 100644 --- a/Controller/Adminhtml/Landingpage/Save.php +++ b/Controller/Adminhtml/Landingpage/Save.php @@ -99,7 +99,7 @@ public function execute() if (isset($data['algolia_configuration']) && $data['algolia_configuration'] != $data['configuration']) { $data['configuration'] = $data['algolia_configuration']; - if ($this->configHelper->isCustomerGroupsEnabled($data['store_id']) && isset($configuration['price'.$data['price_key']])) { + if ($this->configHelper->isCustomerGroupsEnabled($data['store_id'])) { $configuration = json_decode($data['algolia_configuration'], true); $priceConfig = $configuration['price'.$data['price_key']]; $customerGroups = $this->customerGroupCollectionFactory->create(); From 287588b28f6be2b4930f8684676fa1f16284e532 Mon Sep 17 00:00:00 2001 From: Mohit Choudhary Date: Tue, 4 Apr 2023 20:38:19 +0530 Subject: [PATCH 19/20] Updated Changelog --- CHANGELOG.md | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db7396ff..6ea5ad5bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,18 +5,19 @@ ### UPDATES - Ensured compatibility of the extension with Magento 2.4.6 - Updated the code to allow for convenient customization of object serialization -- Updated comment for non-castable attribute in system configuration -- Code has added to address the problem with bundle product pricing when the value of the dynamic price attribute is disabled. -- Updated a function to include the userToken and enablePersonalization tag in the search request being sent +- Enhanced comments for non-castable attributes in system configuration +- Added new code to resolve pricing issues with bundle products when the dynamic price attribute is disabled +- Updated autocomplete to include userToken and enablePersonalization tag in search requests + ### Bug Fixes -- Resolved the issue of section.label in autocomplete -- Fixed the issue of nbOfQuerySuggestions in autocomplete -- Fixed the routing error if searchBox is disable for instant search page -- Resolved the deployment issue related to prefixing Magento database tables -- Fixed the landing page save issue if price filter is not selected in price filter -- Fixed the spacing issue in instant search page for pagination +- Fixed issue with section.label in autocomplete +- Resolved issue with nbOfQuerySuggestions in autocomplete +- Fixed routing error related to disabling searchBox for instant search page +- Resolved deployment issue with prefixed Magento database tables +- Fixed spacing issue with pagination on instant search page + ## 3.10.1 From 5fc605bc13e737190999581b9ad5386ac27f7526 Mon Sep 17 00:00:00 2001 From: mohitalgolia <101385480+mohitalgolia@users.noreply.github.com> Date: Tue, 4 Apr 2023 21:09:57 +0530 Subject: [PATCH 20/20] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ea5ad5bb..14f676a49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ - Ensured compatibility of the extension with Magento 2.4.6 - Updated the code to allow for convenient customization of object serialization - Enhanced comments for non-castable attributes in system configuration -- Added new code to resolve pricing issues with bundle products when the dynamic price attribute is disabled +- Updated the code to ensure that accurate prices are indexed for bundle products when the dynamic price attribute is turned off - Updated autocomplete to include userToken and enablePersonalization tag in search requests