Skip to content

Commit adfa7e8

Browse files
authored
Merge pull request #1680 from algolia/release/3.13.7-dev
Release/3.13.7 dev
2 parents 515bf3d + c388e0c commit adfa7e8

File tree

16 files changed

+517
-50
lines changed

16 files changed

+517
-50
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
# CHANGE LOG
22

3+
## 3.13.7
4+
5+
### Features
6+
- Added a feature to enable automatic price indexing on the Advanced section of the configuration (This feature should help alleviate issues where missing pricing records prevent Algolia from being able to index products.)
7+
8+
### Updates
9+
- Updated `getCookie` method to make it more consistent
10+
- Removed dependency to `catalog_product_price` indexer
11+
12+
### Bug Fixes
13+
- Fixed a bug where the Landing Page Builder was crashing on save with customer group pricing was enabled.
14+
- Fixed issue where Insights information wasn't kept on the url after clicking "add to cart" on PLP powered by InstantSearch
15+
316
## 3.13.6
417

518
### Bug Fixes

Controller/Adminhtml/Landingpage/Save.php

+9-7
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,15 @@ public function execute()
107107
$data['configuration'] = $data['algolia_configuration'];
108108
if ($this->configHelper->isCustomerGroupsEnabled($data['store_id'])) {
109109
$configuration = json_decode($data['algolia_configuration'], true);
110-
$priceConfig = $configuration['price'.$data['price_key']];
111-
$customerGroups = $this->customerGroupCollectionFactory->create();
112-
$store = $this->storeManager->getStore($data['store_id']);
113-
$baseCurrencyCode = $store->getBaseCurrencyCode();
114-
foreach ($customerGroups as $group) {
115-
$groupId = (int) $group->getData('customer_group_id');
116-
$configuration['price.'.$baseCurrencyCode.'.group_'.$groupId] = $priceConfig;
110+
if (isset($configuration['price'.$data['price_key']])) {
111+
$priceConfig = $configuration['price' . $data['price_key']];
112+
$customerGroups = $this->customerGroupCollectionFactory->create();
113+
$store = $this->storeManager->getStore($data['store_id']);
114+
$baseCurrencyCode = $store->getBaseCurrencyCode();
115+
foreach ($customerGroups as $group) {
116+
$groupId = (int)$group->getData('customer_group_id');
117+
$configuration['price.' . $baseCurrencyCode . '.group_' . $groupId] = $priceConfig;
118+
}
117119
}
118120
$data['configuration'] = json_encode($configuration);
119121
}

Helper/ConfigHelper.php

+10
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ class ConfigHelper
106106
public const CONNECTION_TIMEOUT = 'algoliasearch_advanced/advanced/connection_timeout';
107107
public const READ_TIMEOUT = 'algoliasearch_advanced/advanced/read_timeout';
108108
public const WRITE_TIMEOUT = 'algoliasearch_advanced/advanced/write_timeout';
109+
public const AUTO_PRICE_INDEXING_ENABLED = 'algoliasearch_advanced/advanced/auto_price_indexing';
109110

110111
public const SHOW_OUT_OF_STOCK = 'cataloginventory/options/show_out_of_stock';
111112

@@ -1222,6 +1223,15 @@ public function getWriteTimeout($storeId = null)
12221223
return $this->configInterface->getValue(self::WRITE_TIMEOUT, ScopeInterface::SCOPE_STORE, $storeId);
12231224
}
12241225

1226+
public function isAutoPriceIndexingEnabled(?int $storeId = null): bool
1227+
{
1228+
return $this->configInterface->isSetFlag(
1229+
self::AUTO_PRICE_INDEXING_ENABLED,
1230+
ScopeInterface::SCOPE_STORE,
1231+
$storeId
1232+
);
1233+
}
1234+
12251235
/**
12261236
* @param $storeId
12271237
* @return array|bool|float|int|mixed|string

Helper/Data.php

+27-30
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Algolia\AlgoliaSearch\Helper\Entity\PageHelper;
1010
use Algolia\AlgoliaSearch\Helper\Entity\ProductHelper;
1111
use Algolia\AlgoliaSearch\Helper\Entity\SuggestionHelper;
12+
use Algolia\AlgoliaSearch\Service\Product\MissingPriceIndexHandler;
1213
use Magento\Catalog\Model\Category;
1314
use Magento\Catalog\Model\Product;
1415
use Magento\Catalog\Model\ResourceModel\Product\Collection;
@@ -76,6 +77,11 @@ class Data
7677
*/
7778
protected $storeManager;
7879

