algoliasearch - Version 1.11.1

Version Notes

Change Log: https://github.com/algolia/algoliasearch-magento/blob/master/CHANGELOG.md

Download this release

Release Info

Developer Algolia Team
Extension algoliasearch
Version 1.11.1
Comparing to
See all releases


Code changes from version 1.10.0 to 1.11.1

Files changed (43) hide show
  1. app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Notifications.php +42 -0
  2. app/code/community/Algolia/Algoliasearch/Helper/Algoliahelper.php +34 -0
  3. app/code/community/Algolia/Algoliasearch/Helper/Config.php +38 -4
  4. app/code/community/Algolia/Algoliasearch/Helper/Data.php +25 -7
  5. app/code/community/Algolia/Algoliasearch/Helper/Entity/Helper.php +2 -0
  6. app/code/community/Algolia/Algoliasearch/Helper/Entity/Pagehelper.php +18 -1
  7. app/code/community/Algolia/Algoliasearch/Helper/Entity/Producthelper.php +32 -7
  8. app/code/community/Algolia/Algoliasearch/Helper/IndexChecker.php +149 -0
  9. app/code/community/Algolia/Algoliasearch/Model/Exception/IndexPendingException.php +6 -0
  10. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algolia.php +9 -1
  11. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaadditionalsections.php +5 -1
  12. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliacategories.php +8 -0
  13. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliapages.php +5 -1
  14. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaqueuerunner.php +1 -1
  15. app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliasuggestions.php +5 -1
  16. app/code/community/Algolia/Algoliasearch/Model/Observer.php +16 -1
  17. app/code/community/Algolia/Algoliasearch/Model/Queue.php +93 -17
  18. app/code/community/Algolia/Algoliasearch/Model/Resource/Engine.php +15 -18
  19. app/code/community/Algolia/Algoliasearch/Model/Resource/Fulltext.php +4 -0
  20. app/code/community/Algolia/Algoliasearch/Model/System/Config/Source/Dropdown/RetryValues.php +19 -0
  21. app/code/community/Algolia/Algoliasearch/controllers/Adminhtml/QueueController.php +5 -0
  22. app/code/community/Algolia/Algoliasearch/etc/config.xml +16 -2
  23. app/code/community/Algolia/Algoliasearch/etc/system.xml +94 -14
  24. app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.7.1-1.11.1.php +21 -0
  25. app/design/adminhtml/default/default/layout/algoliasearch.xml +10 -0
  26. app/design/adminhtml/default/default/template/algoliasearch/notifications.phtml +30 -0
  27. app/design/frontend/base/default/template/algoliasearch/.DS_Store +0 -0
  28. app/design/frontend/base/default/template/algoliasearch/internals/configuration.phtml +2 -0
  29. app/etc/modules/Algolia_Algoliasearch.xml +1 -1
  30. js/algoliasearch/.DS_Store +0 -0
  31. js/algoliasearch/autocomplete.js +1 -1
  32. js/algoliasearch/instantsearch.js +17 -16
  33. js/algoliasearch/internals/.DS_Store +0 -0
  34. js/algoliasearch/internals/adminhtml/admin_scripts.js +8 -2
  35. js/algoliasearch/internals/frontend/common.js +43 -6
  36. lib/AlgoliaSearch/AlgoliaConnectionException.php +30 -0
  37. lib/AlgoliaSearch/Client.php +8 -9
  38. lib/AlgoliaSearch/ClientContext.php +8 -8
  39. lib/AlgoliaSearch/Index.php +152 -1
  40. lib/AlgoliaSearch/Version.php +1 -1
  41. lib/AlgoliaSearch/loader.php +5 -4
  42. package.xml +4 -4
  43. skin/frontend/base/default/algoliasearch/algoliasearch.css +5 -0
app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Notifications.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Algolia_Algoliasearch_Block_Adminhtml_Notifications extends Mage_Adminhtml_Block_Template
4
+ {
5
+ public function getConfigurationUrl()
6
+ {
7
+ return $this->getUrl('adminhtml/system_config/edit/section/algoliasearch');
8
+ }
9
+
10
+ public function getQueueInfo()
11
+ {
12
+ /** @var Algolia_Algoliasearch_Helper_Config $config */
13
+ $config = Mage::helper('algoliasearch/config');
14
+
15
+ /** @var Mage_Core_Model_Resource $resource */
16
+ $resource = Mage::getSingleton('core/resource');
17
+ $tableName = $resource->getTableName('algoliasearch/queue');
18
+
19
+ $readConnection = $resource->getConnection('core_read');
20
+
21
+ $size = (int)$readConnection->query('SELECT COUNT(*) as total_count FROM '.$tableName)->fetchColumn(0);
22
+ $maxJobsPerSingleRun = $config->getNumberOfJobToRun();
23
+
24
+ $etaMinutes = ceil($size / $maxJobsPerSingleRun) * 5; // 5 - assuming the queue runner runs every 5 minutes
25
+
26
+ $eta = $etaMinutes.' minutes';
27
+ if ($etaMinutes > 60) {
28
+ $hours = floor($etaMinutes / 60);
29
+ $restMinutes = $etaMinutes % 60;
30
+
31
+ $eta = $hours.' hours '.$restMinutes.' minutes';
32
+ }
33
+
34
+ $queueInfo = array(
35
+ 'isEnabled' => $config->isQueueActive(),
36
+ 'currentSize' => $size,
37
+ 'eta' => $eta,
38
+ );
39
+
40
+ return $queueInfo;
41
+ }
42
+ }
app/code/community/Algolia/Algoliasearch/Helper/Algoliahelper.php CHANGED
@@ -217,6 +217,40 @@ class Algolia_Algoliasearch_Helper_Algoliahelper extends Mage_Core_Helper_Abstra
217
  $this->lastTaskId = $res['taskID'];
218
  }
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  public function waitLastTask()
221
  {
222
  if (!isset($this->lastUsedIndexName) || !isset($this->lastTaskId)) {
217
  $this->lastTaskId = $res['taskID'];
218
  }
219
 
220
+ public function copyQueryRules($fromIndexName, $toIndexName)
221
+ {
222
+ $fromIndex = $this->getIndex($fromIndexName);
223
+ $toIndex = $this->getIndex($toIndexName);
224
+
225
+ $queryRulesToSet = array();
226
+
227
+ $hitsPerPage = 100;
228
+ $page = 0;
229
+ do {
230
+ $fetchedQueryRules = $fromIndex->searchRules(array(
231
+ 'page' => $page,
232
+ 'hitsPerPage' => $hitsPerPage,
233
+ ));
234
+
235
+ foreach ($fetchedQueryRules['hits'] as $hit) {
236
+ unset($hit['_highlightResult']);
237
+
238
+ $queryRulesToSet[] = $hit;
239
+ }
240
+
241
+ $page++;
242
+ } while (($page * $hitsPerPage) < $fetchedQueryRules['nbHits']);
243
+
244
+ if (empty($queryRulesToSet)) {
245
+ $res = $toIndex->clearRules(true);
246
+ } else {
247
+ $res = $toIndex->batchRules($queryRulesToSet, true, true);
248
+ }
249
+
250
+ $this->lastUsedIndexName = $toIndex;
251
+ $this->lastTaskId = $res['taskID'];
252
+ }
253
+
254
  public function waitLastTask()
255
  {
256
  if (!isset($this->lastUsedIndexName) || !isset($this->lastTaskId)) {
app/code/community/Algolia/Algoliasearch/Helper/Config.php CHANGED
@@ -13,6 +13,7 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
13
  const SEARCH_ONLY_API_KEY = 'algoliasearch/credentials/search_only_api_key';
14
  const INDEX_PREFIX = 'algoliasearch/credentials/index_prefix';
15
  const IS_INSTANT_ENABLED = 'algoliasearch/credentials/is_instant_enabled';
 
16
 
17
  const REPLACE_CATEGORIES = 'algoliasearch/instant/replace_categories';
18
  const INSTANT_SELECTOR = 'algoliasearch/instant/instant_selector';
@@ -30,6 +31,7 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
30
  const MIN_NUMBER_OF_RESULTS = 'algoliasearch/autocomplete/min_number_of_results';
31
  const DISPLAY_SUGGESTIONS_CATEGORIES = 'algoliasearch/autocomplete/display_categories_with_suggestions';
32
  const RENDER_TEMPLATE_DIRECTIVES = 'algoliasearch/autocomplete/render_template_directives';
 
33
 
34
  const NUMBER_OF_PRODUCT_RESULTS = 'algoliasearch/products/number_product_results';
35
  const PRODUCT_ATTRIBUTES = 'algoliasearch/products/product_additional_attributes';
@@ -48,6 +50,9 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
48
  const IS_ACTIVE = 'algoliasearch/queue/active';
49
  const NUMBER_OF_ELEMENT_BY_PAGE = 'algoliasearch/queue/number_of_element_by_page';
50
  const NUMBER_OF_JOB_TO_RUN = 'algoliasearch/queue/number_of_job_to_run';
 
 
 
51
 
52
  const XML_PATH_IMAGE_WIDTH = 'algoliasearch/image/width';
53
  const XML_PATH_IMAGE_HEIGHT = 'algoliasearch/image/height';
@@ -259,6 +264,21 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
259
  return Mage::getStoreConfigFlag(self::IS_ACTIVE, $storeId);
260
  }
261
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  public function getRemoveWordsIfNoResult($storeId = null)
263
  {
264
  return Mage::getStoreConfig(self::REMOVE_IF_NO_RESULT, $storeId);
@@ -294,6 +314,11 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
294
  return Mage::getStoreConfigFlag(self::IS_INSTANT_ENABLED, $storeId);
295
  }
296
 
 
 
 
 
 
297
  public function getInstantSelector($storeId = null)
298
  {
299
  return Mage::getStoreConfig(self::INSTANT_SELECTOR, $storeId);
@@ -315,6 +340,11 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
315
  return Mage::getStoreConfigFlag(self::RENDER_TEMPLATE_DIRECTIVES, $storeId);
316
  }
317
 
 
 
 
 
 
318
  public function getSortingIndices($storeId = null)
319
  {
320
  /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */
@@ -424,7 +454,7 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
424
 
425
  $attributes = array_unique($attributes);
426
 
427
- return $attributes;
428
  }
429
 
430
  public function getCategoryAdditionalAttributes($storeId = null)
@@ -497,13 +527,17 @@ class Algolia_Algoliasearch_Helper_Config extends Mage_Core_Helper_Abstract
497
 
498
  public function getPopularQueries($storeId = null)
499
  {
 
 
 
 
500
  if ($storeId === null) {
501
  $storeId = Mage::app()->getStore()->getId();
502
  }
503
 
504
- /** @var Algolia_Algoliasearch_Helper_Entity_Suggestionhelper $suggestion_helper */
505
- $suggestion_helper = Mage::helper('algoliasearch/entity_suggestionhelper');
506
- $popularQueries = $suggestion_helper->getPopularQueries($storeId);
507
 
508
  return $popularQueries;
509
  }
13
  const SEARCH_ONLY_API_KEY = 'algoliasearch/credentials/search_only_api_key';
14
  const INDEX_PREFIX = 'algoliasearch/credentials/index_prefix';
15
  const IS_INSTANT_ENABLED = 'algoliasearch/credentials/is_instant_enabled';
16
+ const USE_ADAPTIVE_IMAGE = 'algoliasearch/credentials/use_adaptive_image';
17
 
18
  const REPLACE_CATEGORIES = 'algoliasearch/instant/replace_categories';
19
  const INSTANT_SELECTOR = 'algoliasearch/instant/instant_selector';
31
  const MIN_NUMBER_OF_RESULTS = 'algoliasearch/autocomplete/min_number_of_results';
32
  const DISPLAY_SUGGESTIONS_CATEGORIES = 'algoliasearch/autocomplete/display_categories_with_suggestions';
33
  const RENDER_TEMPLATE_DIRECTIVES = 'algoliasearch/autocomplete/render_template_directives';
34
+ const AUTOCOMPLETE_MENU_DEBUG = 'algoliasearch/autocomplete/debug';
35
 
36
  const NUMBER_OF_PRODUCT_RESULTS = 'algoliasearch/products/number_product_results';
37
  const PRODUCT_ATTRIBUTES = 'algoliasearch/products/product_additional_attributes';
50
  const IS_ACTIVE = 'algoliasearch/queue/active';
51
  const NUMBER_OF_ELEMENT_BY_PAGE = 'algoliasearch/queue/number_of_element_by_page';
52
  const NUMBER_OF_JOB_TO_RUN = 'algoliasearch/queue/number_of_job_to_run';
53
+ const RETRY_LIMIT = 'algoliasearch/queue/number_of_retries';
54
+ const CHECK_PRICE_INDEX = 'algoliasearch/queue/check_price_index';
55
+ const CHECK_STOCK_INDEX = 'algoliasearch/queue/check_stock_index';
56
 
57
  const XML_PATH_IMAGE_WIDTH = 'algoliasearch/image/width';
58
  const XML_PATH_IMAGE_HEIGHT = 'algoliasearch/image/height';
264
  return Mage::getStoreConfigFlag(self::IS_ACTIVE, $storeId);
265
  }
266
 
267
+ public function shouldCheckPriceIndex($storeId = null)
268
+ {
269
+ return Mage::getStoreConfigFlag(self::CHECK_PRICE_INDEX, $storeId);
270
+ }
271
+
272
+ public function shouldCheckStockIndex($storeId = null)
273
+ {
274
+ return Mage::getStoreConfigFlag(self::CHECK_STOCK_INDEX, $storeId);
275
+ }
276
+
277
+ public function getRetryLimit($storeId = null)
278
+ {
279
+ return (int) Mage::getStoreConfig(self::RETRY_LIMIT, $storeId);
280
+ }
281
+
282
  public function getRemoveWordsIfNoResult($storeId = null)
283
  {
284
  return Mage::getStoreConfig(self::REMOVE_IF_NO_RESULT, $storeId);
314
  return Mage::getStoreConfigFlag(self::IS_INSTANT_ENABLED, $storeId);
315
  }
316
 
317
+ public function useAdaptiveImage($storeId = null)
318
+ {
319
+ return Mage::getStoreConfigFlag(self::USE_ADAPTIVE_IMAGE, $storeId);
320
+ }
321
+
322
  public function getInstantSelector($storeId = null)
323
  {
324
  return Mage::getStoreConfig(self::INSTANT_SELECTOR, $storeId);
340
  return Mage::getStoreConfigFlag(self::RENDER_TEMPLATE_DIRECTIVES, $storeId);
341
  }
342
 
343
+ public function isAutocompleteDebugEnabled($storeId = null)
344
+ {
345
+ return Mage::getStoreConfigFlag(self::AUTOCOMPLETE_MENU_DEBUG, $storeId);
346
+ }
347
+
348
  public function getSortingIndices($storeId = null)
349
  {
350
  /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */
454
 
455
  $attributes = array_unique($attributes);
456
 
457
+ return array_values($attributes);
458
  }
459
 
460
  public function getCategoryAdditionalAttributes($storeId = null)
527
 
528
  public function getPopularQueries($storeId = null)
529
  {
530
+ if (!$this->isInstantEnabled($storeId) || !$this->showSuggestionsOnNoResultsPage($storeId)) {
531
+ return array();
532
+ }
533
+
534
  if ($storeId === null) {
535
  $storeId = Mage::app()->getStore()->getId();
536
  }
537
 
538
+ /** @var Algolia_Algoliasearch_Helper_Entity_Suggestionhelper $suggestionHelper */
539
+ $suggestionHelper = Mage::helper('algoliasearch/entity_suggestionhelper');
540
+ $popularQueries = $suggestionHelper->getPopularQueries($storeId);
541
 
542
  return $popularQueries;
543
  }
app/code/community/Algolia/Algoliasearch/Helper/Data.php CHANGED
@@ -185,7 +185,7 @@ class Algolia_Algoliasearch_Helper_Data extends Mage_Core_Helper_Abstract
185
  }
186
  }
187
 
188
- public function rebuildStorePageIndex($storeId)
189
  {
190
  if ($this->config->isEnabledBackend($storeId) === false) {
191
  $this->logger->log('INDEXING IS DISABLED FOR '.$this->logger->getStoreName($storeId));
@@ -193,19 +193,24 @@ class Algolia_Algoliasearch_Helper_Data extends Mage_Core_Helper_Abstract
193
  return;
194
  }
195
 
196
- $emulationInfo = $this->startEmulation($storeId);
197
 
198
- $index_name = $this->page_helper->getIndexName($storeId);
199
 
200
- $pages = $this->page_helper->getPages($storeId);
201
 
 
 
202
  foreach (array_chunk($pages, 100) as $chunk) {
203
- $this->algolia_helper->addObjects($chunk, $index_name.'_tmp');
204
  }
205
 
206
- $this->algolia_helper->moveIndex($index_name.'_tmp', $index_name);
 
207
 
208
- $this->algolia_helper->setSettings($index_name, $this->page_helper->getIndexSettings($storeId));
 
 
209
 
210
  $this->stopEmulation($emulationInfo);
211
  }