80+
/**
81+
* @var MissingPriceIndexHandler
82+
*/
83+
protected $missingPriceIndexHandler;
84+
7985
protected $emulationRuns = false;
8086

8187
/** @var \Magento\Framework\Indexer\IndexerInterface */
@@ -98,20 +104,21 @@ class Data
98104
* @param StoreManagerInterface $storeManager
99105
*/
100106
public function __construct(
101-
AlgoliaHelper $algoliaHelper,
102-
ConfigHelper $configHelper,
103-
ProductHelper $producthelper,
104-
CategoryHelper $categoryHelper,
105-
PageHelper $pageHelper,
106-
SuggestionHelper $suggestionHelper,
107-
AdditionalSectionHelper $additionalSectionHelper,
108-
Emulation $emulation,
109-
Logger $logger,
110-
ResourceConnection $resource,
111-
ManagerInterface $eventManager,
112-
ScopeCodeResolver $scopeCodeResolver,
113-
StoreManagerInterface $storeManager,
114-
IndexerRegistry $indexerRegistry
107+
AlgoliaHelper $algoliaHelper,
108+
ConfigHelper $configHelper,
109+
ProductHelper $producthelper,
110+
CategoryHelper $categoryHelper,
111+
PageHelper $pageHelper,
112+
SuggestionHelper $suggestionHelper,
113+
AdditionalSectionHelper $additionalSectionHelper,
114+
Emulation $emulation,
115+
Logger $logger,
116+
ResourceConnection $resource,
117+
ManagerInterface $eventManager,
118+
ScopeCodeResolver $scopeCodeResolver,
119+
StoreManagerInterface $storeManager,
120+
MissingPriceIndexHandler $missingPriceIndexHandler,
121+
IndexerRegistry $indexerRegistry
115122

116123
)
117124
{
@@ -128,6 +135,7 @@ public function __construct(
128135
$this->eventManager = $eventManager;
129136
$this->scopeCodeResolver = $scopeCodeResolver;
130137
$this->storeManager = $storeManager;
138+
$this->missingPriceIndexHandler = $missingPriceIndexHandler;
131139

132140
$this->priceIndexer = $indexerRegistry->get('catalog_product_price');
133141
}
@@ -421,8 +429,6 @@ public function rebuildStoreProductIndex($storeId, $productIds)
421429
return;
422430
}
423431