@@ -444,6 +449,19 @@ class Algolia_Algoliasearch_Helper_Data extends Mage_Core_Helper_Abstract
444
  $potentiallyDeletedProductsIds = array();
445
  }
446
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  $this->logger->start('CREATE RECORDS '.$this->logger->getStoreName($storeId));
448
  $this->logger->log(count($collection).' product records to create');
449
 
185
  }
186
  }
187
 
188
+ public function rebuildStorePageIndex($storeId, $pageIds = null)
189
  {
190
  if ($this->config->isEnabledBackend($storeId) === false) {
191
  $this->logger->log('INDEXING IS DISABLED FOR '.$this->logger->getStoreName($storeId));
193
  return;
194
  }
195
 
196
+ $shouldUseTmpIndex = ($pageIds === null);
197
 
198
+ $emulationInfo = $this->startEmulation($storeId);
199
 
200
+ $indexName = $this->page_helper->getIndexName($storeId, $shouldUseTmpIndex);
201
 
202
+ /** @var array $pages */
203
+ $pages = $this->page_helper->getPages($storeId, $pageIds);
204
  foreach (array_chunk($pages, 100) as $chunk) {
205
+ $this->algolia_helper->addObjects($chunk, $indexName);
206
  }
207
 
208
+ if ($shouldUseTmpIndex === true) {
209
+ $finalIndexName = $this->page_helper->getIndexName($storeId);
210
 
211
+ $this->algolia_helper->moveIndex($indexName, $finalIndexName);
212
+ $this->algolia_helper->setSettings($finalIndexName, $this->page_helper->getIndexSettings($storeId));
213
+ }
214
 
215
  $this->stopEmulation($emulationInfo);
216
  }
449
  $potentiallyDeletedProductsIds = array();
450
  }
451
 
452
+ if (method_exists('Mage', 'getEdition') === true && Mage::getEdition() === Mage::EDITION_ENTERPRISE) {
453
+ $productIds = array();
454
+
455
+ /** @var Mage_Catalog_Model_Product $products */
456
+ foreach ($collection as $products) {
457
+ $productIds[] = $products->getId();
458
+ }
459
+
460
+ /** @var Algolia_Algoliasearch_Helper_IndexChecker $indexChecker */
461
+ $indexChecker = Mage::helper('algoliasearch/indexChecker');
462
+ $indexChecker->checkIndexers($storeId, $productIds);
463
+ }
464
+
465
  $this->logger->start('CREATE RECORDS '.$this->logger->getStoreName($storeId));
466
  $this->logger->log(count($collection).' product records to create');
467
 
app/code/community/Algolia/Algoliasearch/Helper/Entity/Helper.php CHANGED
@@ -272,6 +272,8 @@ abstract class Algolia_Algoliasearch_Helper_Entity_Helper
272
  $store_ids[] = $store->getId();
273
  }
274
  }
 
 
275
  } else {
276
  $store_ids = array($store_id);
277
  }
272
  $store_ids[] = $store->getId();
273
  }
274
  }
275
+ } elseif (is_array($store_id)) {
276
+ return $store_id;
277
  } else {
278
  $store_ids = array($store_id);
279
  }
app/code/community/Algolia/Algoliasearch/Helper/Entity/Pagehelper.php CHANGED
@@ -21,7 +21,7 @@ class Algolia_Algoliasearch_Helper_Entity_Pagehelper extends Algolia_Algoliasear
21
  return $indexSettings;
22
  }
23
 
24
- public function getPages($storeId)
25
  {
26
  /** @var Mage_Cms_Model_Page $cmsPage */
27
  $cmsPage = Mage::getModel('cms/page');
@@ -29,6 +29,10 @@ class Algolia_Algoliasearch_Helper_Entity_Pagehelper extends Algolia_Algoliasear
29
  /** @var Mage_Cms_Model_Resource_Page_Collection $pages */
30
  $pages = $cmsPage->getCollection()->addStoreFilter($storeId)->addFieldToFilter('is_active', 1);
31
 
 
 
 
 
32
  Mage::dispatchEvent('algolia_after_pages_collection_build', array('store' => $storeId, 'collection' => $pages));
33
 
34
  $ids = $pages->toOptionArray();
@@ -85,4 +89,17 @@ class Algolia_Algoliasearch_Helper_Entity_Pagehelper extends Algolia_Algoliasear
85
 
86
  return $pages;
87
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
21
  return $indexSettings;
22
  }
23
 
24
+ public function getPages($storeId, $pageIds = null)
25
  {
26
  /** @var Mage_Cms_Model_Page $cmsPage */
27
  $cmsPage = Mage::getModel('cms/page');
29
  /** @var Mage_Cms_Model_Resource_Page_Collection $pages */
30
  $pages = $cmsPage->getCollection()->addStoreFilter($storeId)->addFieldToFilter('is_active', 1);
31
 
32
+ if ($pageIds && count($pageIds) > 0) {
33
+ $pages = $pages->addFieldToFilter('page_id', array('in' => $pageIds));
34
+ }
35
+
36
  Mage::dispatchEvent('algolia_after_pages_collection_build', array('store' => $storeId, 'collection' => $pages));
37
 
38
  $ids = $pages->toOptionArray();
89
 
90
  return $pages;
91
  }
92
+
93
+ public function shouldIndexPages($storeId)
94
+ {
95
+ $autocompleteSections = $this->config->getAutocompleteSections($storeId);
96
+
97
+ foreach ($autocompleteSections as $section) {
98
+ if ($section['name'] === 'pages') {
99
+ return true;
100
+ }
101
+ }
102
+
103
+ return false;
104
+ }
105
  }
app/code/community/Algolia/Algoliasearch/Helper/Entity/Producthelper.php CHANGED
@@ -229,7 +229,7 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
229
 
230
  $customRankingAttributes = array();
231
 
232
- $facets = $this->config->getFacets();
233
 
234
  /** @var Mage_Directory_Model_Currency $directoryCurrency */
235
  $directoryCurrency = Mage::getModel('directory/currency');
@@ -291,7 +291,7 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
291
  /*
292
  * Handle replicas
293
  */
294
- $sorting_indices = $this->config->getSortingIndices();
295
 
296
  if (count($sorting_indices) > 0) {
297
  $replicas = array();
@@ -406,6 +406,10 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
406
  } elseif ($saveToTmpIndicesToo === true) {
407
  $this->algolia_helper->copySynonyms($this->getIndexName($storeId), $this->getIndexName($storeId, $saveToTmpIndicesToo));
408
  }
 
 
 
 
409
  }
410
 
411
  protected function getFields($store)
@@ -905,15 +909,16 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
905
  if ($attribute_resource) {
906
  $attribute_resource->setStoreId($product->getStoreId());
907
 
 
 
 
908
  /**
909
  * if $value is missing or if the attribute is SKU,
910
  * use values from child products.
911
  */
912
  if (($value === null || 'sku' == $attribute_name) && ($type == 'configurable' || $type == 'grouped' || $type == 'bundle')) {
913
- if ($value === null) {
914
- $values = array();
915
- } else {
916
- $values = array($this->getValueOrValueText($product, $attribute_name, $attribute_resource));
917
  }
918
 
919
  $all_sub_products_out_of_stock = true;
@@ -931,7 +936,23 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
931
  $value = $sub_product->getData($attribute_name);
932
 
933
  if ($value) {
934
- $values[] = $this->getValueOrValueText($sub_product, $attribute_name, $attribute_resource);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
935
  }
936
  }
937
  }
@@ -940,6 +961,10 @@ class Algolia_Algoliasearch_Helper_Entity_Producthelper extends Algolia_Algolias
940
  $customData[$attribute_name] = array_values(array_unique($values, SORT_REGULAR));
941
  }
942
 
 
 
 
 
943
  // Set main product out of stock if all
944
  // sub-products are out of stock.
945
  if ($customData['in_stock'] && $all_sub_products_out_of_stock) {
229
 
230
  $customRankingAttributes = array();
231
 
232
+ $facets = $this->config->getFacets($storeId);
233
 
234
  /** @var Mage_Directory_Model_Currency $directoryCurrency */
235
  $directoryCurrency = Mage::getModel('directory/currency');
291
  /*
292
  * Handle replicas
293
  */
294
+ $sorting_indices = $this->config->getSortingIndices($storeId);
295
 
296
  if (count($sorting_indices) > 0) {
297
  $replicas = array();
406
  } elseif ($saveToTmpIndicesToo === true) {
407
  $this->algolia_helper->copySynonyms($this->getIndexName($storeId), $this->getIndexName($storeId, $saveToTmpIndicesToo));
408
  }
409
+
410
+ if ($saveToTmpIndicesToo === true) {
411
+ $this->algolia_helper->copyQueryRules($this->getIndexName($storeId), $this->getIndexName($storeId, $saveToTmpIndicesToo));
412
+ }
413
  }
414
 
415
  protected function getFields($store)
909
  if ($attribute_resource) {
910
  $attribute_resource->setStoreId($product->getStoreId());
911
 
912
+ $values = array();
913
+ $subProductImages = array();
914
+
915
  /**
916
  * if $value is missing or if the attribute is SKU,
917
  * use values from child products.
918
  */
919
  if (($value === null || 'sku' == $attribute_name) && ($type == 'configurable' || $type == 'grouped' || $type == 'bundle')) {
920
+ if ($value !== null) {
921
+ $values[] = $this->getValueOrValueText($product, $attribute_name, $attribute_resource);
 
 
922
  }
923
 
924
  $all_sub_products_out_of_stock = true;
936
  $value = $sub_product->getData($attribute_name);
937
 
938
  if ($value) {
939
+ $textValue = $this->getValueOrValueText($sub_product, $attribute_name, $attribute_resource);
940
+
941
+ $values[] = $textValue;
942
+
943
+ if (mb_strtolower($attribute_name, 'utf-8') === 'color') {
944
+ $image = $imageHelper->init($sub_product, $this->config->getImageType())
945
+ ->resize($this->config->getImageWidth(),
946
+ $this->config->getImageHeight());
947
+
948
+ try {
949
+ $textValueInLower = mb_strtolower($textValue, 'utf-8');
950
+ $subProductImages[$textValueInLower] = $image->toString();
951
+ } catch (\Exception $e) {
952
+ $this->logger->log($e->getMessage());
953
+ $this->logger->log($e->getTraceAsString());
954
+ }
955
+ }
956
  }
957
  }
958
  }
961
  $customData[$attribute_name] = array_values(array_unique($values, SORT_REGULAR));
962
  }
963
 
964
+ if (empty($subProductImages) === false) {
965
+ $customData['images_data'] = $subProductImages;
966
+ }
967
+
968
  // Set main product out of stock if all
969
  // sub-products are out of stock.
970
  if ($customData['in_stock'] && $all_sub_products_out_of_stock) {
app/code/community/Algolia/Algoliasearch/Helper/IndexChecker.php ADDED
@@ -0,0 +1,149 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Algolia_Algoliasearch_Helper_IndexChecker extends Mage_Core_Helper_Abstract
4
+ {
5
+ /** @var Algolia_Algoliasearch_Helper_Config */
6
+ private $configHelper;
7
+
8
+ /** @var Varien_Db_Adapter_Interface */
9
+ private $dbConnection;
10
+
11
+ /** @var array */
12
+ private $pendingProductIds;
13
+
14
+ public function __construct()
15
+ {
16
+ /** @var Algolia_Algoliasearch_Helper_Config configHelper */
17
+ $this->configHelper = Mage::helper('algoliasearch/config');
18
+ }
19
+
20
+ /**
21
+ * @param $storeId
22
+ * @param $productIds
23
+ * @throws Exception
24
+ */
25
+ public function checkIndexers($storeId, $productIds)
26
+ {
27
+ if ($this->configHelper->isQueueActive($storeId) === false) {
28
+ return;
29
+ }
30
+
31
+ if (!is_array($productIds)) {
32
+ $productIds = array($productIds);
33
+ }
34
+
35
+ if (empty($productIds)) {
36
+ return;
37
+ }
38
+
39
+ $pendingProductIds = $this->getPendingProductIds($storeId);
40
+
41
+ if (empty($pendingProductIds)) {
42
+ return;
43
+ }
44
+
45
+ foreach ($productIds as $id) {
46
+ if (isset($this->pendingProductIds[$id])) {
47
+ // Throw an exception - this exception is caught in Queue class and it'll retry next time Algolia is processed.
48
+ throw new Algolia_Algoliasearch_Model_Exception_IndexPendingException('Reindexing (price / stock) is still pending for entity ID ' . $id);
49
+ }
50
+ }
51
+ }
52
+
53
+ private function getPendingProductIds($storeId)
54
+ {
55
+ if (isset($this->pendingProductIds) === false) {
56
+ $priceIndexes = $this->pendingPriceIndex($storeId);
57
+ $stockIndexes = $this->pendingStockIndex($storeId);
58
+
59
+ $pendingProductIds = array_unique(array_merge($priceIndexes, $stockIndexes));
60
+ $this->pendingProductIds = array_flip($pendingProductIds);
61
+ }
62
+
63
+ return $this->pendingProductIds;
64
+ }
65
+
66
+ /**
67
+ * Find all productId's pending a price reindex.
68
+ *
69
+ * @param $storeId
70
+ * @return array
71
+ */
72
+ private function pendingPriceIndex($storeId)
73
+ {
74
+ $returnArray = array();
75
+
76
+ if ($this->configHelper->shouldCheckPriceIndex($storeId)) {
77
+ $maxVersion = $this->findLatestVersion('catalog_product_index_price_cl');
78
+ $returnArray = $this->findProductIdsPending('catalog_product_index_price_cl', 'entity_id', $maxVersion);
79
+ }
80
+
81
+ return $returnArray;
82
+ }
83
+
84
+ /**
85
+ * Find all productId's pending a stock reindex.
86
+ *
87
+ * @param $storeId
88
+ * @return array
89
+ */
90
+ private function pendingStockIndex($storeId)
91
+ {
92
+ $returnArray = array();
93
+
94
+ if ($this->configHelper->shouldCheckStockIndex($storeId)) {
95
+ $maxVersion = $this->findLatestVersion('cataloginventory_stock_status_cl');
96
+ $returnArray = $this->findProductIdsPending('cataloginventory_stock_status_cl', 'product_id', $maxVersion);
97
+ }
98
+
99
+ return $returnArray;
100
+ }
101
+
102
+ /**
103
+ * Find all product ID's who have a version ID greater then the maxVersion.
104
+ *
105
+ * @param $changeLogTable
106
+ * @param $idColumn
107
+ * @param $maxVersion
108
+ *
109
+ * @return mixed - array of ID's
110
+ */
111
+ private function findProductIdsPending($changeLogTable, $idColumn, $maxVersion)
112
+ {
113
+ $connection = $this->getConnection();
114
+ $select = $connection->select()
115
+ ->distinct()
116
+ ->from($changeLogTable, $idColumn)
117
+ ->join(array('catalog_product_entity' => 'catalog_product_entity'), "$changeLogTable.$idColumn = catalog_product_entity.entity_id", array())
118
+ ->where('version_id > ?', $maxVersion);
119
+
120
+ return $connection->fetchCol($select);
121
+ }
122
+
123
+ /**
124
+ * Find the latest version ID for a particular changeLog
125
+ *
126
+ * @param $changeLogTable
127
+ * @return mixed
128
+ */
129
+ private function findLatestVersion($changeLogTable)
130
+ {
131
+ $connection = $this->getConnection();
132
+ $select = $connection->select()
133
+ ->from('enterprise_mview_metadata', 'version_id')
134
+ ->where('changelog_name = ?', $changeLogTable);
135
+
136
+ return $connection->fetchOne($select);
137
+ }
138
+
139
+ private function getConnection()
140
+ {
141
+ if (isset($this->dbConnection) === false) {
142
+ /** @var Mage_Core_Model_Resource $coreResource */
143
+ $coreResource = Mage::getSingleton('core/resource');
144
+ $this->dbConnection = $coreResource->getConnection('core_read');
145
+ }
146
+
147
+ return $this->dbConnection;
148
+ }
149
+ }
app/code/community/Algolia/Algoliasearch/Model/Exception/IndexPendingException.php ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Algolia_Algoliasearch_Model_Exception_IndexPendingException extends \Exception
4
+ {
5
+ //
6
+ }
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algolia.php CHANGED
@@ -166,6 +166,10 @@ class Algolia_Algoliasearch_Model_Indexer_Algolia extends Algolia_Algoliasearch_
166
 
167
  protected function _processEvent(Mage_Index_Model_Event $event)
168
  {
 
 
 
 
169
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
170
  if (self::$credential_error === false) {
171
  /** @var Mage_Adminhtml_Model_Session $session */
@@ -205,6 +209,10 @@ class Algolia_Algoliasearch_Model_Indexer_Algolia extends Algolia_Algoliasearch_
205
  */
206
  public function reindexAll()
207
  {
 
 
 
 
208
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
209
  /** @var Mage_Adminhtml_Model_Session $session */
210
  $session = Mage::getSingleton('adminhtml/session');
@@ -212,7 +220,7 @@ class Algolia_Algoliasearch_Model_Indexer_Algolia extends Algolia_Algoliasearch_
212
 
213
  $this->logger->log('ERROR Credentials not configured correctly');
214
 
215
- return;
216
  }
217
 
218
  $this->logger->start('PRODUCTS FULL REINDEX');
166
 
167
  protected function _processEvent(Mage_Index_Model_Event $event)
168
  {
169
+ if ($this->config->isModuleOutputEnabled() === false) {
170
+ return;
171
+ }
172
+
173
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
174
  if (self::$credential_error === false) {
175
  /** @var Mage_Adminhtml_Model_Session $session */
209
  */
210
  public function reindexAll()
211
  {
212
+ if ($this->config->isModuleOutputEnabled() === false) {
213
+ return $this;
214
+ }
215
+
216
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
217
  /** @var Mage_Adminhtml_Model_Session $session */
218
  $session = Mage::getSingleton('adminhtml/session');
220
 
221
  $this->logger->log('ERROR Credentials not configured correctly');
222
 
223
+ return $this;
224
  }
225
 
226
  $this->logger->start('PRODUCTS FULL REINDEX');
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaadditionalsections.php CHANGED
@@ -68,12 +68,16 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliaadditionalsections extends Algo
68
  */
69
  public function reindexAll()
70
  {
 
 
 
 
71
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
72
  /** @var Mage_Adminhtml_Model_Session $session */
73
  $session = Mage::getSingleton('adminhtml/session');
74
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
75
 
76
- return;
77
  }
78
 
79
  $this->engine->rebuildAdditionalSections();
68
  */
69
  public function reindexAll()
70
  {
71
+ if ($this->config->isModuleOutputEnabled() === false) {
72
+ return $this;
73
+ }
74
+
75
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
76
  /** @var Mage_Adminhtml_Model_Session $session */
77
  $session = Mage::getSingleton('adminhtml/session');
78
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
79
 
80
+ return $this;
81
  }
82
 
83
  $this->engine->rebuildAdditionalSections();
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliacategories.php CHANGED
@@ -111,6 +111,10 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliacategories extends Algolia_Algo
111
 
112
  protected function _processEvent(Mage_Index_Model_Event $event)
113
  {
 
 
 
 
114
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
115
  if (self::$credential_error === false) {
116
  /** @var Mage_Adminhtml_Model_Session $session */
@@ -172,6 +176,10 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliacategories extends Algolia_Algo
172
  */
173
  public function reindexAll()
174
  {
 
 
 
 
175
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
176
  /** @var Mage_Adminhtml_Model_Session $session */
177
  $session = Mage::getSingleton('adminhtml/session');
111
 
112
  protected function _processEvent(Mage_Index_Model_Event $event)
113
  {
114
+ if ($this->config->isModuleOutputEnabled() === false) {
115
+ return;
116
+ }
117
+
118
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
119
  if (self::$credential_error === false) {
120
  /** @var Mage_Adminhtml_Model_Session $session */
176
  */
177
  public function reindexAll()
178
  {
179
+ if ($this->config->isModuleOutputEnabled() === false) {
180
+ return $this;
181
+ }
182
+
183
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
184
  /** @var Mage_Adminhtml_Model_Session $session */
185
  $session = Mage::getSingleton('adminhtml/session');
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliapages.php CHANGED
@@ -68,12 +68,16 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliapages extends Algolia_Algoliase
68
  */
69
  public function reindexAll()
70
  {
 
 
 
 
71
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
72
  /** @var Mage_Adminhtml_Model_Session $session */
73
  $session = Mage::getSingleton('adminhtml/session');
74
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
75
 
76
- return;
77
  }
78
 
79
  $this->engine->rebuildPages();
68
  */
69
  public function reindexAll()
70
  {
71
+ if ($this->config->isModuleOutputEnabled() === false) {
72
+ return $this;
73
+ }
74
+
75
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
76
  /** @var Mage_Adminhtml_Model_Session $session */
77
  $session = Mage::getSingleton('adminhtml/session');
78
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
79
 
80
+ return $this;
81
  }
82
 
83
  $this->engine->rebuildPages();
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaqueuerunner.php CHANGED
@@ -68,7 +68,7 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliaqueuerunner extends Mage_Index_
68
  $session = Mage::getSingleton('adminhtml/session');
69
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
70
 
71
- return;
72
  }
73
 
74
  $this->queue->runCron();
68
  $session = Mage::getSingleton('adminhtml/session');
69
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
70
 
71
+ return $this;
72
  }
73
 
74
  $this->queue->runCron();
app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliasuggestions.php CHANGED
@@ -72,12 +72,16 @@ class Algolia_Algoliasearch_Model_Indexer_Algoliasuggestions extends Algolia_Alg
72
  */
73
  public function reindexAll()
74
  {
 
 
 
 
75
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
76
  /** @var Mage_Adminhtml_Model_Session $session */
77
  $session = Mage::getSingleton('adminhtml/session');
78
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
79
 
80
- return;
81
  }
82
 
83
  $this->engine->rebuildSuggestions();
72
  */
73
  public function reindexAll()
74
  {
75
+ if ($this->config->isModuleOutputEnabled() === false) {
76
+ return $this;
77
+ }
78
+
79
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
80
  /** @var Mage_Adminhtml_Model_Session $session */
81
  $session = Mage::getSingleton('adminhtml/session');
82
  $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.');
83
 
84
+ return $this;
85
  }
86
 
87
  $this->engine->rebuildSuggestions();
app/code/community/Algolia/Algoliasearch/Model/Observer.php CHANGED
@@ -91,6 +91,20 @@ class Algolia_Algoliasearch_Model_Observer
91
  Algolia_Algoliasearch_Model_Indexer_Algolia::$product_categories[$product->getId()] = $product->getCategoryIds();
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  public function deleteProductsStoreIndices(Varien_Object $event)
95
  {
96
  $storeId = $event->getStoreId();
@@ -123,8 +137,9 @@ class Algolia_Algoliasearch_Model_Observer
123
  public function rebuildPageIndex(Varien_Object $event)
124
  {
125
  $storeId = $event->getStoreId();
 
126
 
127
- $this->helper->rebuildStorePageIndex($storeId);
128
  }
129
 
130
  public function rebuildSuggestionIndex(Varien_Object $event)
91
  Algolia_Algoliasearch_Model_Indexer_Algolia::$product_categories[$product->getId()] = $product->getCategoryIds();
92
  }
93
 
94
+ public function savePage(Varien_Event_Observer $observer)
95
+ {
96
+ /** @var Mage_Cms_Model_Page $page */
97
+ $page = $observer->getDataObject();
98
+ $page = Mage::getModel('cms/page')->load($page->getId());
99
+
100
+ $storeIds = $page->getStoreId();
101
+
102
+ /** @var Algolia_Algoliasearch_Model_Resource_Engine $engine */
103
+ $engine = Mage::getResourceModel('algoliasearch/engine');
104
+
105
+ $engine->rebuildPages($storeIds, $page->getId());
106
+ }
107
+
108
  public function deleteProductsStoreIndices(Varien_Object $event)
109
  {
110
  $storeId = $event->getStoreId();
137
  public function rebuildPageIndex(Varien_Object $event)
138
  {
139
  $storeId = $event->getStoreId();
140
+ $pageIds = $event->getPageIds();
141
 
142
+ $this->helper->rebuildStorePageIndex($storeId, $pageIds);
143
  }
144
 
145
  public function rebuildSuggestionIndex(Varien_Object $event)
app/code/community/Algolia/Algoliasearch/Model/Queue.php CHANGED
@@ -6,6 +6,7 @@ class Algolia_Algoliasearch_Model_Queue
6
  const ERROR_LOG = 'algoliasearch_queue_errors.log';
7
 
8
  protected $table;
 
9
 
10
  /** @var Magento_Db_Adapter_Pdo_Mysql */
11
  protected $db;
@@ -27,12 +28,18 @@ class Algolia_Algoliasearch_Model_Queue
27
  'moveStoreSuggestionIndex',
28
  );
29
 
 
 
 
 
30
  public function __construct()
31
  {
32
  /** @var Mage_Core_Model_Resource $coreResource */
33
  $coreResource = Mage::getSingleton('core/resource');
34
 
35
  $this->table = $coreResource->getTableName('algoliasearch/queue');
 
 
36
  $this->db = $coreResource->getConnection('core_write');
37
 
38
  $this->config = Mage::helper('algoliasearch/config');
@@ -45,6 +52,7 @@ class Algolia_Algoliasearch_Model_Queue
45
  {
46
  // Insert a row for the new job
47
  $this->db->insert($this->table, array(
 
48
  'class' => $class,
49
  'method' => $method,
50
  'data' => json_encode($data),
@@ -53,19 +61,38 @@ class Algolia_Algoliasearch_Model_Queue
53
  ));
54
  }
55
 
56
- public function runCron()
57
  {
58
- if (!$this->config->isQueueActive()) {
59
  return;
60
  }
61
 
62
- $nbJobs = $this->config->getNumberOfJobToRun();
 
 
 
 
 
 
 
 
63
 
64
- if (getenv('EMPTY_QUEUE') && getenv('EMPTY_QUEUE') == '1') {
65
- $nbJobs = -1;
 
 
 
 
 
66
  }
67
 
68
  $this->run($nbJobs);
 
 
 
 
 
 
69
  }
70
 
71
  public function run($maxJobs)
@@ -75,18 +102,35 @@ class Algolia_Algoliasearch_Model_Queue
75
  $jobs = $this->getJobs($maxJobs, $pid);
76
 
77
  if (empty($jobs)) {
78
- $this->db->closeConnection();
79
  }
80
 
81
  // Run all reserved jobs
82
  foreach ($jobs as $job) {
 
 
 
 
 
 
 
 
 
 
83
  try {
84
  $model = Mage::getSingleton($job['class']);
85
  $method = $job['method'];
86
-
87
  $model->{$method}(new Varien_Object($job['data']));
88
- } catch (Exception $e) {
89
- // Increment retries and log error information
 
 
 
 
 
 
 
 
90
  $this->logger->log("Queue processing {$job['pid']} [KO]: Mage::getSingleton({$job['class']})->{$job['method']}(".json_encode($job['data']).')');
91
  $this->logger->log(date('c').' ERROR: '.get_class($e).": '{$e->getMessage()}' in {$e->getFile()}:{$e->getLine()}\n"."Stack trace:\n".$e->getTraceAsString());
92
  }
@@ -102,12 +146,19 @@ class Algolia_Algoliasearch_Model_Queue
102
 
103
  return;
104
  }
105
-
106
- $this->db->closeConnection();
107
  }
108
 
109
  private function getJobs($maxJobs, $pid)
110
  {
 
 
 
 
 
 
 
 
 
111
  $jobs = array();
112
 
113
  $limit = $maxJobs = ($maxJobs === -1) ? $this->config->getNumberOfJobToRun() : $maxJobs;
@@ -175,8 +226,7 @@ class Algolia_Algoliasearch_Model_Queue
175
 
176
 
177
  if (isset($firstJobId)) {
178
- // Last job has always assigned the last processed ID
179
- $lastJobId = $jobs[count($jobs) - 1]['job_id'];
180
 
181
  // Reserve all new jobs since last run
182
  $this->db->query("UPDATE {$this->db->quoteIdentifier($this->table, true)} SET pid = ".$pid.' WHERE job_id >= '.$firstJobId." AND job_id <= $lastJobId");
@@ -189,6 +239,7 @@ class Algolia_Algoliasearch_Model_Queue
189
  {
190
  foreach ($jobs as &$job) {
191
  $job['data'] = json_decode($job['data'], true);
 
192
  }
193
 
194
  return $jobs;
@@ -211,12 +262,12 @@ class Algolia_Algoliasearch_Model_Queue
211
  // Use the job_id of the the very last job to properly mark processed jobs
212
  $currentJob['job_id'] = max((int) $currentJob['job_id'], (int) $nextJob['job_id']);
213
 
 
 
214
  if (isset($currentJob['data']['product_ids'])) {
215
  $currentJob['data']['product_ids'] = array_merge($currentJob['data']['product_ids'], $nextJob['data']['product_ids']);
216
- $currentJob['data_size'] = count($currentJob['data']['product_ids']);
217
  } elseif (isset($currentJob['data']['category_ids'])) {
218
  $currentJob['data']['category_ids'] = array_merge($currentJob['data']['category_ids'], $nextJob['data']['category_ids']);
219
- $currentJob['data_size'] = count($currentJob['data']['category_ids']);
220
  }
221
 
222
  continue;
@@ -227,10 +278,12 @@ class Algolia_Algoliasearch_Model_Queue
227
 
228
  if (isset($currentJob['data']['product_ids'])) {
229
  $currentJob['data']['product_ids'] = array_unique($currentJob['data']['product_ids']);
 
230
  }
231
 
232
  if (isset($currentJob['data']['category_ids'])) {
233
  $currentJob['data']['category_ids'] = array_unique($currentJob['data']['category_ids']);
 
234
  }
235
 
236
  $jobs[] = $currentJob;
@@ -242,8 +295,6 @@ class Algolia_Algoliasearch_Model_Queue
242
 
243
  private function sortJobs($oldJobs)
244
  {
245
- // Method sorts the jobs and preserves the order of jobs with static methods defined in $this->staticJobMethods
246
-
247
  $sortedJobs = array();
248
 
249
  $tempSortableJobs = array();
@@ -340,4 +391,29 @@ class Algolia_Algoliasearch_Model_Queue
340
 
341
  return array_pop($args);
342
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  }
6
  const ERROR_LOG = 'algoliasearch_queue_errors.log';
7
 
8
  protected $table;
9
+ protected $logTable;
10
 
11
  /** @var Magento_Db_Adapter_Pdo_Mysql */
12
  protected $db;
28
  'moveStoreSuggestionIndex',
29
  );
30
 
31
+ private $noOfFailedJobs = 0;
32
+
33
+ private $logRecord = array();
34
+
35
  public function __construct()
36
  {
37
  /** @var Mage_Core_Model_Resource $coreResource */
38
  $coreResource = Mage::getSingleton('core/resource');
39
 
40
  $this->table = $coreResource->getTableName('algoliasearch/queue');
41
+ $this->logTable = $this->table.'_log';
42
+
43
  $this->db = $coreResource->getConnection('core_write');
44
 
45
  $this->config = Mage::helper('algoliasearch/config');
52
  {
53
  // Insert a row for the new job
54
  $this->db->insert($this->table, array(
55
+ 'created' => date('Y-m-d H:i:s'),
56
  'class' => $class,
57
  'method' => $method,
58
  'data' => json_encode($data),
61
  ));
62
  }
63
 
64
+ public function runCron($nbJobs = null, $force = false)
65
  {
66
+ if (!$this->config->isQueueActive() && $force === false) {
67
  return;
68
  }
69
 
70
+ $this->clearOldLogRecords();
71
+
72
+ $this->logRecord = array(
73
+ 'started' => date('Y-m-d H:i:s'),
74
+ 'processed_jobs' => 0,
75
+ 'with_empty_queue' => 0,
76
+ );
77
+
78
+ $started = time();
79
 
80
+ if ($nbJobs === null) {
81
+ $nbJobs = $this->config->getNumberOfJobToRun();
82
+ if (getenv('EMPTY_QUEUE') && getenv('EMPTY_QUEUE') == '1') {
83
+ $nbJobs = -1;
84
+
85
+ $this->logRecord['with_empty_queue'] = 1;
86
+ }
87
  }
88
 
89
  $this->run($nbJobs);
90
+
91
+ $this->logRecord['duration'] = time() - $started;
92
+
93
+ $this->db->insert($this->logTable, $this->logRecord);
94
+
95
+ $this->db->closeConnection();
96
  }
97
 
98
  public function run($maxJobs)
102
  $jobs = $this->getJobs($maxJobs, $pid);
103
 
104
  if (empty($jobs)) {
105
+ return;
106
  }
107
 
108
  // Run all reserved jobs
109
  foreach ($jobs as $job) {
110
+ // If there are some failed jobs before move, we want to skip the move
111
+ // as most probably not all products have prices reindexed
112
+ // and therefore are not indexed yet in TMP index
113
+ if ($job['method'] === 'moveProductsTmpIndex' && $this->noOfFailedJobs > 0) {
114
+ // Set pid to NULL so it's not deleted after
115
+ $this->db->query("UPDATE {$this->db->quoteIdentifier($this->table, true)} SET pid = NULL WHERE job_id = ".$job['job_id']);
116
+
117
+ continue;
118
+ }
119
+
120
  try {
121
  $model = Mage::getSingleton($job['class']);
122
  $method = $job['method'];
 
123
  $model->{$method}(new Varien_Object($job['data']));
124
+
125
+ $this->logRecord['processed_jobs'] += count($job['merged_ids']);
126
+ } catch (\Exception $e) {
127
+ $this->noOfFailedJobs++;
128
+
129
+ // Increment retries, set the job ID back to NULL
130
+ $updateQuery = "UPDATE {$this->db->quoteIdentifier($this->table, true)} SET pid = NULL, retries = retries + 1 WHERE job_id IN (".implode(', ', (array) $job['merged_ids']).")";
131
+ $this->db->query($updateQuery);
132
+
133
+ // log error information
134
  $this->logger->log("Queue processing {$job['pid']} [KO]: Mage::getSingleton({$job['class']})->{$job['method']}(".json_encode($job['data']).')');
135
  $this->logger->log(date('c').' ERROR: '.get_class($e).": '{$e->getMessage()}' in {$e->getFile()}:{$e->getLine()}\n"."Stack trace:\n".$e->getTraceAsString());
136
  }
146
 
147
  return;
148
  }
 
 
149
  }
150
 
151
  private function getJobs($maxJobs, $pid)
152
  {
153
+ // Clear jobs with crossed max retries count
154
+ $retryLimit = $this->config->getRetryLimit();
155
+ if ($retryLimit > 0) {
156
+ $where = $this->db->quoteInto('retries >= ?', $retryLimit);
157
+ $this->db->delete($this->table, $where);
158
+ } else {
159
+ $this->db->delete($this->table, 'retries > max_retries');
160
+ }
161
+
162
  $jobs = array();
163
 
164
  $limit = $maxJobs = ($maxJobs === -1) ? $this->config->getNumberOfJobToRun() : $maxJobs;
226
 
227
 
228
  if (isset($firstJobId)) {
229
+ $lastJobId = $this->maxValueInArray($jobs, 'job_id');
 
230
 
231
  // Reserve all new jobs since last run
232
  $this->db->query("UPDATE {$this->db->quoteIdentifier($this->table, true)} SET pid = ".$pid.' WHERE job_id >= '.$firstJobId." AND job_id <= $lastJobId");
239
  {
240
  foreach ($jobs as &$job) {
241
  $job['data'] = json_decode($job['data'], true);
242
+ $job['merged_ids'][] = $job['job_id'];
243
  }
244
 
245
  return $jobs;
262
  // Use the job_id of the the very last job to properly mark processed jobs
263
  $currentJob['job_id'] = max((int) $currentJob['job_id'], (int) $nextJob['job_id']);
264
 
265
+ $currentJob['merged_ids'][] = $nextJob['job_id'];
266
+
267
  if (isset($currentJob['data']['product_ids'])) {
268
  $currentJob['data']['product_ids'] = array_merge($currentJob['data']['product_ids'], $nextJob['data']['product_ids']);
 
269
  } elseif (isset($currentJob['data']['category_ids'])) {
270
  $currentJob['data']['category_ids'] = array_merge($currentJob['data']['category_ids'], $nextJob['data']['category_ids']);
 
271
  }
272
 
273
  continue;
278
 
279
  if (isset($currentJob['data']['product_ids'])) {
280
  $currentJob['data']['product_ids'] = array_unique($currentJob['data']['product_ids']);
281
+ $currentJob['data_size'] = count($currentJob['data']['product_ids']);
282
  }
283
 
284
  if (isset($currentJob['data']['category_ids'])) {
285
  $currentJob['data']['category_ids'] = array_unique($currentJob['data']['category_ids']);
286
+ $currentJob['data_size'] = count($currentJob['data']['category_ids']);
287
  }
288
 
289
  $jobs[] = $currentJob;
295
 
296
  private function sortJobs($oldJobs)
297
  {
 
 
298
  $sortedJobs = array();
299
 
300
  $tempSortableJobs = array();
391
 
392
  return array_pop($args);
393
  }
394
+
395
+ private function maxValueInArray($array, $keyToSearch)
396
+ {
397
+ $currentMax = null;
398
+
399
+ foreach ($array as $arr) {
400
+ foreach ($arr as $key => $value) {
401
+ if ($key == $keyToSearch && ($value >= $currentMax)) {
402
+ $currentMax = $value;
403
+ }
404
+ }
405
+ }
406
+
407
+ return $currentMax;
408
+ }
409
+
410
+ private function clearOldLogRecords()
411
+ {
412
+ $idsToDelete = $this->db->query("SELECT id FROM {$this->logTable} ORDER BY started DESC, id DESC LIMIT 25000, ".PHP_INT_MAX)
413
+ ->fetchAll(\PDO::FETCH_COLUMN, 0);
414
+
415
+ if ($idsToDelete) {
416
+ $this->db->query("DELETE FROM {$this->logTable} WHERE id IN (" . implode(", ", $idsToDelete) . ")");
417
+ }
418
+ }
419
  }
app/code/community/Algolia/Algoliasearch/Model/Resource/Engine.php CHANGED
@@ -22,6 +22,9 @@ class Algolia_Algoliasearch_Model_Resource_Engine extends Mage_CatalogSearch_Mod
22
  /** @var Algolia_Algoliasearch_Helper_Entity_Categoryhelper */
23
  protected $category_helper;
24
 
 
 
 
25
  /** @var Algolia_Algoliasearch_Helper_Entity_Suggestionhelper */
26
  protected $suggestion_helper;
27
 
@@ -34,6 +37,7 @@ class Algolia_Algoliasearch_Model_Resource_Engine extends Mage_CatalogSearch_Mod
34
  $this->logger = Mage::helper('algoliasearch/logger');
35
  $this->product_helper = Mage::helper('algoliasearch/entity_producthelper');
36
  $this->category_helper = Mage::helper('algoliasearch/entity_categoryhelper');
 
37
  $this->suggestion_helper = Mage::helper('algoliasearch/entity_suggestionhelper');
38
  }
39
 
@@ -92,25 +96,16 @@ class Algolia_Algoliasearch_Model_Resource_Engine extends Mage_CatalogSearch_Mod
92
  return $this;
93
  }
94
 
95
- public function rebuildPages()
96
  {
97
- /** @var Mage_Core_Model_Store $store */
98
- foreach (Mage::app()->getStores() as $store) {
99
- if ($this->config->isEnabledBackend($store->getId()) === false) {
100
- if (php_sapi_name() === 'cli') {
101
- echo '[ALGOLIA] INDEXING IS DISABLED FOR '.$this->logger->getStoreName($store->getId())."\n";
102
- }
103
-
104
- /** @var Mage_Adminhtml_Model_Session $session */
105
- $session = Mage::getSingleton('adminhtml/session');
106
- $session->addWarning('[ALGOLIA] INDEXING IS DISABLED FOR '.$this->logger->getStoreName($store->getId()));
107
-
108
- $this->logger->log('INDEXING IS DISABLED FOR '.$this->logger->getStoreName($store->getId()));
109
 
110
- continue;
 
 
 
 
111
  }
112
-
113
- $this->addToQueue('algoliasearch/observer', 'rebuildPageIndex', array('store_id' => $store->getId()), 1);
114
  }
115
  }
116
 
@@ -164,8 +159,10 @@ class Algolia_Algoliasearch_Model_Resource_Engine extends Mage_CatalogSearch_Mod
164
  $this->addToQueue('algoliasearch/observer', 'rebuildSuggestionIndex', $data, 1);
165
  }
166
 
167
- $this->addToQueue('algoliasearch/observer', 'moveStoreSuggestionIndex',
168
- array('store_id' => $store->getId()), 1);
 
 
169
  }
170
 
171
  return $this;
22
  /** @var Algolia_Algoliasearch_Helper_Entity_Categoryhelper */
23
  protected $category_helper;
24
 
25
+ /** @var Algolia_Algoliasearch_Helper_Entity_Pagehelper */
26
+ protected $page_helper;
27
+
28
  /** @var Algolia_Algoliasearch_Helper_Entity_Suggestionhelper */
29
  protected $suggestion_helper;
30
 
37
  $this->logger = Mage::helper('algoliasearch/logger');
38
  $this->product_helper = Mage::helper('algoliasearch/entity_producthelper');
39
  $this->category_helper = Mage::helper('algoliasearch/entity_categoryhelper');
40
+ $this->page_helper = Mage::helper('algoliasearch/entity_pagehelper');
41
  $this->suggestion_helper = Mage::helper('algoliasearch/entity_suggestionhelper');
42
  }
43
 
96
  return $this;
97
  }
98
 
99
+ public function rebuildPages($storeId = null, $pageIds = null)
100
  {
101
+ $storeIds = Algolia_Algoliasearch_Helper_Entity_Helper::getStores($storeId);
 
 
 
 
 
 
 
 
 
 
 
102
 
103
+ /** @var Mage_Core_Model_Store $store */
104
+ foreach ($storeIds as $storeId) {
105
+ if ($this->page_helper->shouldIndexPages($storeId) === true) {
106
+ $this->addToQueue('algoliasearch/observer', 'rebuildPageIndex',
107
+ array('store_id' => $storeId, 'page_ids' => $pageIds), 1);
108
  }
 
 
109
  }
110
  }
111
 
159
  $this->addToQueue('algoliasearch/observer', 'rebuildSuggestionIndex', $data, 1);
160
  }
161
 
162
+ if ($nb_page > 0) {
163
+ $this->addToQueue('algoliasearch/observer', 'moveStoreSuggestionIndex',
164
+ array('store_id' => $store->getId()), 1);
165
+ }
166
  }
167
 
168
  return $this;
app/code/community/Algolia/Algoliasearch/Model/Resource/Fulltext.php CHANGED
@@ -47,6 +47,10 @@ class Algolia_Algoliasearch_Model_Resource_Fulltext extends Mage_CatalogSearch_M
47
  return parent::rebuildIndex($storeId, $productIds);
48
  }
49
 
 
 
 
 
50
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
51
  /** @var Mage_Adminhtml_Model_Session $session */
52
  $session = Mage::getSingleton('adminhtml/session');
47
  return parent::rebuildIndex($storeId, $productIds);
48
  }
49
 
50
+ if ($this->config->isModuleOutputEnabled() === false) {
51
+ return parent::rebuildIndex($storeId, $productIds);
52
+ }
53
+
54
  if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) {
55
  /** @var Mage_Adminhtml_Model_Session $session */
56
  $session = Mage::getSingleton('adminhtml/session');
app/code/community/Algolia/Algoliasearch/Model/System/Config/Source/Dropdown/RetryValues.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Algolia_Algoliasearch_Model_System_Config_Source_Dropdown_RetryValues
4
+ {
5
+ public function toOptionArray()
6
+ {
7
+ return array(
8
+ array('value' => '1','label' => '1'),
9
+ array('value' => '2','label' => '2'),
10
+ array('value' => '3','label' => '3'),
11
+ array('value' => '5','label' => '5'),
12
+ array('value' => '10','label' => '10'),
13
+ array('value' => '20','label' => '20'),
14
+ array('value' => '50','label' => '50'),
15
+ array('value' => '100','label' => '100'),
16
+ array('value' => '9999999','label' => 'unlimited')
17
+ );
18
+ }
19
+ }
app/code/community/Algolia/Algoliasearch/controllers/Adminhtml/QueueController.php CHANGED
@@ -2,6 +2,11 @@
2
 
3
  class Algolia_Algoliasearch_Adminhtml_QueueController extends Mage_Adminhtml_Controller_Action
4
  {
 
 
 
 
 
5
  public function indexAction()
6
  {
7
  /** @var Algolia_Algoliasearch_Helper_Config $config */
2
 
3
  class Algolia_Algoliasearch_Adminhtml_QueueController extends Mage_Adminhtml_Controller_Action
4
  {
5
+ public function _isAllowed()
6
+ {
7
+ return true;
8
+ }
9
+
10
  public function indexAction()
11
  {
12
  /** @var Algolia_Algoliasearch_Helper_Config $config */
app/code/community/Algolia/Algoliasearch/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Algolia_Algoliasearch>
5
- <version>1.10.0</version>
6
  </Algolia_Algoliasearch>
7
  </modules>
8
  <frontend>
@@ -130,6 +130,15 @@
130
  </algolia_stockupdate>
131
  </observers>
132
  </catalog_product_save_before>
 
 
 
 
 
 
 
 
 
133
  </events>
134
  <resources>
135
  <algoliasearch_setup>
@@ -173,6 +182,7 @@
173
  <index_prefix>magento_</index_prefix>
174
  <is_popup_enabled>1</is_popup_enabled>
175
  <is_instant_enabled>0</is_instant_enabled>
 
176
  </credentials>
177
  <products>
178
  <number_product_results>9</number_product_results>
@@ -201,6 +211,7 @@
201
  <min_number_of_results>2</min_number_of_results>
202
  <display_categories_with_suggestions>1</display_categories_with_suggestions>
203
  <render_template_directives>1</render_template_directives>
 
204
  </autocomplete>
205
  <categories>
206
  <number_category_suggestions>5</number_category_suggestions>
@@ -209,9 +220,12 @@
209
  <show_cats_not_included_in_navigation>0</show_cats_not_included_in_navigation>
210
  </categories>
211
  <queue>
212
- <active>0</active>
213
  <number_of_element_by_page>100</number_of_element_by_page>
 
214
  <number_of_job_to_run>10</number_of_job_to_run>
 
 
 
215
  </queue>
216
  <image>
217
  <width>265</width>
2
  <config>
3
  <modules>
4
  <Algolia_Algoliasearch>
5
+ <version>1.11.1</version>
6
  </Algolia_Algoliasearch>
7
  </modules>
8
  <frontend>
130
  </algolia_stockupdate>
131
  </observers>
132
  </catalog_product_save_before>
133
+
134
+ <cms_page_save_before>
135
+ <observers>
136
+ <algolia_savepage>
137
+ <class>algoliasearch/observer</class>
138
+ <method>savePage</method>
139
+ </algolia_savepage>
140
+ </observers>
141
+ </cms_page_save_before>
142
  </events>
143
  <resources>
144
  <algoliasearch_setup>
182
  <index_prefix>magento_</index_prefix>
183
  <is_popup_enabled>1</is_popup_enabled>
184
  <is_instant_enabled>0</is_instant_enabled>
185
+ <use_image_adaptive>0</use_image_adaptive>
186
  </credentials>
187
  <products>
188
  <number_product_results>9</number_product_results>
211
  <min_number_of_results>2</min_number_of_results>
212
  <display_categories_with_suggestions>1</display_categories_with_suggestions>
213
  <render_template_directives>1</render_template_directives>
214
+ <debug>0</debug>
215
  </autocomplete>
216
  <categories>
217
  <number_category_suggestions>5</number_category_suggestions>
220
  <show_cats_not_included_in_navigation>0</show_cats_not_included_in_navigation>
221
  </categories>
222
  <queue>
 
223
  <number_of_element_by_page>100</number_of_element_by_page>
224
+ <active>0</active>
225
  <number_of_job_to_run>10</number_of_job_to_run>
226
+ <number_of_retries>3</number_of_retries>
227
+ <check_price_index>0</check_price_index>
228
+ <check_stock_index>0</check_stock_index>
229
  </queue>
230
  <image>
231
  <width>265</width>
app/code/community/Algolia/Algoliasearch/etc/system.xml CHANGED
@@ -4,7 +4,7 @@
4
  <algoliasearch translate="label" module="algoliasearch">
5
  <label>
6
  <![CDATA[
7
- Algolia Search 1.10.0
8
  <style>
9
  .algoliasearch-admin-menu span {
10
  padding-left: 38px !important;
@@ -183,6 +183,22 @@
183
  ]]>
184
  </comment>
185
  </is_instant_enabled>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
186
  </fields>
187
  </credentials>
188
  <autocomplete>
@@ -324,6 +340,21 @@
324
  ]]>
325
  </comment>
326
  </render_template_directives>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  </fields>
328
  </autocomplete>
329
  <instant>
@@ -714,11 +745,21 @@
714
  ]]>
715
  </comment>
716
  <fields>
 
 
 
 
 
 
 
 
 
 
717
  <active translate="label">
718
  <label>Queue Enabled</label>
719
  <frontend_type>select</frontend_type>
720
  <source_model>adminhtml/system_config_source_yesno</source_model>
721
- <sort_order>10</sort_order>
722
  <show_in_default>1</show_in_default>
723
  <show_in_website>1</show_in_website>
724
  <show_in_store>1</show_in_store>
@@ -733,21 +774,11 @@
733
  ]]>
734
  </comment>
735
  </active>
736
- <number_of_element_by_page translate="label comment">
737
- <label>Max number of element per indexing job</label>
738
- <frontend_type>text</frontend_type>
739
- <validate>validate-digits</validate>
740
- <sort_order>30</sort_order>
741
- <show_in_default>1</show_in_default>
742
- <show_in_website>1</show_in_website>
743
- <show_in_store>1</show_in_store>
744
- <comment>The max number of element by indexing job. Default value is 100.</comment>
745
- </number_of_element_by_page>
746
  <number_of_job_to_run translate="label comment">
747
  <label>Number of jobs to run each time the cron is run</label>
748
  <frontend_type>text</frontend_type>
749
  <validate>validate-digits</validate>
750
- <sort_order>40</sort_order>
751
  <show_in_default>1</show_in_default>
752
  <show_in_website>1</show_in_website>
753
  <show_in_store>1</show_in_store>
@@ -763,6 +794,55 @@
763
  <active>1</active>
764
  </depends>
765
  </number_of_job_to_run>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
766
  </fields>
767
  </queue>
768
  <analytics translate="label">
@@ -778,7 +858,7 @@
778
  <table>
779
  <tr>
780
  <td>Analytics documentation:</td>
781
- <td><a target="_blank" href="https://community.algolia.com/magento/doc/m1/analytics/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link">https://community.algolia.com/magento/faq/#why-are-images-not-showing-up</a></td>
782
  </tr>
783
  </table>
784
  <br>
4
  <algoliasearch translate="label" module="algoliasearch">
5
  <label>
6
  <![CDATA[
7
+ Algolia Search 1.11.1
8
  <style>
9
  .algoliasearch-admin-menu span {
10
  padding-left: 38px !important;
183
  ]]>
184
  </comment>
185
  </is_instant_enabled>
186
+ <use_adaptive_image translate="label comment">
187
+ <label>Replace default image by matching variation</label>
188
+ <frontend_type>select</frontend_type>
189
+ <source_model>adminhtml/system_config_source_yesno</source_model>
190
+ <sort_order>90</sort_order>
191
+ <show_in_default>1</show_in_default>
192
+ <show_in_website>1</show_in_website>
193
+ <show_in_store>1</show_in_store>
194
+ <comment>
195
+ <![CDATA[
196
+ E.g. When a customer searches for a "blue dress", Algolia will display the image associated with the blue variation instead of the default picture.
197
+ The same happens when a customer refines products by any color.
198
+ <br /><br />If a customer searches for "blue dress" and refines by "red" color, Algolia will display images for red (refined) color.
199
+ ]]>
200
+ </comment>
201
+ </use_adaptive_image>
202
  </fields>
203
  </credentials>
204
  <autocomplete>
340
  ]]>
341
  </comment>
342
  </render_template_directives>
343
+ <debug translate="label comment">
344
+ <label>Enable autocomplete menu's debug mode</label>
345
+ <frontend_type>select</frontend_type>
346
+ <source_model>adminhtml/system_config_source_yesno</source_model>
347
+ <sort_order>35</sort_order>
348
+ <show_in_default>1</show_in_default>
349
+ <show_in_website>1</show_in_website>
350
+ <show_in_store>1</show_in_store>
351
+ <comment>
352
+ <![CDATA[
353
+ When set to Yes, autocomplete menu won't disappear when clicked outside of the menu.
354
+ It's useful when you debug / style the look of autocomplete menu.
355
+ ]]>
356
+ </comment>
357
+ </debug>
358
  </fields>
359
  </autocomplete>
360
  <instant>
745
  ]]>