424-
$this->checkPriceIndex($productIds);
425-
426432
$this->startEmulation($storeId);
427433
$this->logger->start('Indexing');
428434
try {
@@ -753,6 +759,11 @@ public function rebuildStoreProductIndexPage(
753759
'store' => $storeId
754760
]
755761
);
762+
763+
if ($this->configHelper->isAutoPriceIndexingEnabled($storeId)) {
764+
$this->missingPriceIndexHandler->refreshPriceIndex($collection);
765+
}
766+
756767
$logMessage = 'LOADING: ' . $this->logger->getStoreName($storeId) . ',
757768
collection page: ' . $page . ',
758769
pageSize: ' . $pageSize;
@@ -973,18 +984,4 @@ protected function deleteInactiveIds($storeId, $objectIds, $indexName)
973984
$idsToDeleteFromAlgolia = array_diff($objectIds, $dbIds);
974985
$this->algoliaHelper->deleteObjects($idsToDeleteFromAlgolia, $indexName);
975986
}
976-
977-
/**
978-
* If the price index is stale
979-
* @param array $productIds
980-
* @return void
981-
*/
982-
protected function checkPriceIndex(array $productIds): void
983-
{
984-
$state = $this->priceIndexer->getState()->getStatus();
985-
if ($state === \Magento\Framework\Indexer\StateInterface::STATUS_INVALID) {
986-
$this->priceIndexer->reindexList($productIds);
987-
}
988-
}
989-
990987
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Model\Config;
4+
5+
use Magento\Config\Model\Config\CommentInterface;
6+
use Magento\Framework\UrlInterface;
7+
8+
class AutomaticPriceIndexingComment implements CommentInterface
9+
{
10+
public function __construct(
11+
protected UrlInterface $urlInterface
12+
) { }
13+
14+
public function getCommentText($elementValue)
15+
{
16+
$url = $this->urlInterface->getUrl('https://www.algolia.com/doc/integration/magento-2/how-it-works/indexing-queue/#configure-the-queue');
17+
18+
$comment = array();
19+
$comment[] = 'Algolia relies on the core Magento Product Price index when serializing product data. If the price index is not up to date, Algolia will not be able to accurately determine what should be included in the search index.';
20+
$comment[] = 'If you are experiencing problems with products not syncing to Algolia due to this issue, enabling this setting will allow Algolia to automatically update the price index as needed.';
21+
$comment[] = 'NOTE: This can introduce a marginal amount of overhead to the indexing process so only enable if necessary. Be sure to <a href="' . $url . '" target="_blank">optimize the indexing queue</a> based on the impact of this operation.';
22+
return implode('<br><br>', $comment);
23+
}
24+
}
+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
<?php
2+
3+
namespace Algolia\AlgoliaSearch\Plugin;
4+
5+
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
6+
use Magento\Catalog\Api\ProductRepositoryInterface;
7+
use Magento\Catalog\Model\Product;
8+
use Magento\CatalogInventory\Api\StockRegistryInterface;
9+
use Magento\Checkout\Model\Cart;
10+
use Magento\Checkout\Model\Cart\RequestInfoFilterInterface;
11+
use Magento\Checkout\Model\Session;
12+
use Magento\Framework\DataObject;
13+
use Magento\Framework\Event\ManagerInterface;
14+
use Magento\Framework\Exception\LocalizedException;
15+
use Magento\Framework\Exception\NoSuchEntityException;
16+
use Magento\Store\Model\StoreManagerInterface;
17+
18+
class AddToCartRedirectForInsights
19+
{
20+
/**
21+
* @var RequestInfoFilterInterface
22+
*/
23+
private $requestInfoFilter;
24+
25+
public function __construct(
26+
protected StoreManagerInterface $storeManager,
27+
protected ProductRepositoryInterface $productRepository,
28+
protected Session $checkoutSession,
29+
protected StockRegistryInterface $stockRegistry,
30+
protected ManagerInterface $eventManager,
31+
protected ConfigHelper $configHelper,
32+
) {}
33+
34+
/**
35+
* @param Cart $cartModel
36+
* @param int|Product $productInfo
37+
* @param array|int|DataObject|null $requestInfo
38+
*
39+
* @return null
40+
*
41+
* @throws LocalizedException
42+
* @throws NoSuchEntityException
43+
*/
44+
public function beforeAddProduct(Cart $cartModel, int|Product $productInfo, array|int|DataObject $requestInfo = null)
45+
{
46+
// First, check is Insights are enabled
47+
if (!$this->configHelper->isClickConversionAnalyticsEnabled($this->storeManager->getStore()->getId())) {
48+
return;
49+
}
50+
51+
// If the request doesn't have any insights info, no need to handle it
52+
if (!isset($requestInfo['referer']) || !isset($requestInfo['queryID']) || !isset($requestInfo['indexName'])) {
53+
return;
54+
}
55+
56+
// Check if the request comes from the PLP handled by InstantSearch
57+
if ($requestInfo['referer'] != 'instantsearch') {
58+
return;
59+
}
60+
61+
$product = $this->getProduct($productInfo);
62+
$productId = $product->getId();
63+
64+
if ($productId) {
65+
$request = $this->getQtyRequest($product, $requestInfo);
66+
67+
try {
68+
$result = $product->getTypeInstance()->prepareForCartAdvanced($request, $product);
69+
} catch (LocalizedException $e) {
70+
$this->checkoutSession->setUseNotice(false);
71+
$result = $e->getMessage();
72+
}
73+
74+
// if the result is a string, this mean that the product can't be added to the cart
75+
// see Magento\Quote\Model\Quote::addProduct()
76+
// Here we need to add the insights information to the redirect
77+
if (is_string($result)) {
78+
$redirectUrl = $product->getUrlModel()->getUrl(
79+
$product,
80+
[
81+
'_query' => [
82+
'objectID' => $product->getId(),
83+
'queryID' => $requestInfo['queryID'],
84+
'indexName' => $requestInfo['indexName']
85+
]
86+
]
87+
);
88+
89+
$this->checkoutSession->setRedirectUrl($redirectUrl);
90+
if ($this->checkoutSession->getUseNotice() === null) {
91+
$this->checkoutSession->setUseNotice(true);
92+
}
93+
throw new LocalizedException(__($result));
94+
}
95+
}
96+
}
97+
98+
/**
99+
* @param $productInfo
100+
*
101+
* @return Product
102+
*
103+
* @throws NoSuchEntityException
104+
* @throws LocalizedException
105+
*/
106+
protected function getProduct($productInfo): Product
107+
{
108+
$product = null;
109+
if ($productInfo instanceof Product) {
110+
$product = $productInfo;
111+
if (!$product->getId()) {
112+
throw new LocalizedException(
113+
__("The product wasn't found. Verify the product and try again.")
114+
);
115+
}
116+
} elseif (is_int($productInfo) || is_string($productInfo)) {
117+
$storeId = $this->storeManager->getStore()->getId();
118+
try {
119+
$product = $this->productRepository->getById($productInfo, false, $storeId);
120+
} catch (NoSuchEntityException $e) {
121+
throw new LocalizedException(
122+
__("The product wasn't found. Verify the product and try again."),
123+
$e
124+
);
125+
}
126+
} else {
127+
throw new LocalizedException(
128+
__("The product wasn't found. Verify the product and try again.")
129+
);
130+
}
131+
$currentWebsiteId = $this->storeManager->getStore()->getWebsiteId();
132+
if (!is_array($product->getWebsiteIds()) || !in_array($currentWebsiteId, $product->getWebsiteIds())) {
133+
throw new LocalizedException(
134+
__("The product wasn't found. Verify the product and try again.")
135+
);
136+
}
137+
return $product;
138+
}
139+
140+
/**
141+
* Get request quantity
142+
*
143+
* @param Product $product
144+
* @param DataObject|int|array $request
145+
* @return int|DataObject
146+
*/
147+
protected function getQtyRequest($product, $request = 0)
148+
{
149+
$request = $this->getProductRequest($request);
150+
$stockItem = $this->stockRegistry->getStockItem($product->getId(), $product->getStore()->getWebsiteId());
151+
$minimumQty = $stockItem->getMinSaleQty();
152+
//If product quantity is not specified in request and there is set minimal qty for it
153+
if ($minimumQty
154+
&& $minimumQty > 0
155+
&& !$request->getQty()
156+
) {
157+
$request->setQty($minimumQty);
158+
}
159+
160+
return $request;
161+
}
162+
163+
/**
164+
* Get request for product add to cart procedure
165+
*
166+
* @param DataObject|int|array $requestInfo
167+
* @return DataObject
168+
* @throws LocalizedException
169+
*/
170+
protected function getProductRequest($requestInfo)
171+
{
172+
if ($requestInfo instanceof DataObject) {
173+
$request = $requestInfo;
174+
} elseif (is_numeric($requestInfo)) {
175+
$request = new DataObject(['qty' => $requestInfo]);
176+
} elseif (is_array($requestInfo)) {
177+
$request = new DataObject($requestInfo);
178+
} else {
179+
throw new LocalizedException(
180+
__('We found an invalid request for adding product to quote.')
181+
);
182+
}
183+
$this->getRequestInfoFilter()->filter($request);
184+
185+
return $request;
186+
}
187+
188+
/**
189+
* Getter for RequestInfoFilter
190+
*
191+
* @return RequestInfoFilterInterface
192+
*/
193+
protected function getRequestInfoFilter()
194+
{
195+
if ($this->requestInfoFilter === null) {
196+
$this->requestInfoFilter = \Magento\Framework\App\ObjectManager::getInstance()
197+
->get(RequestInfoFilterInterface::class);
198+
}
199+
return $this->requestInfoFilter;
200+
}
201+
}

0 commit comments

Comments
 (0)