746
  </comment>
747
  <fields>
748
+ <number_of_element_by_page translate="label comment">
749
+ <label>Max number of element per indexing job</label>
750
+ <frontend_type>text</frontend_type>
751
+ <validate>validate-digits</validate>
752
+ <sort_order>10</sort_order>
753
+ <show_in_default>1</show_in_default>
754
+ <show_in_website>1</show_in_website>
755
+ <show_in_store>1</show_in_store>
756
+ <comment>The max number of element by indexing job. Default value is 100.</comment>
757
+ </number_of_element_by_page>
758
  <active translate="label">
759
  <label>Queue Enabled</label>
760
  <frontend_type>select</frontend_type>
761
  <source_model>adminhtml/system_config_source_yesno</source_model>
762
+ <sort_order>20</sort_order>
763
  <show_in_default>1</show_in_default>
764
  <show_in_website>1</show_in_website>
765
  <show_in_store>1</show_in_store>
774
  ]]>
775
  </comment>
776
  </active>
 
 
 
 
 
 
 
 
 
 
777
  <number_of_job_to_run translate="label comment">
778
  <label>Number of jobs to run each time the cron is run</label>
779
  <frontend_type>text</frontend_type>
780
  <validate>validate-digits</validate>
781
+ <sort_order>30</sort_order>
782
  <show_in_default>1</show_in_default>
783
  <show_in_website>1</show_in_website>
784
  <show_in_store>1</show_in_store>
794
  <active>1</active>
795
  </depends>
796
  </number_of_job_to_run>
797
+ <number_of_retries translate="label">
798
+ <label>Number of times to retry processing of queued jobs</label>
799
+ <sort_order>40</sort_order>
800
+ <frontend_type>select</frontend_type>
801
+ <comment>Select the number of times to retry events that have failed the indexes check.</comment>
802
+ <source_model>algoliasearch/system_config_source_dropdown_retryValues</source_model>
803
+ <show_in_default>1</show_in_default>
804
+ <show_in_website>1</show_in_website>
805
+ <show_in_store>1</show_in_store>
806
+ <depends>
807
+ <active>1</active>
808
+ </depends>
809
+ </number_of_retries>
810
+ <check_price_index translate="label">
811
+ <label>Should check if the prices were reindexed before pushing to Algolia?</label>
812
+ <sort_order>40</sort_order>
813
+ <frontend_type>select</frontend_type>
814
+ <comment>
815
+ <![CDATA[
816
+ Use only when on Enterprise Edition with enabled asynchronous price reindexing.<br />
817
+ If set to Yes, the queue checks if all the products which are supposed to be indexed in Algolia has reindexed prices. If they don't those products will be skipped and pushed to Algolia when they have its' prices reindexed.
818
+ ]]>
819
+ </comment>
820
+ <source_model>adminhtml/system_config_source_yesno</source_model>
821
+ <show_in_default>1</show_in_default>
822
+ <show_in_website>1</show_in_website>
823
+ <show_in_store>1</show_in_store>
824
+ <depends>
825
+ <active>1</active>
826
+ </depends>
827
+ </check_price_index>
828
+ <check_stock_index translate="label">
829
+ <label>Should check if the stock was reindexed before pushing to Algolia?</label>
830
+ <sort_order>50</sort_order>
831
+ <frontend_type>select</frontend_type>
832
+ <comment>
833
+ <![CDATA[
834
+ Use only when on Enterprise Edition with enabled asynchronous price reindexing.<br />
835
+ If set to Yes, the queue checks if all the products which are supposed to be indexed in Algolia has reindexed stock. If they don't those products will be skipped and pushed to Algolia when they have its' stock reindexed.
836
+ ]]>
837
+ </comment>
838
+ <source_model>adminhtml/system_config_source_yesno</source_model>
839
+ <show_in_default>1</show_in_default>
840
+ <show_in_website>1</show_in_website>
841
+ <show_in_store>1</show_in_store>
842
+ <depends>
843
+ <active>1</active>
844
+ </depends>
845
+ </check_stock_index>
846
  </fields>
847
  </queue>
848
  <analytics translate="label">
858
  <table>
859
  <tr>
860
  <td>Analytics documentation:</td>
861
+ <td><a target="_blank" href="https://community.algolia.com/magento/doc/m1/analytics/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link">https://community.algolia.com/magento/doc/m1/analytics/</a></td>
862
  </tr>
863
  </table>
864
  <br>
app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.7.1-1.11.1.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** @var Mage_Core_Model_Resource_Setup $installer */
4
+ $installer = $this;
5
+ $installer->startSetup();
6
+
7
+ $tableName = $installer->getTable('algoliasearch/queue');
8
+ $installer->run("ALTER TABLE `{$tableName}` ADD `created` DATETIME AFTER `job_id`;");
9
+
10
+ $installer->run("
11
+ CREATE TABLE IF NOT EXISTS `{$tableName}_log` (
12
+ `id` INT(20) NOT NULL auto_increment,
13
+ `started` DATETIME NOT NULL,
14
+ `duration` INT(20) NOT NULL,
15
+ `processed_jobs` INT NOT NULL,
16
+ `with_empty_queue` INT(1) NOT NULL,
17
+ PRIMARY KEY `id` (`id`)
18
+ ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 AUTO_INCREMENT=1;
19
+ ");
20
+
21
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/algoliasearch.xml CHANGED
@@ -1,5 +1,15 @@
1
  <?xml version="1.0"?>
2
  <layout>
 
 
 
 
 
 
 
 
 
 
3
  <algolia_bundle_handle>
4
  <reference name="head">
5
  <action method="addJs"><script>algoliasearch/internals/adminhtml/algoliaAdminBundle.min.js</script></action>
1
  <?xml version="1.0"?>
2
  <layout>
3
+ <default>
4
+ <reference name="head">
5
+ <action method="addCss"><stylesheet>algoliasearch/algoliasearch.css</stylesheet></action>
6
+ </reference>
7
+
8
+ <reference name="notifications">
9
+ <block type="algoliasearch/adminhtml_notifications" name="algoliasearch_notifications" template="algoliasearch/notifications.phtml"/>
10
+ </reference>
11
+ </default>
12
+
13
  <algolia_bundle_handle>
14
  <reference name="head">
15
  <action method="addJs"><script>algoliasearch/internals/adminhtml/algoliaAdminBundle.min.js</script></action>
app/design/adminhtml/default/default/template/algoliasearch/notifications.phtml ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** @var Algolia_Algoliasearch_Block_Adminhtml_Notifications $this */
4
+
5
+ $queueInfo = $this->getQueueInfo();
6
+
7
+ ?>
8
+
9
+ <div class="notification-global algoliasearch-queue-notification"> <!-- TODO FIX the SKIN URL -->
10
+ <strong>Algolia Search</strong> -
11
+ <?php if($queueInfo['isEnabled'] === true):?>
12
+ <strong>
13
+ <a href="<?php echo $this->getConfigurationUrl(); ?>">Indexing queue</a> information:
14
+ </strong>
15
+
16
+ Number of queued jobs: <strong><?php echo $queueInfo['currentSize']; ?></strong>,
17
+
18
+ <?php if ($queueInfo['currentSize'] > 0): ?>
19
+ all queued jobs will be processed in appr. <strong><?php echo $queueInfo['eta']; ?></strong>,
20
+ <?php endif; ?>
21
+
22
+ more information about how the indexing queue works you can find in the documentation: <a href="https://community.algolia.com/magento/doc/m1/indexing/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link#general-information" target="_blank">Indexing queue</a>
23
+ <?php else: ?>
24
+ <strong>
25
+ <a href="<?php echo $this->getConfigurationUrl(); ?>">Indexing queue</a> is not enabled.
26
+ </strong>
27
+
28
+ It's highly recommended to enable it, especially if you are on production environment. You can learn how to enable the index queue in the documentation: <a href="https://community.algolia.com/magento/doc/m1/indexing/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link#general-information" target="_blank">Indexing queue</a>
29
+ <?php endif; ?>
30
+ </div>
app/design/frontend/base/default/template/algoliasearch/.DS_Store ADDED
Binary file
app/design/frontend/base/default/template/algoliasearch/internals/configuration.phtml CHANGED
@@ -213,6 +213,7 @@ $algoliaJsConfig = array(
213
  'nbOfCategoriesSuggestions' => $config->getNumberOfCategoriesSuggestions(),
214
  'nbOfQueriesSuggestions' => $config->getNumberOfQueriesSuggestions(),
215
  'displaySuggestionsCategories' => $config->displaySuggestionsCategories(),
 
216
  ),
217
  'extensionVersion' => $config->getExtensionVersion(),
218
  'applicationId' => $config->getApplicationID(),
@@ -247,6 +248,7 @@ $algoliaJsConfig = array(
247
  'showSuggestionsOnNoResultsPage' => $config->showSuggestionsOnNoResultsPage(),
248
  'baseUrl' => $baseUrl,
249
  'popularQueries' => $config->getPopularQueries(),
 
250
  'urls' => array(
251
  'logo' => $this->getSkinUrl('algoliasearch/search-by-algolia.svg'),
252
  ),
213
  'nbOfCategoriesSuggestions' => $config->getNumberOfCategoriesSuggestions(),
214
  'nbOfQueriesSuggestions' => $config->getNumberOfQueriesSuggestions(),
215
  'displaySuggestionsCategories' => $config->displaySuggestionsCategories(),
216
+ 'isDebugEnabled' => $config->isAutocompleteDebugEnabled(),
217
  ),
218
  'extensionVersion' => $config->getExtensionVersion(),
219
  'applicationId' => $config->getApplicationID(),
248
  'showSuggestionsOnNoResultsPage' => $config->showSuggestionsOnNoResultsPage(),
249
  'baseUrl' => $baseUrl,
250
  'popularQueries' => $config->getPopularQueries(),
251
+ 'useAdaptiveImage' => $config->useAdaptiveImage(),
252
  'urls' => array(
253
  'logo' => $this->getSkinUrl('algoliasearch/search-by-algolia.svg'),
254
  ),
app/etc/modules/Algolia_Algoliasearch.xml CHANGED
@@ -4,7 +4,7 @@
4
  <Algolia_Algoliasearch>
5
  <active>true</active>
6
  <codePool>community</codePool>
7
- <version>1.10.0</version>
8
  </Algolia_Algoliasearch>
9
  </modules>
10
  </config>
4
  <Algolia_Algoliasearch>
5
  <active>true</active>
6
  <codePool>community</codePool>
7
+ <version>1.11.1</version>
8
  </Algolia_Algoliasearch>
9
  </modules>
10
  </config>
js/algoliasearch/.DS_Store CHANGED
Binary file
js/algoliasearch/autocomplete.js CHANGED
@@ -68,7 +68,7 @@ document.addEventListener("DOMContentLoaded", function(event) {
68
  dropdownMenu: '#menu-template'
69
  },
70
  dropdownMenuContainer: "#algolia-autocomplete-container",
71
- debug: false
72
  };
73
 
74
  if (isMobile() === true) {
68
  dropdownMenu: '#menu-template'
69
  },
70
  dropdownMenuContainer: "#algolia-autocomplete-container",
71
+ debug: algoliaConfig.autocomplete.isDebugEnabled
72
  };
73
 
74
  if (isMobile() === true) {
js/algoliasearch/instantsearch.js CHANGED
@@ -59,6 +59,22 @@ document.addEventListener("DOMContentLoaded", function (event) {
59
  }
60
  };
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  if (typeof algoliaHookBeforeInstantsearchInit === 'function') {
63
  instantsearchOptions = algoliaHookBeforeInstantsearchInit(instantsearchOptions);
64
  }
@@ -115,13 +131,6 @@ document.addEventListener("DOMContentLoaded", function (event) {
115
  data.helper.toggleRefine(algoliaConfig.request.refinementKey, algoliaConfig.request.refinementValue);
116
  }
117
 
118
- if (algoliaConfig.areCategoriesInFacets === false && algoliaConfig.request.path.length > 0) {
119
- var facet = 'categories.level' + algoliaConfig.request.level;
120
-
121
- data.helper.state.facets.push(facet);
122
- data.helper.toggleRefine(facet, algoliaConfig.request.path);
123
- }
124
-
125
  data.helper.setPage(page);
126
  },
127
  render: function (data) {
@@ -227,7 +236,7 @@ document.addEventListener("DOMContentLoaded", function (event) {
227
  transformData: {
228
  allItems: function (results) {
229
  for (var i = 0; i < results.hits.length; i++) {
230
- results.hits[i] = transformHit(results.hits[i], algoliaConfig.priceKey);
231
  results.hits[i].isAddToCartEnabled = algoliaConfig.instant.isAddToCartEnabled;
232
 
233
  results.hits[i].algoliaConfig = window.algoliaConfig;
@@ -462,14 +471,6 @@ document.addEventListener("DOMContentLoaded", function (event) {
462
  search = algoliaHookAfterInstantsearchStart(search);
463
  }
464
 
465
- if (algoliaConfig.request.path.length > 0
466
- && 'categories.level0' in search.helper.state.hierarchicalFacetsRefinements === false
467
- && 'categories.level0' in search.helper.state.facetsRefinements === false) {
468
- var page = search.helper.state.page;
469
-
470
- search.helper.toggleRefinement('categories.level0', algoliaConfig.request.path).setPage(page).search();
471
- }
472
-
473
  handleInputCrossInstant($(instant_selector));
474
 
475
  var instant_search_bar = $(instant_selector);
59
  }
60
  };
61
 
62
+ if (algoliaConfig.request.path.length > 0 && window.location.hash.indexOf('categories.level0') === -1) {
63
+ if (algoliaConfig.areCategoriesInFacets) {
64
+ instantsearchOptions.searchParameters = {
65
+ hierarchicalFacetsRefinements: {
66
+ 'categories.level0': [algoliaConfig.request.path]
67
+ }
68
+ };
69
+ } else {
70
+ instantsearchOptions.searchParameters = {
71
+ facetsRefinements: { }
72
+ };
73
+
74
+ instantsearchOptions.searchParameters['facetsRefinements']['categories.level' + algoliaConfig.request.level] = [algoliaConfig.request.path];
75
+ }
76
+ }
77
+
78
  if (typeof algoliaHookBeforeInstantsearchInit === 'function') {
79
  instantsearchOptions = algoliaHookBeforeInstantsearchInit(instantsearchOptions);
80
  }
131
  data.helper.toggleRefine(algoliaConfig.request.refinementKey, algoliaConfig.request.refinementValue);
132
  }
133
 
 
 
 
 
 
 
 
134
  data.helper.setPage(page);
135
  },
136
  render: function (data) {
236
  transformData: {
237
  allItems: function (results) {
238
  for (var i = 0; i < results.hits.length; i++) {
239
+ results.hits[i] = transformHit(results.hits[i], algoliaConfig.priceKey, search.helper);
240
  results.hits[i].isAddToCartEnabled = algoliaConfig.instant.isAddToCartEnabled;
241
 
242
  results.hits[i].algoliaConfig = window.algoliaConfig;
471
  search = algoliaHookAfterInstantsearchStart(search);
472
  }
473
 
 
 
 
 
 
 
 
 
474
  handleInputCrossInstant($(instant_selector));
475
 
476
  var instant_search_bar = $(instant_selector);
js/algoliasearch/internals/.DS_Store CHANGED
Binary file
js/algoliasearch/internals/adminhtml/admin_scripts.js CHANGED
@@ -34,7 +34,13 @@ algoliaAdminBundle.$(function($) {
34
  }
35
  });
36
 
37
- $.getJSON('/index.php/admin/queue', function(queueInfo) {
 
 
 
 
 
 
38
  var message = '<span style="font-size: 25px; position: relative; top: 5px;">⚠</span> ' +
39
  '<strong style="font-size: 1.15em;"><a href="https://community.algolia.com/magento/doc/m1/indexing/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link#general-information" target="_blank">Indexing queue</a> is not enabled</strong><br>' +
40
  'It\'s highly recommended to enable it, especially if you are on production environment. ' +
@@ -74,7 +80,7 @@ algoliaAdminBundle.$(function($) {
74
  }
75
  }, 200);
76
 
77
- $.getJSON('/index.php/admin/queue/truncate', function(payload) {
78
  window.clearInterval(dots);
79
 
80
  if (payload.status === 'ok') {
34
  }
35
  });
36
 
37
+ // Queue info
38
+
39
+ var url = window.location.href,
40
+ position = url.indexOf('/system_config/edit/'),
41
+ baseUrl = url.substring(0, position);
42
+
43
+ $.getJSON(baseUrl + '/queue', function(queueInfo) {
44
  var message = '<span style="font-size: 25px; position: relative; top: 5px;">⚠</span> ' +
45
  '<strong style="font-size: 1.15em;"><a href="https://community.algolia.com/magento/doc/m1/indexing/?utm_source=magento&utm_medium=extension&utm_campaign=magento_1&utm_term=shop-owner&utm_content=doc-link#general-information" target="_blank">Indexing queue</a> is not enabled</strong><br>' +
46
  'It\'s highly recommended to enable it, especially if you are on production environment. ' +
80
  }
81
  }, 200);
82
 
83
+ $.getJSON(baseUrl + '/queue/truncate', function(payload) {
84
  window.clearInterval(dots);
85
 
86
  if (payload.status === 'ok') {
js/algoliasearch/internals/frontend/common.js CHANGED
@@ -8,7 +8,7 @@ document.addEventListener("DOMContentLoaded", function (e) {
8
  return check;
9
  };
10
 
11
- window.transformHit = function (hit, price_key) {
12
  if (Array.isArray(hit.categories)) {
13
  hit.categories = hit.categories.join(', ');
14
  }
@@ -20,7 +20,19 @@ document.addEventListener("DOMContentLoaded", function (e) {
20
 
21
  hit.categories_without_path = hit.categories_without_path.join(', ');
22
  }
23
-
 
 
 
 
 
 
 
 
 
 
 
 
24
  if (Array.isArray(hit.color)) {
25
  var colors = [];
26
 
@@ -28,16 +40,42 @@ document.addEventListener("DOMContentLoaded", function (e) {
28
  if (color.matchLevel === 'none') {
29
  return;
30
  }
31
-
32
  colors.push(color.value);
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  });
34
 
35
  colors = colors.join(', ');
36
 
37
- hit._highlightResult.color = {value: colors};
38
  }
39
  else if (hit._highlightResult.color && hit._highlightResult.color.matchLevel === 'none') {
40
- hit._highlightResult.color = {value: ''};
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  }
42
 
43
  if (hit._highlightResult.color && hit._highlightResult.color.value && hit.categories_without_path) {
@@ -46,7 +84,6 @@ document.addEventListener("DOMContentLoaded", function (e) {
46
  }
47
  }
48
 
49
-
50
  if (Array.isArray(hit._highlightResult.name)) {
51
  hit._highlightResult.name = hit._highlightResult.name[0];
52
  }
8
  return check;
9
  };
10
 
11
+ window.transformHit = function (hit, price_key, helper) {
12
  if (Array.isArray(hit.categories)) {
13
  hit.categories = hit.categories.join(', ');
14
  }
20
 
21
  hit.categories_without_path = hit.categories_without_path.join(', ');
22
  }
23
+
24
+ var matchedColors = [];
25
+
26
+ if (helper && algoliaConfig.useAdaptiveImage === true) {
27
+ if (hit.images_data && helper.state.facetsRefinements.color) {
28
+ matchedColors = helper.state.disjunctiveFacetsRefinements.color.slice(0); // slice to clone
29
+ }
30
+
31
+ if (hit.images_data && helper.state.disjunctiveFacetsRefinements.color) {
32
+ matchedColors = helper.state.disjunctiveFacetsRefinements.color.slice(0); // slice to clone
33
+ }
34
+ }
35
+
36
  if (Array.isArray(hit.color)) {
37
  var colors = [];
38
 
40
  if (color.matchLevel === 'none') {
41
  return;
42
  }
43
+
44
  colors.push(color.value);
45
+
46
+ if (algoliaConfig.useAdaptiveImage === true) {
47
+ var re = /<em>(.*?)<\/em>/g;
48
+ var matchedWords = color.value.match(re).map(function (val) {
49
+ return val.replace(/<\/?em>/g, '');
50
+ });
51
+
52
+ var matchedColor = matchedWords.join(' ');
53
+
54
+ if (hit.images_data && color.fullyHighlighted && color.fullyHighlighted === true) {
55
+ matchedColors.push(matchedColor);
56
+ }
57
+ }
58
  });
59
 
60
  colors = colors.join(', ');
61
 
62
+ hit._highlightResult.color = { value: colors };
63
  }
64
  else if (hit._highlightResult.color && hit._highlightResult.color.matchLevel === 'none') {
65
+ hit._highlightResult.color = { value: '' };
66
+ }
67
+
68
+ if (algoliaConfig.useAdaptiveImage === true) {
69
+ $.each(matchedColors, function (i, color) {
70
+ color = color.toLowerCase();
71
+
72
+ if (hit.images_data[color]) {
73
+ hit.image_url = hit.images_data[color];
74
+ hit.thumbnail_url = hit.images_data[color];
75
+
76
+ return false;
77
+ }
78
+ });
79
  }
80
 
81
  if (hit._highlightResult.color && hit._highlightResult.color.value && hit.categories_without_path) {
84
  }
85
  }
86
 
 
87
  if (Array.isArray(hit._highlightResult.name)) {
88
  hit._highlightResult.name = hit._highlightResult.name[0];
89
  }
lib/AlgoliaSearch/AlgoliaConnectionException.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright (c) 2013 Algolia
5
+ * http://www.algolia.com/
6
+ *
7
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ * of this software and associated documentation files (the "Software"), to deal
9
+ * in the Software without restriction, including without limitation the rights
10
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ * copies of the Software, and to permit persons to whom the Software is
12
+ * furnished to do so, subject to the following conditions:
13
+ *
14
+ * The above copyright notice and this permission notice shall be included in
15
+ * all copies or substantial portions of the Software.
16
+ *
17
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ * THE SOFTWARE.
24
+ */
25
+
26
+ namespace AlgoliaSearch;
27
+
28
+ class AlgoliaConnectionException extends AlgoliaException
29
+ {
30
+ }
lib/AlgoliaSearch/Client.php CHANGED
@@ -712,7 +712,6 @@ class Client
712
  */
713
  public static function generateSecuredApiKey($privateApiKey, $query, $userToken = null)
714
  {
715
- $urlEncodedQuery = '';
716
  if (is_array($query)) {
717
  $queryParameters = array();
718
  if (array_keys($query) !== array_keys(array_keys($query))) {
@@ -820,7 +819,7 @@ class Client
820
  }
821
  }
822
  }
823
- throw new AlgoliaException('Hosts unreachable: '.implode(',', $exceptions));
824
  }
825
 
826
  /**
@@ -989,9 +988,9 @@ class Client
989
  curl_close($curlHandle);
990
 
991
  if (intval($http_status / 100) == 4) {
992
- throw new AlgoliaException(isset($answer['message']) ? $answer['message'] : $http_status.' error');
993
  } elseif (intval($http_status / 100) != 2) {
994
- throw new \Exception($http_status.': '.$response);
995
  }
996
 
997
  return $answer;
@@ -1084,14 +1083,14 @@ class Client
1084
  }
1085
 
1086
  /**
1087
- * @param string $appId
1088
- * @param string $apiKey
1089
- * @param array $hostsArray
1090
- * @param array $options
1091
  *
1092
  * @return PlacesIndex
1093
  */
1094
- public static function initPlaces($appId, $apiKey, $hostsArray = null, $options = array())
1095
  {
1096
  $options['placesEnabled'] = true;
1097
  $client = new static($appId, $apiKey, $hostsArray, $options);
712
  */
713
  public static function generateSecuredApiKey($privateApiKey, $query, $userToken = null)
714
  {
 
715
  if (is_array($query)) {
716
  $queryParameters = array();
717
  if (array_keys($query) !== array_keys(array_keys($query))) {
819
  }
820
  }
821
  }
822
+ throw new AlgoliaConnectionException('Hosts unreachable: '.implode(',', $exceptions));
823
  }
824
 
825
  /**
988
  curl_close($curlHandle);
989
 
990
  if (intval($http_status / 100) == 4) {
991
+ throw new AlgoliaException(isset($answer['message']) ? $answer['message'] : $http_status.' error', $http_status);
992
  } elseif (intval($http_status / 100) != 2) {
993
+ throw new \Exception($http_status.': '.$response, $http_status);
994
  }
995
 
996
  return $answer;
1083
  }
1084
 
1085
  /**
1086
+ * @param string|null $appId
1087
+ * @param string|null $apiKey
1088
+ * @param array|null $hostsArray
1089
+ * @param array $options
1090
  *
1091
  * @return PlacesIndex
1092
  */
1093
+ public static function initPlaces($appId = null, $apiKey = null, $hostsArray = null, $options = array())
1094
  {
1095
  $options['placesEnabled'] = true;
1096
  $client = new static($appId, $apiKey, $hostsArray, $options);
lib/AlgoliaSearch/ClientContext.php CHANGED
@@ -82,15 +82,15 @@ class ClientContext
82
  private $failingHostsCache;
83
 
84
  /**
85
- * @param string $applicationID
86
- * @param string $apiKey
87
- * @param array $hostsArray
88
- * @param bool $placesEnabled
89
- * @param FailingHostsCache $failingHostsCache
90
  *
91
  * @throws Exception
92
  */
93
- public function __construct($applicationID, $apiKey, $hostsArray, $placesEnabled = false, FailingHostsCache $failingHostsCache = null)
94
  {
95
  // connect timeout of 1s by default
96
  $this->connectTimeout = 1;
@@ -112,11 +112,11 @@ class ClientContext
112
  $this->writeHostsArray = $this->getDefaultWriteHosts();
113
  }
114
 
115
- if ($this->applicationID == null || mb_strlen($this->applicationID) == 0) {
116
  throw new Exception('AlgoliaSearch requires an applicationID.');
117
  }
118
 
119
- if ($this->apiKey == null || mb_strlen($this->apiKey) == 0) {
120
  throw new Exception('AlgoliaSearch requires an apiKey.');
121
  }
122
 
82
  private $failingHostsCache;
83
 
84
  /**
85
+ * @param string|null $applicationID
86
+ * @param string|null $apiKey
87
+ * @param array|null $hostsArray
88
+ * @param bool $placesEnabled
89
+ * @param FailingHostsCache|null $failingHostsCache
90
  *
91
  * @throws Exception
92
  */
93
+ public function __construct($applicationID = null, $apiKey = null, $hostsArray = null, $placesEnabled = false, FailingHostsCache $failingHostsCache = null)
94
  {
95
  // connect timeout of 1s by default
96
  $this->connectTimeout = 1;
112
  $this->writeHostsArray = $this->getDefaultWriteHosts();
113
  }
114
 
115
+ if (($this->applicationID == null || mb_strlen($this->applicationID) == 0) && $placesEnabled === false) {
116
  throw new Exception('AlgoliaSearch requires an applicationID.');
117
  }
118
 
119
+ if (($this->apiKey == null || mb_strlen($this->apiKey) == 0) && $placesEnabled === false) {
120
  throw new Exception('AlgoliaSearch requires an apiKey.');
121
  }
122
 
lib/AlgoliaSearch/Index.php CHANGED
@@ -383,7 +383,22 @@ class Index
383
  return $this->batch($requests);
384
  }
385
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
386
  /**
 
387
  * Delete all objects matching a query.
388
  *
389
  * @param string $query the query string
@@ -1505,6 +1520,142 @@ class Index
1505
  return $this->searchForFacetValues($facetName, $facetQuery, $query);
1506
  }
1507
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1508
  /**
1509
  * @param string $name
1510
  * @param array $arguments
@@ -1521,6 +1672,6 @@ class Index
1521
  return call_user_func_array(array($this, 'doBcBrowse'), $arguments);
1522
  }
1523
 
1524
- return;
1525
  }
1526
  }
383
  return $this->batch($requests);
384
  }
385
 
386
+ public function deleteBy(array $args)
387
+ {
388
+ return $this->client->request(
389
+ $this->context,
390
+ 'POST',
391
+ '/1/indexes/'.$this->urlIndexName.'/deleteByQuery',
392
+ null,
393
+ array('params' => $this->client->buildQuery($args)),
394
+ $this->context->writeHostsArray,
395
+ $this->context->connectTimeout,
396
+ $this->context->readTimeout
397
+ );
398
+ }
399
+
400
  /**
401
+ * @deprecated use `deleteBy()` instead.
402
  * Delete all objects matching a query.
403
  *
404
  * @param string $query the query string
1520
  return $this->searchForFacetValues($facetName, $facetQuery, $query);
1521
  }
1522
 
1523
+ /**
1524
+ * @param $params
1525
+ *
1526
+ * @return mixed
1527
+ *
1528
+ * @throws AlgoliaException
1529
+ */
1530
+ public function searchRules(array $params = array())
1531
+ {
1532
+ return $this->client->request(
1533
+ $this->context,
1534
+ 'POST',
1535
+ '/1/indexes/'.$this->urlIndexName.'/rules/search',
1536
+ null,
1537
+ $params,
1538
+ $this->context->readHostsArray,
1539
+ $this->context->connectTimeout,
1540
+ $this->context->readTimeout
1541
+ );
1542
+ }
1543
+
1544
+ /**
1545
+ * @param $objectID
1546
+ *
1547
+ * @return mixed
1548
+ *
1549
+ * @throws AlgoliaException
1550
+ */
1551
+ public function getRule($objectID)
1552
+ {
1553
+ return $this->client->request(
1554
+ $this->context,
1555
+ 'GET',
1556
+ '/1/indexes/'.$this->urlIndexName.'/rules/'.urlencode($objectID),
1557
+ null,
1558
+ null,
1559
+ $this->context->readHostsArray,
1560
+ $this->context->connectTimeout,
1561
+ $this->context->readTimeout
1562
+ );
1563
+ }
1564
+
1565
+ /**
1566
+ * @param $objectID
1567
+ * @param $forwardToReplicas
1568
+ *
1569
+ * @return mixed
1570
+ *
1571
+ * @throws AlgoliaException
1572
+ */
1573
+ public function deleteRule($objectID, $forwardToReplicas = false)
1574
+ {
1575
+ return $this->client->request(
1576
+ $this->context,
1577
+ 'DELETE',
1578
+ '/1/indexes/'.$this->urlIndexName.'/rules/'.urlencode($objectID).'?forwardToReplicas='.($forwardToReplicas ? 'true' : 'false'),
1579
+ null,
1580
+ null,
1581
+ $this->context->writeHostsArray,
1582
+ $this->context->connectTimeout,
1583
+ $this->context->readTimeout
1584
+ );
1585
+ }
1586
+
1587
+ /**
1588
+ * @param bool $forwardToReplicas
1589
+ *
1590
+ * @return mixed
1591
+ *
1592
+ * @throws AlgoliaException
1593
+ */
1594
+ public function clearRules($forwardToReplicas = false)
1595
+ {
1596
+ return $this->client->request(
1597
+ $this->context,
1598
+ 'POST',
1599
+ '/1/indexes/'.$this->urlIndexName.'/rules/clear?forwardToReplicas='.($forwardToReplicas ? 'true' : 'false'),
1600
+ null,
1601
+ null,
1602
+ $this->context->writeHostsArray,
1603
+ $this->context->connectTimeout,
1604
+ $this->context->readTimeout
1605
+ );
1606
+ }
1607
+
1608
+ /**
1609
+ * @param $rules
1610
+ * @param bool $forwardToReplicas
1611
+ * @param bool $clearExistingRules
1612
+ *
1613
+ * @return mixed
1614
+ *
1615
+ * @throws AlgoliaException
1616
+ */
1617
+ public function batchRules($rules, $forwardToReplicas = false, $clearExistingRules = false)
1618
+ {
1619
+ return $this->client->request(
1620
+ $this->context,
1621
+ 'POST',
1622
+ '/1/indexes/'.$this->urlIndexName.'/rules/batch?clearExistingRules='.($clearExistingRules ? 'true' : 'false')
1623
+ .'&forwardToReplicas='.($forwardToReplicas ? 'true' : 'false'),
1624
+ null,
1625
+ $rules,
1626
+ $this->context->writeHostsArray,
1627
+ $this->context->connectTimeout,
1628
+ $this->context->readTimeout
1629
+ );
1630
+ }
1631
+
1632
+ /**
1633
+ * @param $objectID
1634
+ * @param $content
1635
+ * @param bool $forwardToReplicas
1636
+ *
1637
+ * @return mixed
1638
+ *
1639
+ * @throws AlgoliaException
1640
+ */
1641
+ public function saveRule($objectID, $content, $forwardToReplicas = false)
1642
+ {
1643
+ if (!isset($content['objectID'])) {
1644
+ $content['objectID'] = $objectID;
1645
+ }
1646
+
1647
+ return $this->client->request(
1648
+ $this->context,
1649
+ 'PUT',
1650
+ '/1/indexes/'.$this->urlIndexName.'/rules/'.urlencode($objectID).'?forwardToReplicas='.($forwardToReplicas ? 'true' : 'false'),
1651
+ null,
1652
+ $content,
1653
+ $this->context->writeHostsArray,
1654
+ $this->context->connectTimeout,
1655
+ $this->context->readTimeout
1656
+ );
1657
+ }
1658
+
1659
  /**
1660
  * @param string $name
1661
  * @param array $arguments
1672
  return call_user_func_array(array($this, 'doBcBrowse'), $arguments);
1673
  }
1674
 
1675
+ throw new \BadMethodCallException(sprintf('No method named %s was found.', $name));
1676
  }
1677
  }
lib/AlgoliaSearch/Version.php CHANGED
@@ -29,7 +29,7 @@ namespace AlgoliaSearch;
29
 
30
  class Version
31
  {
32
- const VALUE = '1.17.0';
33
 
34
  public static $custom_value = '';
35
 
29
 
30
  class Version
31
  {
32
+ const VALUE = '1.19.0';
33
 
34
  public static $custom_value = '';
35
 
lib/AlgoliaSearch/loader.php CHANGED
@@ -25,14 +25,15 @@
25
  */
26
 
27
  require_once __DIR__.'/AlgoliaException.php';
 
28
  require_once __DIR__.'/Client.php';
29
  require_once __DIR__.'/ClientContext.php';
 
 
30
  require_once __DIR__.'/Index.php';
31
  require_once __DIR__.'/IndexBrowser.php';
 
 
32
  require_once __DIR__.'/PlacesIndex.php';
33
  require_once __DIR__.'/SynonymType.php';
34
  require_once __DIR__.'/Version.php';
35
- require_once __DIR__.'/Json.php';
36
- require_once __DIR__.'/FailingHostsCache.php';
37
- require_once __DIR__.'/FileFailingHostsCache.php';
38
- require_once __DIR__.'/InMemoryFailingHostsCache.php';
25
  */
26
 
27
  require_once __DIR__.'/AlgoliaException.php';
28
+ require_once __DIR__.'/AlgoliaConnectionException.php';
29
  require_once __DIR__.'/Client.php';
30
  require_once __DIR__.'/ClientContext.php';
31
+ require_once __DIR__.'/FailingHostsCache.php';
32
+ require_once __DIR__.'/FileFailingHostsCache.php';
33
  require_once __DIR__.'/Index.php';
34
  require_once __DIR__.'/IndexBrowser.php';
35
+ require_once __DIR__.'/InMemoryFailingHostsCache.php';
36
+ require_once __DIR__.'/Json.php';
37
  require_once __DIR__.'/PlacesIndex.php';
38
  require_once __DIR__.'/SynonymType.php';
39
  require_once __DIR__.'/Version.php';
 
 
 
 
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>algoliasearch</name>
4
- <version>1.10.0</version>
5
  <stability>stable</stability>
6
  <license uri="https://github.com/algolia/algoliasearch-magento/blob/master/LICENSE.txt">MIT</license>
7
  <channel>community</channel>
@@ -15,9 +15,9 @@
15
  </description>
16
  <notes>Change Log: https://github.com/algolia/algoliasearch-magento/blob/master/CHANGELOG.md</notes>
17
  <authors><author><name>Algolia Team</name><user>algolia</user><email>support@algolia.com</email></author></authors>
18
- <date>2017-06-12</date>
19
- <time>11:10:56</time>
20
- <contents><target name="mageetc"><dir name="modules"><file name="Algolia_Algoliasearch.xml" hash="f8a8f988360c15fbaf5e81b9ed584a66"/></dir></target><target name="magecommunity"><dir name="Algolia"><dir name="Algoliasearch"><dir name="Block"><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="AbstractField.php" hash="c5b2a65b11d5993e385234367689c10d"/><file name="AdditionalSections.php" hash="f8f8e2d9385b8aa3dcc79987a832d284"/><file name="CategoryAdditionalAttributes.php" hash="cec9f23859bfd3328305dafcbec9cf68"/><file name="CustomRankingCategoryAttributes.php" hash="90e976e6c636d3df2f13cd843e2184fa"/><file name="CustomRankingProductAttributes.php" hash="7540e89be193568c069b21d225964be7"/><file name="ExcludedPages.php" hash="0119009da0f9b5daef8fd66854ae0661"/><file name="Facets.php" hash="893e9599b639593ed6897a27edb8d7e3"/><file name="OnewaySynonyms.php" hash="f1ff6ae2e8bc4cc61238e399564d46b6"/><file name="ProductAdditionalAttributes.php" hash="5eed1b4abcb3d51f35702bdf0743ee61"/><file name="Select.php" hash="e9521a9c869b427bca0fe57ea92288a1"/><file name="Sorts.php" hash="c40feb1c0adfc303f96ce8ca47724a19"/><file name="Synonyms.php" hash="ee555973c7c2f385240b168cd58047e5"/></dir></dir></dir></dir></dir><dir name="Helper"><file name="Algoliahelper.php" hash="a8c8073b9b00ae235931f9bcd288d230"/><file name="Config.php" hash="d34c99602bfba59a1847a703544f6500"/><file name="Data.php" hash="f22e5233667e5c974fa69f3ac5cc7b8c"/><dir name="Entity"><file name="Additionalsectionshelper.php" hash="12017b4c8dce6eda8f8ceb984cfa5e53"/><file name="Categoryhelper.php" hash="e878300df61d2326b6f73044a9e1b974"/><file name="Helper.php" hash="ca6845f2b25da13f524daa573c3c0687"/><file name="Pagehelper.php" hash="adc2a79612e2284f4ccad1b4db36e944"/><file name="Producthelper.php" hash="3f39446a49bb6a5176d429a9b1500eea"/><file name="Suggestionhelper.php" hash="cb40a85330cd8dc59b4d1c647b124899"/></dir><file name="Image.php" hash="5c8aba6fd77c0c0796a8ac67f9769c84"/><file name="Logger.php" hash="9f1d1ceb9059a98746aa9fd473549449"/><file name=".DS_Store" hash="45eb27e8591a0f709d87531296fcf1d7"/></dir><dir name="Model"><dir name="Indexer"><file name="Abstract.php" hash="9f442576c0cd25d70c5a2bc36c1ad535"/><file name="Algolia.php" hash="862887c085e701eabde47e8f9b540585"/><file name="Algoliaadditionalsections.php" hash="bb065ba1adc4fef1e820fc7baa88ce7f"/><file name="Algoliacategories.php" hash="49b00c33b47a349d34c19281ab9e0215"/><file name="Algoliapages.php" hash="c782fb36d45b478a41918abb98a869d4"/><file name="Algoliaqueuerunner.php" hash="e2cd5b4022e5003367e6c81f0912b783"/><file name="Algoliasuggestions.php" hash="069aeb9955aef734ebd3fa969d634865"/></dir><file name="Observer.php" hash="c70e434ffd46822036110ba40d563cec"/><file name="Queue.php" hash="6e27922cddf20ef8092a6a9fe05be1e3"/><dir name="Resource"><file name="Engine.php" hash="c76d008c4f80feb1fb1fcaafecf42d9a"/><dir name="Fulltext"><file name="Collection.php" hash="e3c8a13d9a034fcd1aa40e2e336208a0"/></dir><file name="Fulltext.php" hash="b662e692f0a32428764f15f7db2b07d0"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="ExtraSettings.php" hash="d1d67d01841dda9660031ea258f4fbf0"/><dir name="Serialized"><file name="Array.php" hash="6492ba56f58b26cebc6d826ba3502779"/></dir><file name="SynonymsFile.php" hash="12b218765f015ea31f03da822f4c2ca5"/></dir></dir><file name="Imagetype.php" hash="1391d49853b94714080de07fc662a831"/><file name="IndexVisibility.php" hash="b4d685a15371f59796fbe12db0f2dce3"/><file name="Removewords.php" hash="9b7d40d7ccf11d6d5fa101c8b06c5b9e"/></dir></dir><dir name="bin"><file name="dump.php" hash="fc7e65743142c494969eb9b995c1e0a1"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="QueueController.php" hash="9d13c628cfbd5e18fd410111b587e56b"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="07edd7bca541d4dbeba73c2b70ec53a2"/><file name="config.xml" hash="34cf73892fb1a7fdce1085f14d31e7f3"/><file name="system.xml" hash="16efefd13c8b0a468f8062a087bd4633"/></dir><dir name="sql"><dir name="algoliasearch_setup"><file name="mysql4-install-0.1.0.php" hash="561f4f9e9f7021061964330a6c1eccec"/><file name="mysql4-upgrade-0.1.0-1.4.8.php" hash="1fae6deaf608f812844c8639b178cbc7"/><file name="mysql4-upgrade-1.4.8-1.5.0.php" hash="a7eaf9d86daeb0686b1cf03f9ed9c817"/><file name="mysql4-upgrade-1.5.5-1.6.0.php" hash="3aeb056f347896a0ddf888cefd21bfeb"/><file name="mysql4-upgrade-1.6.0-1.7.1.php" hash="e7854e9d144ca79894b07252488535e8"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="algoliasearch.xml" hash="58543413c69185fd8016db48c9d4522a"/></dir><dir name="template"><dir name="algoliasearch"><dir name="autocomplete"><file name="attribute.phtml" hash="122da2c7c5b3b4e346e2284f710c7faa"/><file name="category.phtml" hash="179a0709434e4a54d66e662999b2a2d9"/><file name="menu.phtml" hash="61b58ab6e3be1ac57a58744b887bcf62"/><file name="page.phtml" hash="d836a9f545202e36e442f281bfcfd79f"/><file name="product.phtml" hash="826ee0dfebf3163a8737dc16d71a1a79"/><file name="suggestion.phtml" hash="1c8e38f341e407b7026acd17a865419e"/></dir><file name="autocomplete.phtml" hash="f459643574e8cbcff4642168ed5303e7"/><dir name="instantsearch"><file name="currentRefinements.phtml" hash="be70be35514f4ec2b8c52e1174a035bb"/><file name="hit.phtml" hash="77e9b53dadfc4702328bd71068144700"/><file name="refinementsItem.phtml" hash="9e3e31dde749ae01b28fc288ff09ded0"/><file name="stats.phtml" hash="6460c77e5cad476058226ec1f8dba0f9"/><file name="wrapper.phtml" hash="7442e46858eaa25154ab85fc69fb154d"/></dir><dir name="internals"><file name="beforecontent.phtml" hash="19f2ee9532f4e46c77ade0157976b780"/><file name="configuration.phtml" hash="eac3d0a84714be2b5381b2ae81ec12e0"/></dir></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="algoliasearch"><file name="adminjs.phtml" hash="1c287afa9e605e0a82270708997e2191"/></dir></dir><dir name="layout"><file name="algoliasearch.xml" hash="f49d4d2a5328f7f0a260eaaa0fcb1d19"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="algoliasearch"><file name="algolia-admin-menu.svg" hash="e38a9a012b0b127acd77c00c7abfa5ba"/><file name="algoliasearch.css" hash="f133fa3dd969387ee261943f2c4ea6e1"/><file name="clear-cross.svg" hash="079bf9e68e180c2f1df4e5fc4f9a2022"/><file name="cross-circle.svg" hash="82279532ee2100132649bb0cb6aa2954"/><file name="is-icon.svg" hash="cd407613fc0e8644aef3095f9c0f86cd"/><file name="magnifying-glass.svg" hash="73847c3bd772c161418cf8a59422b544"/><file name="search-by-algolia.svg" hash="5cc0f28bf007081ce109d6d09bb943ee"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir></dir></dir></dir></target><target name="mage"><dir name="js"><dir name="algoliasearch"><file name="autocomplete.js" hash="956912a1bb365f7a9b270abc623c738a"/><file name="instantsearch.js" hash="9e97aa82661419a86703a055bed857c6"/><dir name="internals"><dir name="adminhtml"><file name="admin_scripts.js" hash="4de80e7e80cd0687fdb7aca0a7caf5c8"/><file name="algoliaAdminBundle.min.js" hash="dd7397cbb880e33d1a53034bd89db926"/><file name="algoliaAdminBundle.min.js.map" hash="e7dd40d266532d0c2d7901effd4b6526"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><dir name="frontend"><file name="Function.prototype.bind.js" hash="eb15975feb0cc976face88cb194294ae"/><file name="algoliaBundle.min.js" hash="f889b8e505423b0a4807758c5664af73"/><file name="algoliaBundle.min.js.map" hash="d6ab863fad690f014d45d04fded0a7f4"/><file name="common.js" hash="ca7025cca1436335f708ce435b5dddb6"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><file name=".DS_Store" hash="c860452222691f31e468aa99fd04ddac"/></dir><file name=".DS_Store" hash="d6358f636f4535a23cc607f88f4522ed"/></dir></dir><dir name="lib"><dir name="AlgoliaSearch"><file name="AlgoliaException.php" hash="47e71cc8e04b8be4d1787580179004d2"/><file name="Client.php" hash="0234f0db991223ec97fe1d76e48708b3"/><file name="ClientContext.php" hash="2ebbefeab32eaf290e2cf66ab932d89f"/><file name="FailingHostsCache.php" hash="0aedafa333280473eff8eb6d55f53328"/><file name="FileFailingHostsCache.php" hash="763ea004ade17204597924bb562500db"/><file name="InMemoryFailingHostsCache.php" hash="5dafaaffaaf8f4c4d8429b35a1daab9b"/><file name="Index.php" hash="df7e8abb51bbff0448fb60d5ad596eda"/><file name="IndexBrowser.php" hash="0264b1fb79575229a43627c1c12273ec"/><file name="Json.php" hash="dc9433a3091b4a04eafbff1f322f5c38"/><file name="PlacesIndex.php" hash="bd5f8c04de2573528d44e5277250212a"/><file name="SynonymType.php" hash="9d561527010de52acf1b88daa3100570"/><file name="Version.php" hash="fc71563fc6343a70069c7f41eb27a9e7"/><file name="loader.php" hash="7517d8d5b62a57a7c3059822b9afe39e"/><dir name="resources"><file name="ca-bundle.crt" hash="47961e7ef15667c93cd99be01b51f00a"/></dir><file name=".DS_Store" hash="50c2aebe3913ec5a14b5298371d00c28"/></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Algolia_Algoliasearch.csv" hash="5eeeecf4a6ac60b207cecd8d44ba9302"/></dir></target></contents>
21
  <compatible/>
22
  <dependencies><required><php><min>5.3.0</min><max>7.2.0</max></php><extension><name>curl</name><min>7.16.2</min><max/></extension><extension><name>json</name><min/><max/></extension></required></dependencies>
23
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>algoliasearch</name>
4
+ <version>1.11.1</version>
5
  <stability>stable</stability>
6
  <license uri="https://github.com/algolia/algoliasearch-magento/blob/master/LICENSE.txt">MIT</license>
7
  <channel>community</channel>
15
  </description>
16
  <notes>Change Log: https://github.com/algolia/algoliasearch-magento/blob/master/CHANGELOG.md</notes>
17
  <authors><author><name>Algolia Team</name><user>algolia</user><email>support@algolia.com</email></author></authors>
18
+ <date>2017-09-15</date>
19
+ <time>12:24:27</time>
20
+ <contents><target name="mageetc"><dir name="modules"><file name="Algolia_Algoliasearch.xml" hash="bf2d7b412e345f47291c96d3dc6a7c7f"/></dir></target><target name="magecommunity"><dir name="Algolia"><dir name="Algoliasearch"><dir name="Block"><dir name="Adminhtml"><file name="Notifications.php" hash="1f93e773503f91c3a0bc9364cd4e4e25"/></dir><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="AbstractField.php" hash="c5b2a65b11d5993e385234367689c10d"/><file name="AdditionalSections.php" hash="f8f8e2d9385b8aa3dcc79987a832d284"/><file name="CategoryAdditionalAttributes.php" hash="cec9f23859bfd3328305dafcbec9cf68"/><file name="CustomRankingCategoryAttributes.php" hash="90e976e6c636d3df2f13cd843e2184fa"/><file name="CustomRankingProductAttributes.php" hash="7540e89be193568c069b21d225964be7"/><file name="ExcludedPages.php" hash="0119009da0f9b5daef8fd66854ae0661"/><file name="Facets.php" hash="893e9599b639593ed6897a27edb8d7e3"/><file name="OnewaySynonyms.php" hash="f1ff6ae2e8bc4cc61238e399564d46b6"/><file name="ProductAdditionalAttributes.php" hash="5eed1b4abcb3d51f35702bdf0743ee61"/><file name="Select.php" hash="e9521a9c869b427bca0fe57ea92288a1"/><file name="Sorts.php" hash="c40feb1c0adfc303f96ce8ca47724a19"/><file name="Synonyms.php" hash="ee555973c7c2f385240b168cd58047e5"/></dir></dir></dir></dir></dir><dir name="Helper"><file name="Algoliahelper.php" hash="1f3363dc208c968a0900e1efd9700557"/><file name="Config.php" hash="3fde4878ca4af93b88ad3fc97a0e9e0d"/><file name="Data.php" hash="30446c67a415453298a816e4a999338c"/><dir name="Entity"><file name="Additionalsectionshelper.php" hash="12017b4c8dce6eda8f8ceb984cfa5e53"/><file name="Categoryhelper.php" hash="e878300df61d2326b6f73044a9e1b974"/><file name="Helper.php" hash="69fe5cef19b1101674c1afd0dcb0de1f"/><file name="Pagehelper.php" hash="79ad1cd36bcf0f9d9e54d4d37c43b088"/><file name="Producthelper.php" hash="55f7d90251a4d754b0ddc74f691709b8"/><file name="Suggestionhelper.php" hash="cb40a85330cd8dc59b4d1c647b124899"/></dir><file name="Image.php" hash="5c8aba6fd77c0c0796a8ac67f9769c84"/><file name="IndexChecker.php" hash="8f0f52bd1129930a27dda6ddaaab20e4"/><file name="Logger.php" hash="9f1d1ceb9059a98746aa9fd473549449"/><file name=".DS_Store" hash="45eb27e8591a0f709d87531296fcf1d7"/></dir><dir name="Model"><dir name="Exception"><file name="IndexPendingException.php" hash="43ab04b5cdc7829f408f1e87cf072582"/></dir><dir name="Indexer"><file name="Abstract.php" hash="9f442576c0cd25d70c5a2bc36c1ad535"/><file name="Algolia.php" hash="06f2f06a82ecc2ff21a455059196efda"/><file name="Algoliaadditionalsections.php" hash="2ff2d4217b0d60d2811e48a8c412c496"/><file name="Algoliacategories.php" hash="f439f6d5a8a5141382b40745d48a8a12"/><file name="Algoliapages.php" hash="1f30b8c99b9f1b5743aba74a6ae458a1"/><file name="Algoliaqueuerunner.php" hash="51996d5991f48c6eff37fe265ac5be66"/><file name="Algoliasuggestions.php" hash="cdc75681a6f2c3484b745be184f5c1ee"/></dir><file name="Observer.php" hash="219db86ef207096c69517b36eb51a396"/><file name="Queue.php" hash="cfe9595a8dcb88a11ea4523feccc72f9"/><dir name="Resource"><file name="Engine.php" hash="950a646f2b71c8256feda7a049e719c6"/><dir name="Fulltext"><file name="Collection.php" hash="e3c8a13d9a034fcd1aa40e2e336208a0"/></dir><file name="Fulltext.php" hash="ea0d934f2a7d9a308d50827fad8aa0c1"/></dir><dir name="System"><dir name="Config"><dir name="Backend"><file name="ExtraSettings.php" hash="d1d67d01841dda9660031ea258f4fbf0"/><dir name="Serialized"><file name="Array.php" hash="6492ba56f58b26cebc6d826ba3502779"/></dir><file name="SynonymsFile.php" hash="12b218765f015ea31f03da822f4c2ca5"/></dir><dir name="Source"><dir name="Dropdown"><file name="RetryValues.php" hash="c03347006d692207e5ba2cdd9f4034be"/></dir></dir></dir><file name="Imagetype.php" hash="1391d49853b94714080de07fc662a831"/><file name="IndexVisibility.php" hash="b4d685a15371f59796fbe12db0f2dce3"/><file name="Removewords.php" hash="9b7d40d7ccf11d6d5fa101c8b06c5b9e"/></dir></dir><dir name="bin"><file name="dump.php" hash="fc7e65743142c494969eb9b995c1e0a1"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="QueueController.php" hash="b38ffbe6c46a89fa30968a3232d9eea5"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="07edd7bca541d4dbeba73c2b70ec53a2"/><file name="config.xml" hash="d9145130ba885986aeef7d1f86c25cd6"/><file name="system.xml" hash="73da3922c85946c80d887e83ca684195"/></dir><dir name="sql"><dir name="algoliasearch_setup"><file name="mysql4-install-0.1.0.php" hash="561f4f9e9f7021061964330a6c1eccec"/><file name="mysql4-upgrade-0.1.0-1.4.8.php" hash="1fae6deaf608f812844c8639b178cbc7"/><file name="mysql4-upgrade-1.4.8-1.5.0.php" hash="a7eaf9d86daeb0686b1cf03f9ed9c817"/><file name="mysql4-upgrade-1.5.5-1.6.0.php" hash="3aeb056f347896a0ddf888cefd21bfeb"/><file name="mysql4-upgrade-1.6.0-1.7.1.php" hash="e7854e9d144ca79894b07252488535e8"/><file name="mysql4-upgrade-1.7.1-1.11.1.php" hash="d5b85eddc8ca10f2dd7e4ed3c80f87a8"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="algoliasearch.xml" hash="58543413c69185fd8016db48c9d4522a"/></dir><dir name="template"><dir name="algoliasearch"><dir name="autocomplete"><file name="attribute.phtml" hash="122da2c7c5b3b4e346e2284f710c7faa"/><file name="category.phtml" hash="179a0709434e4a54d66e662999b2a2d9"/><file name="menu.phtml" hash="61b58ab6e3be1ac57a58744b887bcf62"/><file name="page.phtml" hash="d836a9f545202e36e442f281bfcfd79f"/><file name="product.phtml" hash="826ee0dfebf3163a8737dc16d71a1a79"/><file name="suggestion.phtml" hash="1c8e38f341e407b7026acd17a865419e"/></dir><file name="autocomplete.phtml" hash="f459643574e8cbcff4642168ed5303e7"/><dir name="instantsearch"><file name="currentRefinements.phtml" hash="be70be35514f4ec2b8c52e1174a035bb"/><file name="hit.phtml" hash="77e9b53dadfc4702328bd71068144700"/><file name="refinementsItem.phtml" hash="9e3e31dde749ae01b28fc288ff09ded0"/><file name="stats.phtml" hash="6460c77e5cad476058226ec1f8dba0f9"/><file name="wrapper.phtml" hash="7442e46858eaa25154ab85fc69fb154d"/></dir><dir name="internals"><file name="beforecontent.phtml" hash="19f2ee9532f4e46c77ade0157976b780"/><file name="configuration.phtml" hash="1c30ae2eb5a3f2668857a6bd9613f2e8"/></dir><file name=".DS_Store" hash="b0da4239ae378aa4070a7a1d1f8d20c4"/></dir></dir></dir></dir></dir><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="algoliasearch"><file name="adminjs.phtml" hash="1c287afa9e605e0a82270708997e2191"/><file name="notifications.phtml" hash="517dfed6eae5ad6dbf4d15977cc276c0"/></dir></dir><dir name="layout"><file name="algoliasearch.xml" hash="67748ecc7520db757aa66be8a6c67711"/></dir></dir></dir></dir></target><target name="mageskin"><dir name="frontend"><dir name="base"><dir name="default"><dir name="algoliasearch"><file name="algolia-admin-menu.svg" hash="e38a9a012b0b127acd77c00c7abfa5ba"/><file name="algoliasearch.css" hash="84aa2b3b55d9e8e1b2f49bcf8d0518f6"/><file name="clear-cross.svg" hash="079bf9e68e180c2f1df4e5fc4f9a2022"/><file name="cross-circle.svg" hash="82279532ee2100132649bb0cb6aa2954"/><file name="is-icon.svg" hash="cd407613fc0e8644aef3095f9c0f86cd"/><file name="magnifying-glass.svg" hash="73847c3bd772c161418cf8a59422b544"/><file name="search-by-algolia.svg" hash="5cc0f28bf007081ce109d6d09bb943ee"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir></dir></dir></dir></target><target name="mage"><dir name="js"><dir name="algoliasearch"><file name="autocomplete.js" hash="a24275150c1a1128324e540fb7313ee6"/><file name="instantsearch.js" hash="18342a873ba7cc51dfbc63e2b167414e"/><dir name="internals"><dir name="adminhtml"><file name="admin_scripts.js" hash="e8f80b34295a4a217d76f3efda6e8875"/><file name="algoliaAdminBundle.min.js" hash="dd7397cbb880e33d1a53034bd89db926"/><file name="algoliaAdminBundle.min.js.map" hash="e7dd40d266532d0c2d7901effd4b6526"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><dir name="frontend"><file name="Function.prototype.bind.js" hash="eb15975feb0cc976face88cb194294ae"/><file name="algoliaBundle.min.js" hash="f889b8e505423b0a4807758c5664af73"/><file name="algoliaBundle.min.js.map" hash="d6ab863fad690f014d45d04fded0a7f4"/><file name="common.js" hash="5fcecaf2e481fe60fc6f23ce60d35fc6"/><file name=".DS_Store" hash="194577a7e20bdcc7afbb718f502c134c"/></dir><file name=".DS_Store" hash="b3bd0ab8bb97268f873844ff8ed7e13f"/></dir><file name=".DS_Store" hash="b15c4e7d8e463c565f40cd74d58f2773"/></dir></dir><dir name="lib"><dir name="AlgoliaSearch"><file name="AlgoliaConnectionException.php" hash="53ce5540b7b0a0940338fa5be79d9c4a"/><file name="AlgoliaException.php" hash="47e71cc8e04b8be4d1787580179004d2"/><file name="Client.php" hash="12a157007a50afa02a4c82acd1723343"/><file name="ClientContext.php" hash="e795a25b85c2d15d06a036d9c9bfbe6c"/><file name="FailingHostsCache.php" hash="0aedafa333280473eff8eb6d55f53328"/><file name="FileFailingHostsCache.php" hash="763ea004ade17204597924bb562500db"/><file name="InMemoryFailingHostsCache.php" hash="5dafaaffaaf8f4c4d8429b35a1daab9b"/><file name="Index.php" hash="a24f71d99f1b90911358cfe6a465a601"/><file name="IndexBrowser.php" hash="0264b1fb79575229a43627c1c12273ec"/><file name="Json.php" hash="dc9433a3091b4a04eafbff1f322f5c38"/><file name="PlacesIndex.php" hash="bd5f8c04de2573528d44e5277250212a"/><file name="SynonymType.php" hash="9d561527010de52acf1b88daa3100570"/><file name="Version.php" hash="da873793933d35cf046ed834eef88b4f"/><file name="loader.php" hash="e8faacecf3fd0696e3eda112cdc218c3"/><dir name="resources"><file name="ca-bundle.crt" hash="47961e7ef15667c93cd99be01b51f00a"/></dir><file name=".DS_Store" hash="50c2aebe3913ec5a14b5298371d00c28"/></dir></dir></target><target name="magelocale"><dir name="en_US"><file name="Algolia_Algoliasearch.csv" hash="5eeeecf4a6ac60b207cecd8d44ba9302"/></dir></target></contents>
21
  <compatible/>
22
  <dependencies><required><php><min>5.3.0</min><max>7.2.0</max></php><extension><name>curl</name><min>7.16.2</min><max/></extension><extension><name>json</name><min/><max/></extension></required></dependencies>
23
  </package>
skin/frontend/base/default/algoliasearch/algoliasearch.css CHANGED
@@ -323,6 +323,11 @@ a.ais-current-refined-values--link:hover
323
  .ais-range-slider--marker-large:first-child {
324
  margin-left: 0;
325
  }
 
 
 
 
 
326
  /******************
327
  **
328
  ** Auto-completion menu
323
  .ais-range-slider--marker-large:first-child {
324
  margin-left: 0;
325
  }
326
+
327
+ .ais-root__collapsed .ais-body, .ais-root__collapsed .ais-footer {
328
+ display: none;
329
+ }
330
+
331
  /******************
332
  **
333
  ** Auto-completion menu