├── .github ├── ISSUE_TEMPLATE.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .php_cs ├── .styleci.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── MAINTAINERS.md ├── README.md ├── app ├── code │ └── community │ │ └── Algolia │ │ └── Algoliasearch │ │ ├── Block │ │ ├── Adminhtml │ │ │ ├── Indexingqueue.php │ │ │ ├── Indexingqueue │ │ │ │ ├── Edit.php │ │ │ │ ├── Edit │ │ │ │ │ └── Form.php │ │ │ │ ├── Grid.php │ │ │ │ ├── Grid │ │ │ │ │ └── Renderer │ │ │ │ │ │ └── Json.php │ │ │ │ └── Status.php │ │ │ ├── Notifications.php │ │ │ └── Reindexsku │ │ │ │ ├── Edit.php │ │ │ │ └── Edit │ │ │ │ └── Form.php │ │ ├── Checkout │ │ │ └── Success │ │ │ │ └── Conversion.php │ │ └── System │ │ │ └── Config │ │ │ └── Form │ │ │ └── Field │ │ │ ├── AbstractField.php │ │ │ ├── AdditionalSections.php │ │ │ ├── CategoryAdditionalAttributes.php │ │ │ ├── ClickAnalytics.php │ │ │ ├── CustomRankingCategoryAttributes.php │ │ │ ├── CustomRankingProductAttributes.php │ │ │ ├── ExcludedPages.php │ │ │ ├── Facets.php │ │ │ ├── Logo.php │ │ │ ├── OnewaySynonyms.php │ │ │ ├── ProductAdditionalAttributes.php │ │ │ ├── ProductAttributes.php │ │ │ ├── Select.php │ │ │ ├── Sorts.php │ │ │ └── Synonyms.php │ │ ├── Helper │ │ ├── Algoliahelper.php │ │ ├── Config.php │ │ ├── Data.php │ │ ├── Entity │ │ │ ├── Additionalsectionshelper.php │ │ │ ├── Categoryhelper.php │ │ │ ├── Helper.php │ │ │ ├── Pagehelper.php │ │ │ ├── Producthelper.php │ │ │ └── Suggestionhelper.php │ │ ├── Image.php │ │ ├── IndexChecker.php │ │ ├── Logger.php │ │ └── ProxyHelper.php │ │ ├── Model │ │ ├── Exception │ │ │ ├── IndexPendingException.php │ │ │ ├── ProductDeletedException.php │ │ │ ├── ProductDisabledException.php │ │ │ ├── ProductNotVisibleException.php │ │ │ ├── ProductOutOfStockException.php │ │ │ ├── ProductReindexException.php │ │ │ └── ProductUnknownSkuException.php │ │ ├── Indexer │ │ │ ├── Abstract.php │ │ │ ├── Algolia.php │ │ │ ├── Algoliaadditionalsections.php │ │ │ ├── Algoliacategories.php │ │ │ ├── Algoliadeleteproducts.php │ │ │ ├── Algoliapages.php │ │ │ ├── Algoliaqueuerunner.php │ │ │ └── Algoliasuggestions.php │ │ ├── Job.php │ │ ├── Observer.php │ │ ├── Observer │ │ │ └── Conversion.php │ │ ├── Queue.php │ │ ├── Resource │ │ │ ├── Engine.php │ │ │ ├── Fulltext.php │ │ │ ├── Fulltext │ │ │ │ └── Collection.php │ │ │ ├── Job.php │ │ │ └── Job │ │ │ │ └── Collection.php │ │ ├── Source │ │ │ ├── JobMethods.php │ │ │ └── JobStatuses.php │ │ └── System │ │ │ ├── BackendRenderingDisplayMode.php │ │ │ ├── Config │ │ │ ├── Backend │ │ │ │ ├── EnableClickAnalytics.php │ │ │ │ ├── ExtraSettings.php │ │ │ │ ├── Serialized │ │ │ │ │ └── Array.php │ │ │ │ └── SynonymsFile.php │ │ │ └── Source │ │ │ │ └── Dropdown │ │ │ │ └── RetryValues.php │ │ │ ├── ConversionAnalyticsMode.php │ │ │ ├── Imagetype.php │ │ │ ├── IndexVisibility.php │ │ │ └── Removewords.php │ │ ├── bin │ │ └── dump.php │ │ ├── controllers │ │ └── Adminhtml │ │ │ └── Algoliasearch │ │ │ ├── IndexingqueueController.php │ │ │ ├── QueueController.php │ │ │ └── ReindexskuController.php │ │ ├── etc │ │ ├── adminhtml.xml │ │ ├── config.xml │ │ └── system.xml │ │ └── sql │ │ └── algoliasearch_setup │ │ ├── mysql4-install-0.1.0.php │ │ ├── mysql4-upgrade-0.1.0-1.4.8.php │ │ ├── mysql4-upgrade-1.11.1-1.12.0.php │ │ ├── mysql4-upgrade-1.14.1-1.15.0.php │ │ ├── mysql4-upgrade-1.15.0-1.16.0.php │ │ ├── mysql4-upgrade-1.16.0-1.17.0.php │ │ ├── mysql4-upgrade-1.4.8-1.5.0.php │ │ ├── mysql4-upgrade-1.5.5-1.6.0.php │ │ ├── mysql4-upgrade-1.6.0-1.7.1.php │ │ └── mysql4-upgrade-1.7.1-1.11.1.php ├── design │ ├── adminhtml │ │ └── default │ │ │ └── default │ │ │ ├── layout │ │ │ └── algoliasearch.xml │ │ │ └── template │ │ │ └── algoliasearch │ │ │ ├── adminjs.phtml │ │ │ ├── notifications.phtml │ │ │ └── queue │ │ │ └── status.phtml │ └── frontend │ │ └── base │ │ └── default │ │ ├── layout │ │ └── algoliasearch.xml │ │ └── template │ │ └── algoliasearch │ │ ├── autocomplete.phtml │ │ ├── autocomplete │ │ ├── attribute.phtml │ │ ├── category.phtml │ │ ├── menu.phtml │ │ ├── page.phtml │ │ ├── product.phtml │ │ └── suggestion.phtml │ │ ├── checkout │ │ └── success │ │ │ └── conversion.phtml │ │ ├── instantsearch │ │ ├── currentRefinements.phtml │ │ ├── hit-item.phtml │ │ ├── hit.phtml │ │ ├── refinementsItem.phtml │ │ ├── stats.phtml │ │ └── wrapper.phtml │ │ └── internals │ │ ├── beforecontent.phtml │ │ └── configuration.phtml ├── etc │ └── modules │ │ └── Algolia_Algoliasearch.xml └── locale │ ├── en_US │ └── Algolia_Algoliasearch.csv │ ├── nl_NL │ └── Algolia_Algoliasearch.csv │ └── sv_SE │ └── Algolia_Algoliasearch.csv ├── composer.json ├── dev ├── Dockerfile.base ├── Dockerfile.dev ├── Dockerfile.test ├── bin │ ├── .zshrc │ ├── algoliasearch.xml │ ├── config.inc.php │ ├── install-magento │ ├── makeRelease.php │ ├── php.ini │ ├── start.sh │ └── test.sh ├── restart.sh └── runTests.sh ├── doc ├── auto-complete.gif └── instant-search.gif ├── js └── algoliasearch │ ├── autocomplete.js │ ├── click_conversion_analytics.js │ ├── instantsearch.js │ └── internals │ ├── adminhtml │ ├── admin_scripts.js │ ├── algoliaAdminBundle.min.js │ └── algoliaAdminBundle.min.js.map │ └── frontend │ ├── Function.prototype.bind.js │ ├── algoliaBundle.min.js │ ├── algoliaBundle.min.js.map │ ├── common.js │ └── search-insights.js ├── lib └── AlgoliaSearch │ ├── AlgoliaConnectionException.php │ ├── AlgoliaException.php │ ├── Analytics.php │ ├── Client.php │ ├── ClientContext.php │ ├── FailingHostsCache.php │ ├── FileFailingHostsCache.php │ ├── InMemoryFailingHostsCache.php │ ├── Index.php │ ├── IndexBrowser.php │ ├── Iterators │ ├── AlgoliaIterator.php │ ├── RuleIterator.php │ └── SynonymIterator.php │ ├── Json.php │ ├── PlacesIndex.php │ ├── SynonymType.php │ ├── Version.php │ ├── loader.php │ └── resources │ └── ca-bundle.crt ├── modman ├── phpunit.xml.dist ├── skin ├── adminhtml │ └── base │ │ └── default │ │ └── algoliasearch │ │ └── algoliasearch.css └── frontend │ └── base │ └── default │ └── algoliasearch │ ├── algolia-admin-menu.svg │ ├── algoliasearch.css │ ├── clear-cross.svg │ ├── cross-circle.svg │ ├── is-icon.svg │ ├── magnifying-glass.svg │ ├── search-by-algolia.svg │ └── stars-icon.svg └── tests ├── AbstractIndexingTestCase.php ├── AbstractTestCase.php ├── CategoriesIndexingTest.php ├── ConfigTest.php ├── PagesIndexingTest.php ├── ProductsIndexingTest.php ├── QueueTest.php └── bootstrap.php /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 15 | 16 | **Do you want to request a *feature* or report a *bug*?** 17 | 18 | 26 | 27 | **Bug: What is the current behavior?** 28 | 29 | **Bug: What is the expected behavior?** 30 | 31 | **Bug: What is the proposed solution?** 32 | 33 | **Feature: What is your use case for such a feature?** 34 | 35 | **Feature: What is your proposed configuration entry? The new option to add? What is the behavior?** 36 | 37 | **What is the version of Magento and of Algolia extension you are using? Always use the latest version of the extension one before opening a bug issue.** 38 | 39 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | **Summary** 7 | 8 | 13 | 14 | **Result** 15 | 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | vendor 3 | composer.lock 4 | -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | in(__DIR__.DIRECTORY_SEPARATOR.'app/code/'); 5 | 6 | return Symfony\CS\Config\Config::create() 7 | ->setUsingCache(true) 8 | ->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL) 9 | ->fixers([ 10 | 'align_double_arrow', 11 | 'long_array_syntax', 12 | '-multiline_array_trailing_comma', 13 | '-pre_increment' 14 | ])->finder($finder); -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: PSR2 2 | 3 | enabled: 4 | - long_array_syntax 5 | 6 | finder: 7 | path: 8 | - "app/code" -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | How to contribute? 2 | 3 | Basic flow: 4 | 5 | - Fork this repository 6 | - Make the fix/change/feature 7 | - Commit 8 | - Open a pull request to the **develop** branch 9 | - We will then review your pull request and make sure your fix helps the community. 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Algolia 4 | http://www.algolia.com/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /MAINTAINERS.md: -------------------------------------------------------------------------------- 1 | ## Maintainers 2 | The Algolia Magento 1 extension has reached a support and maintenance EOL and, therefore, will not commit to maintain the extension past FEB 2021. We encourage you to upgrade to Magento 2 as Magento 1 has already reached its end of life. -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Indexingqueue.php: -------------------------------------------------------------------------------- 1 | _blockGroup = 'algoliasearch'; 11 | $this->_controller = 'adminhtml_indexingqueue'; 12 | 13 | parent::__construct(); 14 | 15 | $this->_removeButton('add'); 16 | $this->_addButton('clear_queue', array( 17 | 'label' => Mage::helper('algoliasearch')->__('Clear Queue'), 18 | 'onclick' => "if (confirm('Are you sure you want to clear the queue? This operation cannot be reverted.')) { 19 | location.href='" . $this->getUrl('*/*/clear') . "' };", 20 | 'class' => 'cancel', 21 | )); 22 | } 23 | 24 | /** 25 | * Get header text. 26 | * 27 | * @return string 28 | */ 29 | public function getHeaderText() 30 | { 31 | return Mage::helper('algoliasearch')->__('Algolia Search - Indexing Queue'); 32 | } 33 | 34 | /** 35 | * Set custom Algolia icon class. 36 | * 37 | * @return string 38 | */ 39 | public function getHeaderCssClass() 40 | { 41 | return 'icon-head algoliasearch-head-icon'; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Indexingqueue/Edit.php: -------------------------------------------------------------------------------- 1 | _objectId = 'job_id'; 13 | $this->_blockGroup = 'algoliasearch'; 14 | $this->_controller = 'adminhtml_indexingqueue'; 15 | 16 | $this->_removeButton('save'); 17 | $this->_removeButton('reset'); 18 | $this->_removeButton('delete'); 19 | } 20 | 21 | /** 22 | * Get header text. 23 | * 24 | * @return string 25 | */ 26 | public function getHeaderText() 27 | { 28 | return Mage::helper('algoliasearch')->__('Algolia Search - Indexing Queue Job #%s', 29 | Mage::registry('algoliasearch_current_job')->getJobId()); 30 | } 31 | 32 | /** 33 | * Set custom Algolia icon class. 34 | * 35 | * @return string 36 | */ 37 | public function getHeaderCssClass() 38 | { 39 | return 'icon-head algoliasearch-head-icon'; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Indexingqueue/Grid.php: -------------------------------------------------------------------------------- 1 | setId('job_id'); 13 | $this->setDefaultSort('job_id'); 14 | $this->setDefaultDir('acs'); 15 | } 16 | 17 | /** 18 | * Prepare Search Report collection for grid 19 | * 20 | * @return Mage_Adminhtml_Block_Report_Search_Grid 21 | */ 22 | protected function _prepareCollection() 23 | { 24 | $collection = Mage::getResourceModel('algoliasearch/job_collection'); 25 | $this->setCollection($collection); 26 | 27 | return parent::_prepareCollection(); 28 | } 29 | 30 | /** 31 | * Prepare Grid columns 32 | * 33 | * @return Mage_Adminhtml_Block_Report_Search_Grid 34 | */ 35 | protected function _prepareColumns() 36 | { 37 | $this->addColumn('job_id', array( 38 | 'header' => Mage::helper('algoliasearch')->__('Job ID'), 39 | 'width' => '50px', 40 | 'filter' => false, 41 | 'index' => 'job_id', 42 | 'type' => 'number' 43 | )); 44 | 45 | $this->addColumn('created', array( 46 | 'header' => Mage::helper('algoliasearch')->__('Created'), 47 | 'index' => 'created', 48 | 'type' => 'datetime', 49 | )); 50 | 51 | $this->addColumn('status', array( 52 | 'header' => Mage::helper('algoliasearch')->__('Status'), 53 | 'index' => 'status', 54 | 'getter' => 'getStatusLabel', 55 | 'filter' => false, 56 | )); 57 | 58 | $this->addColumn('method', array( 59 | 'header' => Mage::helper('algoliasearch')->__('Method'), 60 | 'index' => 'method', 61 | 'type' => 'options', 62 | 'options' => Mage::getModel('algoliasearch/source_jobMethods')->getMethods(), 63 | )); 64 | 65 | $this->addColumn('data', array( 66 | 'header' => Mage::helper('algoliasearch')->__('Data'), 67 | 'index' => 'data', 68 | 'renderer' => 'Algolia_Algoliasearch_Block_Adminhtml_Indexingqueue_Grid_Renderer_Json' 69 | )); 70 | 71 | $this->addColumn('max_retries', array( 72 | 'header' => Mage::helper('algoliasearch')->__('Max Retries'), 73 | 'width' => '40px', 74 | 'filter' => false, 75 | 'index' => 'max_retries', 76 | 'type' => 'number' 77 | )); 78 | 79 | $this->addColumn('retries', array( 80 | 'header' => Mage::helper('algoliasearch')->__('Retries'), 81 | 'width' => '40px', 82 | 'filter' => false, 83 | 'index' => 'retries', 84 | 'type' => 'number' 85 | )); 86 | 87 | $this->addColumn('action', 88 | array( 89 | 'header' => Mage::helper('algoliasearch')->__('Action'), 90 | 'width' => '50px', 91 | 'type' => 'action', 92 | 'getter' => 'getJobId', 93 | 'actions' => array( 94 | array( 95 | 'caption' => Mage::helper('algoliasearch')->__('View'), 96 | 'url' => array('base'=>'*/*/view'), 97 | 'field' => 'id' 98 | ) 99 | ), 100 | 'filter' => false, 101 | 'sortable' => false, 102 | )); 103 | 104 | return parent::_prepareColumns(); 105 | } 106 | 107 | /** 108 | * Retrieve Row Click callback URL 109 | * 110 | * @return string 111 | */ 112 | public function getRowUrl($row) 113 | { 114 | return $this->getUrl('*/*/view', array('id' => $row->getJobId())); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Indexingqueue/Grid/Renderer/Json.php: -------------------------------------------------------------------------------- 1 | getData('data')) { 13 | $json = json_decode($json, true); 14 | 15 | foreach ($json as $var => $value) { 16 | $html .= $var . ': ' . (is_array($value) ? implode(',', $value) : $value) . '
'; 17 | } 18 | } 19 | return $html; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Notifications.php: -------------------------------------------------------------------------------- 1 | getUrl('adminhtml/system_config/edit/section/algoliasearch'); 10 | } 11 | 12 | public function showNotification() 13 | { 14 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 15 | $config = Mage::helper('algoliasearch/config'); 16 | 17 | return $config->showQueueNotificiation(); 18 | } 19 | 20 | public function getQueueInfo() 21 | { 22 | if (isset($this->_queueInfo)) { 23 | return $this->_queueInfo; 24 | } 25 | 26 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 27 | $config = Mage::helper('algoliasearch/config'); 28 | 29 | /** @var Mage_Core_Model_Resource $resource */ 30 | $resource = Mage::getSingleton('core/resource'); 31 | $tableName = $resource->getTableName('algoliasearch/queue'); 32 | 33 | $readConnection = $resource->getConnection('core_read'); 34 | 35 | $size = (int)$readConnection->query('SELECT COUNT(*) as total_count FROM ' . $tableName)->fetchColumn(0); 36 | $maxJobsPerSingleRun = $config->getNumberOfJobToRun(); 37 | 38 | $etaMinutes = ceil($size / $maxJobsPerSingleRun) * 5; // 5 - assuming the queue runner runs every 5 minutes 39 | 40 | $eta = $etaMinutes . ' minutes'; 41 | if ($etaMinutes > 60) { 42 | $hours = floor($etaMinutes / 60); 43 | $restMinutes = $etaMinutes % 60; 44 | 45 | $eta = $hours . ' hours ' . $restMinutes . ' minutes'; 46 | } 47 | 48 | $queueInfo = array( 49 | 'isEnabled' => $config->isQueueActive(), 50 | 'currentSize' => $size, 51 | 'eta' => $eta, 52 | ); 53 | 54 | $this->_queueInfo = $queueInfo; 55 | 56 | return $this->_queueInfo; 57 | } 58 | 59 | /** 60 | * Show notification based on condition 61 | * 62 | * @return bool 63 | */ 64 | protected function _toHtml() 65 | { 66 | $queueInfo = $this->getQueueInfo(); 67 | if ($this->showNotification() 68 | && $queueInfo['isEnabled'] === true 69 | && $queueInfo['currentSize'] > 0) { 70 | return parent::_toHtml(); 71 | } 72 | 73 | return ''; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Reindexsku/Edit.php: -------------------------------------------------------------------------------- 1 | _objectId = 'sku'; 13 | $this->_blockGroup = 'algoliasearch'; 14 | $this->_controller = 'adminhtml_reindexsku'; 15 | } 16 | 17 | /** 18 | * Get header text. 19 | * 20 | * @return string 21 | */ 22 | public function getHeaderText() 23 | { 24 | return Mage::helper('algoliasearch')->__('Algolia Search - Reindex SKU(s)'); 25 | } 26 | 27 | /** 28 | * Set custom Algolia icon class. 29 | * 30 | * @return string 31 | */ 32 | public function getHeaderCssClass() 33 | { 34 | return 'icon-head algoliasearch-head-icon'; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Adminhtml/Reindexsku/Edit/Form.php: -------------------------------------------------------------------------------- 1 | 'edit_form', 12 | 'action' => $this->getUrl('*/*/reindexPost'), 13 | 'method' => 'post', 14 | )); 15 | 16 | $fieldset = $form->addFieldset('base_fieldset', array()); 17 | 18 | $html = '

'; 19 | $html .= '

'.__('Enter here the SKU(s) you want to reindex separated by commas or carriage returns.').'

'; 20 | $html .= '

'.__('You will be notified if there is any reason why your product can\'t be reindexed.').'

'; 21 | $html .= '

'.__('It can be :').'

'; 22 | $html .= ''; 29 | $html .= '

'.__('You can reindex up to 10 SKUs at once.').'

'; 30 | 31 | $fieldset->addField('skus', 'textarea', array( 32 | 'name' => 'skus', 33 | 'label' => Mage::helper('algoliasearch')->__('Product SKU(s)'), 34 | 'title' => Mage::helper('algoliasearch')->__('Product SKU(s)'), 35 | 'required' => true, 36 | 'style' => 'width:100%', 37 | 'after_element_html' => $html, 38 | )); 39 | 40 | $form->setUseContainer(true); 41 | $this->setForm($form); 42 | 43 | return parent::_prepareForm(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/Checkout/Success/Conversion.php: -------------------------------------------------------------------------------- 1 | getLastOrderId()) { 13 | $this->_order = Mage::getModel('sales/order')->load($orderId); 14 | } 15 | } 16 | 17 | /** 18 | * @return string 19 | */ 20 | public function getOrderItemsConversionJson() 21 | { 22 | $orderItemsData = array(); 23 | $orderItems = $this->_order->getAllVisibleItems(); 24 | 25 | /** @var Item $item */ 26 | foreach ($orderItems as $item) { 27 | if ($item->getData('algoliasearch_query_param') !== '') { 28 | $orderItemsData[$item->getProductId()] = json_decode($item->getData('algoliasearch_query_param')); 29 | } 30 | } 31 | 32 | return Mage::helper('core')->jsonEncode($orderItemsData); 33 | } 34 | 35 | public function _toHtml() 36 | { 37 | if ($this->_order 38 | && Mage::helper('algoliasearch/config')->isClickConversionAnalyticsEnabled($this->_order->getStoreId()) 39 | && Mage::helper('algoliasearch/config')->getConversionAnalyticsMode($this->_order->getStoreId()) === 'place_order' 40 | ) { 41 | return parent::_toHtml(); 42 | } 43 | 44 | return ''; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/AbstractField.php: -------------------------------------------------------------------------------- 1 | settings)) { 11 | throw new Exception('Please, specify columns settings.'); 12 | } 13 | 14 | foreach ($this->settings['columns'] as $columnName => $columnSettings) { 15 | $fieldSettings = array(); 16 | 17 | if (isset($columnSettings['label'])) { 18 | $fieldSettings['label'] = Mage::helper('adminhtml')->__($columnSettings['label']); 19 | } 20 | 21 | if (isset($columnSettings['options'])) { 22 | $fieldSettings['renderer'] = $this->getRenderer($columnName, $columnSettings); 23 | } 24 | 25 | if (isset($columnSettings['class'])) { 26 | $fieldSettings['class'] = $columnSettings['class']; 27 | } 28 | 29 | if (isset($columnSettings['style'])) { 30 | $fieldSettings['style'] = $columnSettings['style']; 31 | } 32 | 33 | $this->addColumn($columnName, $fieldSettings); 34 | } 35 | 36 | $this->_addAfter = $this->settings['addAfter']; 37 | $this->_addButtonLabel = Mage::helper('adminhtml')->__($this->settings['buttonLabel']); 38 | 39 | parent::__construct(); 40 | } 41 | 42 | protected function _prepareArrayRow(Varien_Object $row) 43 | { 44 | foreach ($this->settings['columns'] as $columnName => $columnSettings) { 45 | if (!isset($columnSettings['options']) || !isset($columnSettings['rowMethod'])) { 46 | continue; 47 | } 48 | 49 | $row->setData('option_extra_attr_'.$this->getRenderer($columnName, $columnSettings)->calcOptionHash($row->{$columnSettings['rowMethod']}()), 'selected="selected"'); 50 | } 51 | } 52 | 53 | /** 54 | * Creates and populates a select block to represent each column in the configuration property. 55 | * 56 | * @param $columnId string The name of the column defined in addColumn 57 | * @param $columnSettings array Settings for select box 58 | * 59 | * @return Algolia_Algoliasearch_Block_System_Config_Form_Field_Select 60 | * 61 | * @throws Exception 62 | */ 63 | protected function getRenderer($columnId, array $columnSettings) 64 | { 65 | if (array_key_exists($columnId, $this->selectFields) && $this->selectFields[$columnId]) { 66 | return $this->selectFields[$columnId]; 67 | } 68 | 69 | $options = $columnSettings['options']; 70 | if (!is_array($options) && is_callable($options)) { 71 | $options = $options(); 72 | } 73 | 74 | $width = 100; 75 | if (isset($columnSettings['width'])) { 76 | $width = $columnSettings['width']; 77 | } 78 | 79 | /** @var Algolia_Algoliasearch_Block_System_Config_Form_Field_Select $selectField */ 80 | $selectField = Mage::app()->getLayout()->createBlock('algoliasearch/system_config_form_field_select'); 81 | 82 | $selectField->setIsRenderToJsTemplate(true); 83 | $selectField->setOptions($options); 84 | $selectField->setExtraParams('style="width:'.$width.'px;"'); 85 | 86 | if (isset($columnSettings['disabled']) && $columnSettings['disabled'] != 0) { 87 | $extra = $selectField->getExtraParams(); 88 | $extra .= ' disabled'; 89 | $selectField->setExtraParams($extra); 90 | } 91 | 92 | $this->selectFields[$columnId] = $selectField; 93 | 94 | return $this->selectFields[$columnId]; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/AdditionalSections.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'name' => array( 13 | 'label' => 'Section', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | $sections = array( 18 | array('name' => 'pages', 'label' => 'Pages'), 19 | ); 20 | 21 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 22 | $config = Mage::helper('algoliasearch/config'); 23 | 24 | $attributes = $config->getFacets(); 25 | foreach ($attributes as $attribute) { 26 | if ($attribute['attribute'] == 'price' || $attribute['attribute'] == 'category' || $attribute['attribute'] == 'categories') { 27 | continue; 28 | } 29 | 30 | $sections[] = array( 31 | 'name' => $attribute['attribute'], 32 | 'label' => $attribute['label'] ? $attribute['label'] : $attribute['attribute'] 33 | ); 34 | } 35 | 36 | foreach ($sections as $section) { 37 | $options[$section['name']] = $section['label']; 38 | } 39 | 40 | return $options; 41 | }, 42 | 'rowMethod' => 'getName', 43 | 'width' => 130, 44 | ), 45 | 'label' => array( 46 | 'label' => 'Label', 47 | 'style' => 'width: 100px;', 48 | ), 49 | 'hitsPerPage' => array( 50 | 'label' => 'Hits per page', 51 | 'style' => 'width: 100px;', 52 | 'class' => 'required-entry input-text validate-number', 53 | ), 54 | ), 55 | 'buttonLabel' => 'Add Section', 56 | 'addAfter' => false, 57 | ); 58 | 59 | parent::__construct(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/CategoryAdditionalAttributes.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Entity_Categoryhelper $category_helper */ 18 | $category_helper = Mage::helper('algoliasearch/entity_categoryhelper'); 19 | 20 | $searchableAttributes = $category_helper->getAllAttributes(); 21 | foreach ($searchableAttributes as $key => $label) { 22 | $options[$key] = $key ? $key : $label; 23 | } 24 | 25 | return $options; 26 | }, 27 | 'rowMethod' => 'getAttribute', 28 | 'width' => 160, 29 | ), 30 | 'searchable' => array( 31 | 'label' => 'Searchable', 32 | 'options' => array( 33 | '1' => 'Yes', 34 | '0' => 'No', 35 | ), 36 | 'rowMethod' => 'getSearchable', 37 | ), 38 | 'retrievable' => array( 39 | 'label' => 'Retrievable', 40 | 'options' => array( 41 | '1' => 'Yes', 42 | '0' => 'No', 43 | ), 44 | 'rowMethod' => 'getRetrievable', 45 | ), 46 | 'order' => array( 47 | 'label' => 'Ordered', 48 | 'options' => array( 49 | 'unordered' => 'Unordered', 50 | 'ordered' => 'Ordered', 51 | ), 52 | 'rowMethod' => 'getOrder', 53 | ), 54 | ), 55 | 'buttonLabel' => 'Add Attribute', 56 | 'addAfter' => false, 57 | ); 58 | 59 | parent::__construct(); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/ClickAnalytics.php: -------------------------------------------------------------------------------- 1 | isClickAnalyticsEnabled($element)) { 10 | $element->setDisabled(true); 11 | $this->_showUpsell = true; 12 | } 13 | 14 | return parent::_getElementHtml($element); 15 | } 16 | 17 | /** 18 | * @return bool 19 | */ 20 | public function isClickAnalyticsEnabled() 21 | { 22 | $proxyHelper = Mage::helper('algoliasearch/proxyHelper'); 23 | $info = $proxyHelper->getClientConfigurationData(); 24 | 25 | return isset($info['click_analytics']) && $info['click_analytics'] == 1; 26 | } 27 | 28 | protected function _decorateRowHtml($element, $html) 29 | { 30 | if (!$this->_showUpsell) { 31 | return parent::_decorateRowHtml($element, $html); 32 | } 33 | 34 | $additionalRow = '
'; 35 | $additionalRow .= $this->__('To get access to this Algolia feature, please consider upgrading to a higher plan.', 36 | 'https://www.algolia.com/pricing/'); 37 | $additionalRow .= '
'; 38 | 39 | return '' . $html . '' . $additionalRow; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/CustomRankingCategoryAttributes.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 18 | $config = Mage::helper('algoliasearch/config'); 19 | 20 | $attributes = $config->getCategoryAdditionalAttributes(); 21 | foreach ($attributes as $attribute) { 22 | $options[$attribute['attribute']] = $attribute['attribute']; 23 | } 24 | 25 | $options['custom_attribute'] = '[use custom attribute]'; 26 | 27 | return $options; 28 | }, 29 | 'rowMethod' => 'getAttribute', 30 | 'width' => 150, 31 | ), 32 | 'custom_attribute' => array( 33 | 'label' => 'Custom attribute', 34 | 'style' => 'width: 120px;', 35 | ), 36 | 'order' => array( 37 | 'label' => 'Asc / Desc', 38 | 'options' => array( 39 | 'desc' => 'Descending', 40 | 'asc' => 'Ascending', 41 | ), 42 | 'rowMethod' => 'getOrder', 43 | ), 44 | ), 45 | 'buttonLabel' => 'Add Ranking Criterion', 46 | 'addAfter' => false, 47 | ); 48 | 49 | parent::__construct(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/CustomRankingProductAttributes.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */ 18 | $product_helper = Mage::helper('algoliasearch/entity_producthelper'); 19 | $attributes = $product_helper->getAllAttributes(); 20 | foreach ($attributes as $key => $label) { 21 | $options[$key] = $key ?: $label; 22 | } 23 | 24 | $options['custom_attribute'] = '[use custom attribute]'; 25 | 26 | return $options; 27 | }, 28 | 'rowMethod' => 'getAttribute', 29 | 'width' => 150, 30 | ), 31 | 'custom_attribute' => array( 32 | 'label' => 'Custom attribute', 33 | 'style' => 'width: 120px;', 34 | ), 35 | 'order' => array( 36 | 'label' => 'Asc / Desc', 37 | 'options' => array( 38 | 'desc' => 'Descending', 39 | 'asc' => 'Ascending', 40 | ), 41 | 'rowMethod' => 'getOrder', 42 | ), 43 | ), 44 | 'buttonLabel' => 'Add Ranking Criterion', 45 | 'addAfter' => false, 46 | ); 47 | 48 | parent::__construct(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/ExcludedPages.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'pages' => array( 13 | 'label' => 'Pages', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Mage_Cms_Model_Resource_Page_Collection $magento_pages */ 18 | $magento_pages = Mage::getModel('cms/page')->getCollection()->addFieldToFilter('is_active', 1); 19 | 20 | $ids = $magento_pages->toOptionArray(); 21 | foreach ($ids as $id) { 22 | $options[$id['value']] = $id['value']; 23 | } 24 | 25 | return $options; 26 | }, 27 | 'rowMethod' => 'getPages', 28 | 'width' => 230, 29 | ), 30 | ), 31 | 'buttonLabel' => 'Add Excluded Page', 32 | 'addAfter' => false, 33 | ); 34 | 35 | parent::__construct(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/Facets.php: -------------------------------------------------------------------------------- 1 | settings = array( 13 | 'columns' => array( 14 | 'attribute' => array( 15 | 'label' => 'Attribute', 16 | 'options' => function () { 17 | $options = array(); 18 | 19 | /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */ 20 | $product_helper = Mage::helper('algoliasearch/entity_producthelper'); 21 | 22 | $attributes = $product_helper->getAllAttributes(); 23 | foreach ($attributes as $key => $label) { 24 | $options[$key] = $key ?: $label; 25 | } 26 | 27 | return $options; 28 | }, 29 | 'rowMethod' => 'getAttribute', 30 | 'width' => 160, 31 | ), 32 | 'type' => array( 33 | 'label' => 'Facet type', 34 | 'options' => array( 35 | 'conjunctive' => 'Conjunctive', 36 | 'disjunctive' => 'Disjunctive', 37 | 'slider' => 'Slider', 38 | 'priceRanges' => 'Price Ranges', 39 | ), 40 | 'rowMethod' => 'getType', 41 | ), 42 | 'label' => array( 43 | 'label' => 'Label', 44 | 'style' => 'width: 100px;', 45 | ), 46 | 'searchable' => array( 47 | 'label' => 'Searchable?', 48 | 'options' => array( 49 | '1' => 'Yes', 50 | '2' => 'No' 51 | ), 52 | 'rowMethod' => 'getSearchable', 53 | ), 54 | 'create_rule' => array( 55 | 'label' => 'Create Query rule?', 56 | 'options' => array( 57 | '2' => 'No', 58 | '1' => 'Yes' 59 | ), 60 | 'rowMethod' => 'getCreateRule', 61 | 'disabled' => $this->isQueryRulesDisabled() 62 | ), 63 | ), 64 | 'buttonLabel' => 'Add Facet', 65 | 'addAfter' => false, 66 | ); 67 | 68 | parent::__construct(); 69 | } 70 | 71 | /** 72 | * @return bool 73 | */ 74 | public function isQueryRulesDisabled() 75 | { 76 | if (is_null($this->_isQueryRulesDisabled)) { 77 | $this->_isQueryRulesDisabled = $this->_disableQueryRules(); 78 | } 79 | 80 | return $this->_isQueryRulesDisabled; 81 | } 82 | 83 | /** 84 | * @return bool 85 | */ 86 | protected function _disableQueryRules() 87 | { 88 | $proxyHelper = Mage::helper('algoliasearch/proxyHelper'); 89 | $info = $proxyHelper->getClientConfigurationData(); 90 | 91 | return !isset($info['query_rules']) || $info['query_rules'] == 0; 92 | } 93 | 94 | protected function _decorateRowHtml($element, $html) 95 | { 96 | if (!$this->isQueryRulesDisabled()) { 97 | return parent::_decorateRowHtml($element, $html); 98 | } 99 | 100 | $additionalRow = '
'; 101 | $additionalRow .= $this->__('To get access to this Algolia feature, please consider upgrading to a higher plan.', 102 | 'https://www.algolia.com/pricing/'); 103 | $additionalRow .= '
'; 104 | 105 | return '' . $html . '' . $additionalRow; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/Logo.php: -------------------------------------------------------------------------------- 1 | showLogo($element)) { 10 | $element->setDisabled(true); 11 | $element->setValue(0); 12 | $this->_showUpsell = true; 13 | } 14 | 15 | return parent::_getElementHtml($element); 16 | } 17 | 18 | /** 19 | * @return bool 20 | */ 21 | public function showLogo() 22 | { 23 | $proxyHelper = Mage::helper('algoliasearch/proxyHelper'); 24 | $info = $proxyHelper->getClientConfigurationData(); 25 | 26 | return isset($info['require_logo']) && $info['require_logo'] == 1; 27 | } 28 | 29 | protected function _decorateRowHtml($element, $html) 30 | { 31 | if (!$this->_showUpsell) { 32 | return parent::_decorateRowHtml($element, $html); 33 | } 34 | 35 | $additionalRow = '
'; 36 | $additionalRow .= $this->__('To be able to remove the Algolia logo, please consider upgrading to a higher plan.', 37 | 'https://www.algolia.com/pricing/'); 38 | $additionalRow .= '
'; 39 | 40 | return '' . $html . '' . $additionalRow; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/OnewaySynonyms.php: -------------------------------------------------------------------------------- 1 | settings = array( 8 | 'columns' => array( 9 | 'input' => array( 10 | 'label' => 'Input', 11 | 'style' => 'width: 100px;', 12 | ), 13 | 'synonyms' => array( 14 | 'label' => 'Synonyms (comma-separated)', 15 | 'style' => 'width: 435px;', 16 | ), 17 | ), 18 | 'buttonLabel' => 'Add One-way Synonyms', 19 | 'addAfter' => false, 20 | ); 21 | 22 | parent::__construct(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/ProductAdditionalAttributes.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */ 18 | $product_helper = Mage::helper('algoliasearch/entity_producthelper'); 19 | 20 | $searchableAttributes = $product_helper->getAllAttributes(); 21 | foreach ($searchableAttributes as $key => $label) { 22 | $options[$key] = $key ?: $label; 23 | } 24 | 25 | return $options; 26 | }, 27 | 'rowMethod' => 'getAttribute', 28 | 'width' => 160, 29 | ), 30 | 'searchable' => array( 31 | 'label' => 'Searchable', 32 | 'options' => array( 33 | '1' => 'Yes', 34 | '0' => 'No', 35 | ), 36 | 'rowMethod' => 'getSearchable', 37 | ), 38 | 'retrievable' => array( 39 | 'label' => 'Retrievable', 40 | 'options' => array( 41 | '1' => 'Yes', 42 | '0' => 'No', 43 | ), 44 | 'rowMethod' => 'getRetrievable', 45 | ), 46 | 'order' => array( 47 | 'label' => 'Ordered', 48 | 'options' => array( 49 | 'unordered' => 'Unordered', 50 | 'ordered' => 'Ordered', 51 | ), 52 | 'rowMethod' => 'getOrder', 53 | ), 54 | 'index_no_value' => array( 55 | 'label' => 'Index empty value', 56 | 'options' => array( 57 | '1' => 'Yes', 58 | '0' => 'No', 59 | ), 60 | 'rowMethod' => 'getIndexNoValue', 61 | ), 62 | ), 63 | 'buttonLabel' => 'Add Attribute', 64 | 'addAfter' => false, 65 | ); 66 | 67 | parent::__construct(); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/ProductAttributes.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */ 18 | $product_helper = Mage::helper('algoliasearch/entity_producthelper'); 19 | $attributes = $product_helper->getAllAttributes(); 20 | foreach ($attributes as $key => $label) { 21 | $options[$key] = $key ?: $label; 22 | } 23 | 24 | $options['custom_attribute'] = '[use custom attribute]'; 25 | 26 | return $options; 27 | }, 28 | 'rowMethod' => 'getAttribute', 29 | 'width' => 150, 30 | ), 31 | ), 32 | 'buttonLabel' => 'Add Attribute', 33 | 'addAfter' => false, 34 | ); 35 | 36 | parent::__construct(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/Select.php: -------------------------------------------------------------------------------- 1 | setName($this->getInputName()); 8 | $this->setClass('select'); 9 | 10 | return trim(preg_replace('/\s+/', ' ', parent::_toHtml())); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/Sorts.php: -------------------------------------------------------------------------------- 1 | settings = array( 11 | 'columns' => array( 12 | 'attribute' => array( 13 | 'label' => 'Attribute', 14 | 'options' => function () { 15 | $options = array(); 16 | 17 | /** @var Algolia_Algoliasearch_Helper_Entity_Producthelper $product_helper */ 18 | $product_helper = Mage::helper('algoliasearch/entity_producthelper'); 19 | $attributes = $product_helper->getAllAttributes(); 20 | foreach ($attributes as $key => $label) { 21 | $options[$key] = $key ?: $label; 22 | } 23 | 24 | return $options; 25 | }, 26 | 'rowMethod' => 'getAttribute', 27 | 'width' => 160, 28 | ), 29 | 'sort' => array( 30 | 'label' => 'Sort', 31 | 'options' => array( 32 | 'asc' => 'Ascending', 33 | 'desc' => 'Descending', 34 | ), 35 | 'rowMethod' => 'getSort', 36 | ), 37 | 'label' => array( 38 | 'label' => 'Label', 39 | 'style' => 'width: 200px;', 40 | ), 41 | ), 42 | 'buttonLabel' => 'Add Sorting Attribute', 43 | 'addAfter' => false, 44 | ); 45 | 46 | parent::__construct(); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Block/System/Config/Form/Field/Synonyms.php: -------------------------------------------------------------------------------- 1 | settings = array( 8 | 'columns' => array( 9 | 'synonyms' => array( 10 | 'label' => 'Synonyms (comma-separated)', 11 | 'style' => 'width: 550px;', 12 | ), 13 | ), 14 | 'buttonLabel' => 'Add Synonyms', 15 | 'addAfter' => false, 16 | ); 17 | 18 | parent::__construct(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Helper/Entity/Additionalsectionshelper.php: -------------------------------------------------------------------------------- 1 | array('unordered(value)'), 14 | ); 15 | 16 | $transport = new Varien_Object($indexSettings); 17 | Mage::dispatchEvent('algolia_additional_sections_index_before_set_settings', array('store_id' => $storeId, 'index_settings' => $transport)); 18 | $indexSettings = $transport->getData(); 19 | 20 | return $indexSettings; 21 | } 22 | 23 | public function getAttributeValues($storeId, $section) 24 | { 25 | /** @var Mage_Catalog_Model_Product_Visibility $catalogProductVisibility */ 26 | $catalogProductVisibility = Mage::getSingleton('catalog/product_visibility'); 27 | 28 | $attributeCode = $section['name']; 29 | 30 | /** @var Mage_Catalog_Model_Resource_Product_Collection $products */ 31 | $products = Mage::getResourceModel('catalog/product_collection')->addStoreFilter($storeId) 32 | ->addAttributeToFilter('visibility', 33 | array('in' => $catalogProductVisibility->getVisibleInSearchIds())) 34 | ->addAttributeToFilter('status', 35 | array('eq' => Mage_Catalog_Model_Product_Status::STATUS_ENABLED)) 36 | ->addAttributeToFilter($attributeCode, array('notnull' => true)) 37 | ->addAttributeToFilter($attributeCode, array('neq' => '')) 38 | ->addAttributeToSelect($attributeCode); 39 | 40 | $usedAttributeValues = array_keys(array_flip(// array unique 41 | explode(',', implode(',', $products->getColumnValues($attributeCode))))); 42 | 43 | /** @var Mage_Eav_Model_Config $eavConfig */ 44 | $eavConfig = Mage::getSingleton('eav/config'); 45 | 46 | /** @var Mage_Eav_Model_Attribute $attributeModel */ 47 | $attributeModel = $eavConfig->getAttribute('catalog_product', $attributeCode); 48 | $attributeModel->setStoreId($storeId); 49 | 50 | $values = $attributeModel->getSource()->getOptionText(implode(',', $usedAttributeValues)); 51 | 52 | if (!$values || count($values) == 0) { 53 | $values = array_unique($products->getColumnValues($attributeCode)); 54 | } 55 | 56 | if ($values && is_array($values) == false) { 57 | $values = array($values); 58 | } 59 | 60 | $values = array_map(function ($value) use ($section, $storeId) { 61 | $record = array( 62 | 'objectID' => $value, 63 | 'value' => $value, 64 | ); 65 | 66 | $transport = new Varien_Object($record); 67 | Mage::dispatchEvent('algolia_additional_section_item_index_before', array('section' => $section, 'record' => $transport, 'store_id' => $storeId)); // Only for backward compatibility 68 | Mage::dispatchEvent('algolia_additional_section_items_before_index', array('section' => $section, 'record' => $transport, 'store_id' => $storeId)); 69 | $record = $transport->getData(); 70 | 71 | return $record; 72 | }, $values); 73 | 74 | return $values; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Helper/Entity/Pagehelper.php: -------------------------------------------------------------------------------- 1 | array('unordered(slug)', 'unordered(name)', 'unordered(content)'), 14 | 'attributesToSnippet' => array('content:7'), 15 | ); 16 | 17 | $transport = new Varien_Object($indexSettings); 18 | Mage::dispatchEvent('algolia_pages_index_before_set_settings', array('store_id' => $storeId, 'index_settings' => $transport)); 19 | $indexSettings = $transport->getData(); 20 | 21 | return $indexSettings; 22 | } 23 | 24 | public function getPages($storeId, $pageIds = null) 25 | { 26 | /** @var Mage_Cms_Model_Resource_Page_Collection $pages */ 27 | $pageCollection = Mage::getModel('cms/page')->getCollection() 28 | ->addStoreFilter($storeId) 29 | ->addFieldToFilter('is_active', 1); 30 | 31 | if ($pageIds && count($pageIds) > 0) { 32 | $pageCollection->addFieldToFilter('page_id', array('in' => $pageIds)); 33 | } 34 | 35 | Mage::dispatchEvent('algolia_after_pages_collection_build', array('store' => $storeId, 'collection' => $pageCollection)); 36 | 37 | $excludedPages = array_values($this->config->getExcludedPages()); 38 | foreach ($excludedPages as &$excludedPage) { 39 | $excludedPage = $excludedPage['pages']; 40 | } 41 | 42 | $pages = array(); 43 | /** @var Mage_Cms_Model_Page $page */ 44 | foreach ($pageCollection as $page) { 45 | if (in_array($page->getIdentifier(), $excludedPages)) { 46 | continue; 47 | } 48 | 49 | $pageObject = array(); 50 | 51 | $pageObject['slug'] = $page->getIdentifier(); 52 | $pageObject['name'] = $page->getTitle(); 53 | 54 | $content = $page->getContent(); 55 | if ($this->config->getRenderTemplateDirectives()) { 56 | /** @var Mage_Cms_Helper_Data $cms_helper */ 57 | $cms_helper = Mage::helper('cms'); 58 | $tmplProc = $cms_helper->getPageTemplateProcessor(); 59 | $content = $tmplProc->filter($content); 60 | } 61 | 62 | /** @var Mage_Cms_Helper_Page $cmsPageHelper */ 63 | $cmsPageHelper = Mage::helper('cms/page'); 64 | 65 | $pageObject['objectID'] = $page->getId(); 66 | $pageObject['url'] = $cmsPageHelper->getPageUrl($page->getId()); 67 | $pageObject['content'] = $this->strip($content, array('script', 'style')); 68 | 69 | $transport = new Varien_Object($pageObject); 70 | Mage::dispatchEvent('algolia_after_create_page_object', array('page' => $transport, 'pageObject' => $page)); 71 | $pageObject = $transport->getData(); 72 | 73 | $pages[] = $pageObject; 74 | } 75 | 76 | return $pages; 77 | } 78 | 79 | public function shouldIndexPages($storeId) 80 | { 81 | $autocompleteSections = $this->config->getAutocompleteSections($storeId); 82 | 83 | foreach ($autocompleteSections as $section) { 84 | if ($section['name'] === 'pages') { 85 | return true; 86 | } 87 | } 88 | 89 | return false; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Helper/Image.php: -------------------------------------------------------------------------------- 1 | _getModel(); 11 | 12 | if ($this->getImageFile()) { 13 | $model->setBaseFile($this->getImageFile()); 14 | } else { 15 | $model->setBaseFile($this->getProduct()->getData($model->getDestinationSubdir())); 16 | } 17 | 18 | if ($model->isCached()) { 19 | return $this->removeProtocol($model->getUrl()); 20 | } 21 | 22 | if ($this->_scheduleRotate) { 23 | $model->rotate($this->getAngle()); 24 | } 25 | 26 | if ($this->_scheduleResize) { 27 | $model->resize(); 28 | } 29 | 30 | if ($this->getWatermark()) { 31 | $model->setWatermark($this->getWatermark()); 32 | } 33 | 34 | return $this->removeProtocol($model->saveFile()->getUrl()); 35 | } 36 | 37 | public function removeProtocol($url) 38 | { 39 | return str_replace(array('https://', 'http://'), '//', $url); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Helper/Logger.php: -------------------------------------------------------------------------------- 1 | config = Mage::helper('algoliasearch/config'); 15 | $this->enabled = $this->config->isLoggingEnabled(); 16 | 17 | /** @var Mage_Core_Model_Store $store */ 18 | foreach (Mage::app()->getStores() as $store) { 19 | $this->stores[$store->getId()] = $store->getName(); 20 | } 21 | } 22 | 23 | public function isEnable() 24 | { 25 | return $this->enabled; 26 | } 27 | 28 | public function getStoreName($storeId) 29 | { 30 | if ($storeId === null) { 31 | return 'undefined store'; 32 | } 33 | 34 | if (array_key_exists($storeId, $this->stores)) { 35 | return $storeId . ' (' . $this->stores[$storeId] . ')'; 36 | } 37 | 38 | return $storeId; 39 | } 40 | 41 | public function start($action) 42 | { 43 | if ($this->enabled == false) { 44 | return; 45 | } 46 | 47 | $this->log(''); 48 | $this->log(''); 49 | $this->log('>>>>> BEGIN '.$action); 50 | $this->timers[$action] = microtime(true); 51 | } 52 | 53 | public function stop($action) 54 | { 55 | if ($this->enabled == false) { 56 | return; 57 | } 58 | 59 | if (false === isset($this->timers[$action])) { 60 | throw new Exception('Algolia Logger => non existing action'); 61 | } 62 | 63 | $this->log('<<<<< END '.$action.' ('.$this->formatTime($this->timers[$action], microtime(true)).')'); 64 | } 65 | 66 | public function log($message, $forceLog = false) 67 | { 68 | if ($this->config->isLoggingEnabled() || $forceLog) { 69 | Mage::log($message, null, 'algolia.log'); 70 | } 71 | } 72 | 73 | protected function formatTime($begin, $end) 74 | { 75 | return ($end - $begin).'sec'; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Helper/ProxyHelper.php: -------------------------------------------------------------------------------- 1 | configHelper = Mage::helper('algoliasearch/config'); 22 | } 23 | 24 | /** 25 | * @param string $type 26 | * 27 | * @return string|array 28 | */ 29 | public function getInfo($type) 30 | { 31 | $appId = $this->configHelper->getApplicationID(); 32 | $apiKey = $this->configHelper->getAPIKey(); 33 | 34 | $token = $appId . ':' . $apiKey; 35 | $token = base64_encode($token); 36 | $token = str_replace(array("\n", '='), '', $token); 37 | 38 | $params = array( 39 | 'appId' => $appId, 40 | 'token' => $token, 41 | ); 42 | 43 | if ($type !== self::INFO_TYPE_EXTENSION_SUPPORT) { 44 | $params['type'] = $type; 45 | } 46 | 47 | $info = $this->postRequest($params, self::PROXY_URL_PARAM_GET_INFO); 48 | 49 | if ($info) { 50 | $info = json_decode($info, true); 51 | } 52 | 53 | return $info; 54 | } 55 | 56 | public function getClientConfigurationData() 57 | { 58 | if (!$this->allClientData) { 59 | $this->allClientData = $this->getInfo(self::INFO_TYPE_ALL); 60 | } 61 | 62 | return $this->allClientData; 63 | } 64 | 65 | /** 66 | * @param $data 67 | * @param $proxyMethod 68 | * 69 | * @return bool|string 70 | */ 71 | private function postRequest($data, $proxyMethod) 72 | { 73 | $ch = curl_init(); 74 | 75 | curl_setopt($ch, CURLOPT_URL, self::PROXY_URL . $proxyMethod); 76 | curl_setopt($ch, CURLOPT_POST, 1); 77 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); 78 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 79 | 80 | $result = curl_exec($ch); 81 | 82 | curl_close($ch); 83 | 84 | return $result; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Exception/IndexPendingException.php: -------------------------------------------------------------------------------- 1 | product = $product; 21 | 22 | return $this; 23 | } 24 | 25 | /** 26 | * Add related store ID. 27 | * 28 | * @param int $storeId 29 | * 30 | * @return $this 31 | */ 32 | public function withStoreId($storeId) 33 | { 34 | $this->storeId = $storeId; 35 | 36 | return $this; 37 | } 38 | 39 | /** 40 | * Get related product. 41 | * 42 | * @return Mage_Catalog_Model_Product 43 | */ 44 | public function getProduct() 45 | { 46 | return $this->product; 47 | } 48 | 49 | /** 50 | * Get related store ID. 51 | * 52 | * @return int 53 | */ 54 | public function getStoreId() 55 | { 56 | return $this->storeId; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Exception/ProductUnknownSkuException.php: -------------------------------------------------------------------------------- 1 | Configuration > Algolia Search > Queue configuration'; 9 | 10 | public function __construct() 11 | { 12 | parent::__construct(); 13 | 14 | $this->engine = Mage::getResourceModel('algoliasearch/engine'); 15 | } 16 | 17 | /** 18 | * This function will update all the requested categories and their child 19 | * categories in Algolia. You can provide either a single category ID or an 20 | * array of category IDs. A category ID should be either a string or an 21 | * integer. 22 | * 23 | * @param array|string|int $updateCategoryIds 24 | */ 25 | public function reindexSpecificCategories($updateCategoryIds) 26 | { 27 | $updateCategoryIds = (array) $updateCategoryIds; 28 | 29 | foreach ($updateCategoryIds as $id) { 30 | /** @var Mage_Catalog_Model_Category $categoryModel */ 31 | $categoryModel = Mage::getModel('catalog/category'); 32 | $categories = $categoryModel->getCategories($id); 33 | 34 | foreach ($categories as $category) { 35 | $updateCategoryIds[] = $category->getId(); 36 | } 37 | } 38 | 39 | $this->engine->rebuildCategoryIndex(null, $updateCategoryIds); 40 | } 41 | 42 | /** 43 | * This function will update all the requested products and their parent 44 | * products in Algolia. You can provide either a single product ID or an 45 | * array of product IDs. A product ID should be either a string or an 46 | * integer. 47 | * 48 | * @param array|string|int $updateProductIds 49 | */ 50 | public function reindexSpecificProducts($updateProductIds) 51 | { 52 | $updateProductIds = (array) $updateProductIds; 53 | $productIds = $updateProductIds; 54 | 55 | foreach ($updateProductIds as $updateProductId) { 56 | if (!$this->_isProductComposite($updateProductId)) { 57 | $parentIds = $this->_getResource()->getRelationsByChild($updateProductId); 58 | 59 | if (!empty($parentIds)) { 60 | $productIds = array_merge($productIds, $parentIds); 61 | } 62 | } 63 | } 64 | 65 | if (!empty($productIds)) { 66 | $this->engine->rebuildProductIndex(null, $productIds); 67 | } 68 | } 69 | 70 | /** 71 | * @return Mage_CatalogSearch_Model_Resource_Indexer_Fulltext 72 | */ 73 | protected function _getResource() 74 | { 75 | return Mage::getResourceSingleton('catalogsearch/indexer_fulltext'); 76 | } 77 | 78 | /** 79 | * Check whether a product is composite. 80 | * 81 | * @param int $productId 82 | * 83 | * @return bool 84 | */ 85 | protected function _isProductComposite($productId) 86 | { 87 | /** @var Mage_Catalog_Model_Product $product */ 88 | $product = Mage::getModel('catalog/product')->loadByAttribute('entity_id', $productId); 89 | 90 | if ($product === false) { 91 | return false; 92 | } 93 | 94 | return $product->isComposite(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaadditionalsections.php: -------------------------------------------------------------------------------- 1 | engine = new Algolia_Algoliasearch_Model_Resource_Engine(); 18 | $this->config = Mage::helper('algoliasearch/config'); 19 | } 20 | 21 | protected $_matchedEntities = array(); 22 | 23 | protected function _getResource() 24 | { 25 | return Mage::getResourceSingleton('catalogsearch/indexer_fulltext'); 26 | } 27 | 28 | public function getName() 29 | { 30 | return Mage::helper('algoliasearch')->__('Algolia Search Additional autocomplete sections'); 31 | } 32 | 33 | public function getDescription() 34 | { 35 | /** @var Algolia_Algoliasearch_Helper_Data $helper */ 36 | $helper = Mage::helper('algoliasearch'); 37 | $decription = $helper->__('Rebuild additional sections.').' '.$helper->__($this->enableQueueMsg); 38 | 39 | return $decription; 40 | } 41 | 42 | public function matchEvent(Mage_Index_Model_Event $event) 43 | { 44 | return false; 45 | } 46 | 47 | protected function _registerEvent(Mage_Index_Model_Event $event) 48 | { 49 | return $this; 50 | } 51 | 52 | protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event) 53 | { 54 | return $this; 55 | } 56 | 57 | protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event) 58 | { 59 | return $this; 60 | } 61 | 62 | protected function _processEvent(Mage_Index_Model_Event $event) 63 | { 64 | } 65 | 66 | /** 67 | * Rebuild all index data. 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(); 84 | 85 | return $this; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliadeleteproducts.php: -------------------------------------------------------------------------------- 1 | engine = new Algolia_Algoliasearch_Model_Resource_Engine(); 16 | $this->config = Mage::helper('algoliasearch/config'); 17 | } 18 | 19 | public function getName() 20 | { 21 | return Mage::helper('algoliasearch')->__('Algolia Search - Remove inactive products from Algolia'); 22 | } 23 | 24 | public function getDescription() 25 | { 26 | /** @var Algolia_Algoliasearch_Helper_Data $helper */ 27 | $helper = Mage::helper('algoliasearch'); 28 | $decription = $helper->__('Run this indexer only when you want to remove inactive / deleted products from Algolia.'); 29 | 30 | return $decription; 31 | } 32 | 33 | public function matchEvent(Mage_Index_Model_Event $event) 34 | { 35 | return false; 36 | } 37 | 38 | protected function _registerEvent(Mage_Index_Model_Event $event) 39 | { 40 | return $this; 41 | } 42 | 43 | protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event) 44 | { 45 | return $this; 46 | } 47 | 48 | protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event) 49 | { 50 | return $this; 51 | } 52 | 53 | protected function _processEvent(Mage_Index_Model_Event $event) 54 | { 55 | } 56 | 57 | /** 58 | * Rebuild all index data. 59 | */ 60 | public function reindexAll() 61 | { 62 | if ($this->config->isModuleOutputEnabled() === false) { 63 | return $this; 64 | } 65 | 66 | if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) { 67 | /** @var Mage_Adminhtml_Model_Session $session */ 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->engine->deleteInactiveProducts(); 75 | 76 | return $this; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliapages.php: -------------------------------------------------------------------------------- 1 | engine = new Algolia_Algoliasearch_Model_Resource_Engine(); 18 | $this->config = Mage::helper('algoliasearch/config'); 19 | } 20 | 21 | protected $_matchedEntities = array(); 22 | 23 | protected function _getResource() 24 | { 25 | return Mage::getResourceSingleton('catalogsearch/indexer_fulltext'); 26 | } 27 | 28 | public function getName() 29 | { 30 | return Mage::helper('algoliasearch')->__('Algolia Search Pages'); 31 | } 32 | 33 | public function getDescription() 34 | { 35 | /** @var Algolia_Algoliasearch_Helper_Data $helper */ 36 | $helper = Mage::helper('algoliasearch'); 37 | $decription = $helper->__('Rebuild pages.').' '.$helper->__($this->enableQueueMsg); 38 | 39 | return $decription; 40 | } 41 | 42 | public function matchEvent(Mage_Index_Model_Event $event) 43 | { 44 | return false; 45 | } 46 | 47 | protected function _registerEvent(Mage_Index_Model_Event $event) 48 | { 49 | return $this; 50 | } 51 | 52 | protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event) 53 | { 54 | return $this; 55 | } 56 | 57 | protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event) 58 | { 59 | return $this; 60 | } 61 | 62 | protected function _processEvent(Mage_Index_Model_Event $event) 63 | { 64 | } 65 | 66 | /** 67 | * Rebuild all index data. 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(); 84 | 85 | return $this; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliaqueuerunner.php: -------------------------------------------------------------------------------- 1 | config = Mage::helper('algoliasearch/config'); 18 | $this->queue = Mage::getSingleton('algoliasearch/queue'); 19 | } 20 | 21 | protected $_matchedEntities = array(); 22 | 23 | protected function _getResource() 24 | { 25 | return Mage::getResourceSingleton('catalogsearch/indexer_fulltext'); 26 | } 27 | 28 | public function getName() 29 | { 30 | return Mage::helper('algoliasearch')->__('Algolia Search Queue Runner'); 31 | } 32 | 33 | public function getDescription() 34 | { 35 | return Mage::helper('algoliasearch')->__('Process the queue if enabled. This allow to run jobs in the queue'); 36 | } 37 | 38 | public function matchEvent(Mage_Index_Model_Event $event) 39 | { 40 | return false; 41 | } 42 | 43 | protected function _registerEvent(Mage_Index_Model_Event $event) 44 | { 45 | return $this; 46 | } 47 | 48 | protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event) 49 | { 50 | return $this; 51 | } 52 | 53 | protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event) 54 | { 55 | return $this; 56 | } 57 | 58 | protected function _processEvent(Mage_Index_Model_Event $event) 59 | { 60 | } 61 | 62 | /** 63 | * Rebuild all index data. 64 | */ 65 | public function reindexAll() 66 | { 67 | if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || !$this->config->getSearchOnlyAPIKey()) { 68 | /** @var Mage_Adminhtml_Model_Session $session */ 69 | $session = Mage::getSingleton('adminhtml/session'); 70 | $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.'); 71 | 72 | return $this; 73 | } 74 | 75 | $this->queue->runCron(); 76 | 77 | return $this; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Indexer/Algoliasuggestions.php: -------------------------------------------------------------------------------- 1 | engine = new Algolia_Algoliasearch_Model_Resource_Engine(); 18 | $this->config = Mage::helper('algoliasearch/config'); 19 | } 20 | 21 | protected $_matchedEntities = array(); 22 | 23 | protected function _getResource() 24 | { 25 | return Mage::getResourceSingleton('catalogsearch/indexer_fulltext'); 26 | } 27 | 28 | public function getName() 29 | { 30 | return Mage::helper('algoliasearch')->__('Algolia Search Suggestions'); 31 | } 32 | 33 | public function getDescription() 34 | { 35 | /** @var Algolia_Algoliasearch_Helper_Data $helper */ 36 | $helper = Mage::helper('algoliasearch'); 37 | $decription = $helper->__('Rebuild suggestions.').' '.$helper->__($this->enableQueueMsg); 38 | 39 | return $decription; 40 | } 41 | 42 | public function matchEvent(Mage_Index_Model_Event $event) 43 | { 44 | $result = false; 45 | 46 | $event->addNewData(self::EVENT_MATCH_RESULT_KEY, $result); 47 | 48 | return $result; 49 | } 50 | 51 | protected function _registerEvent(Mage_Index_Model_Event $event) 52 | { 53 | return $this; 54 | } 55 | 56 | protected function _registerCatalogProductEvent(Mage_Index_Model_Event $event) 57 | { 58 | return $this; 59 | } 60 | 61 | protected function _registerCatalogCategoryEvent(Mage_Index_Model_Event $event) 62 | { 63 | return $this; 64 | } 65 | 66 | protected function _processEvent(Mage_Index_Model_Event $event) 67 | { 68 | } 69 | 70 | /** 71 | * Rebuild all index data. 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(); 88 | 89 | return $this; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Job.php: -------------------------------------------------------------------------------- 1 | _init('algoliasearch/job'); 17 | } 18 | 19 | /** 20 | * @return string 21 | */ 22 | public function getStatus() 23 | { 24 | $status = Algolia_Algoliasearch_Model_Source_JobStatuses::STATUS_PROCESSING; 25 | 26 | if (is_null($this->getPid())) { 27 | $status = Algolia_Algoliasearch_Model_Source_JobStatuses::STATUS_NEW; 28 | } 29 | 30 | if ((int) $this->getRetries() >= $this->getMaxRetries()) { 31 | $status = Algolia_Algoliasearch_Model_Source_JobStatuses::STATUS_ERROR; 32 | } 33 | 34 | return $status; 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function getStatusLabel() 41 | { 42 | $status = $this->getStatus(); 43 | $labels = Mage::getModel('algoliasearch/source_jobStatuses')->getStatuses(); 44 | 45 | return isset($labels[$status]) ? $labels[$status] : $status; 46 | } 47 | 48 | /** 49 | * @param Exception $e 50 | * 51 | * @return Algolia_Algoliasearch_Model_Job 52 | */ 53 | public function saveError(Exception $e) 54 | { 55 | $this->setErrorLog($e->getMessage()); 56 | $this->save($this); 57 | 58 | return $this; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Observer/Conversion.php: -------------------------------------------------------------------------------- 1 | isClickConversionAnalyticsEnabled($storeId) 18 | && Mage::helper('algoliasearch/config')->getConversionAnalyticsMode($storeId) === 'place_order'; 19 | } 20 | 21 | /** 22 | * @param array $params 23 | * @return bool 24 | */ 25 | protected function _hasRequiredParameters($params = array()) 26 | { 27 | foreach ($this->_analyticsParams as $requiredParam) { 28 | if (!isset($params[$requiredParam])) { 29 | return false; 30 | } 31 | } 32 | 33 | return true; 34 | } 35 | 36 | /** 37 | * @event catalog_controller_product_init_before 38 | */ 39 | public function setAlgoliaParamsToSession(Varien_Event_Observer $observer) 40 | { 41 | $checkoutSession = Mage::getSingleton('checkout/session'); 42 | if (!$this->_isOrderConversionTrackingEnabled($checkoutSession->getQuote()->getStoreId())) { 43 | return; 44 | } 45 | 46 | /** @var Mage_Core_Controller_Front_Action $controllerAction */ 47 | $controllerAction = $observer->getEvent()->getControllerAction(); 48 | $params = $controllerAction->getRequest()->getParams(); 49 | 50 | if (!$this->_hasRequiredParameters($params)) { 51 | return; 52 | } 53 | 54 | $conversionData = array( 55 | 'queryID' => $params['queryID'], 56 | 'indexName' => $params['indexName'], 57 | 'objectID' => $params['objectID'], 58 | ); 59 | 60 | $session = Mage::getSingleton('core/session', array('name' => 'frontend')); 61 | $session->setData('algolia_conversion_parameters', Mage::helper('core')->jsonEncode($conversionData)); 62 | } 63 | 64 | /** 65 | * @event checkout_cart_product_add_after 66 | */ 67 | public function saveAlgoliaParamToQuoteItem(Varien_Event_Observer $observer) 68 | { 69 | /** @var Mage_Sales_Model_Quote_Item $quoteItem */ 70 | $quoteItem = $observer->getEvent()->getQuoteItem(); 71 | /** @var Mage_Catalog_Model_Product $product */ 72 | $product = $observer->getEvent()->getProduct(); 73 | 74 | if ($this->_isOrderConversionTrackingEnabled($product->getStoreId())) { 75 | $session = Mage::getSingleton('core/session'); 76 | $quoteItem->setData('algoliasearch_query_param', $session->getData('algolia_conversion_parameters')); 77 | $session->unsetData('algolia_conversion_parameters'); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Resource/Fulltext.php: -------------------------------------------------------------------------------- 1 | engine = new Algolia_Algoliasearch_Model_Resource_Engine(); 19 | $this->config = Mage::helper('algoliasearch/config'); 20 | $this->logger = Mage::helper('algoliasearch/logger'); 21 | } 22 | 23 | public function prepareResult($object, $queryText, $query) 24 | { 25 | if (!$this->config->getApplicationID() || !$this->config->getAPIKey() || $this->config->isEnabledFrontEnd() === false) { 26 | return parent::prepareResult($object, $queryText, $query); 27 | } 28 | 29 | return $this; 30 | } 31 | 32 | protected function _saveProductIndexes($storeId, $productIndexes) 33 | { 34 | if ($this->config->isEnabledBackend($storeId) === false) { 35 | return parent::_saveProductIndexes($storeId, $productIndexes); 36 | } 37 | 38 | return $this; 39 | } 40 | 41 | /** 42 | * Only used when reindexing everything. Otherwise Model/Indexer/Algolia will take care of the rest. 43 | * 44 | * @param int|null $storeId 45 | * @param array|null $productIds 46 | * 47 | * @return $this|Mage_CatalogSearch_Model_Resource_Fulltext 48 | */ 49 | public function rebuildIndex($storeId = null, $productIds = null) 50 | { 51 | if ($this->config->isModuleOutputEnabled() === false) { 52 | return parent::rebuildIndex($storeId, $productIds); 53 | } 54 | 55 | if ($storeId !== null) { 56 | $this->reindex($storeId, $productIds); 57 | 58 | return $this; 59 | } 60 | 61 | /** @var Mage_Core_Model_Store $store */ 62 | foreach (Mage::app()->getStores() as $store) { 63 | $this->reindex($store->getId(), $productIds); 64 | } 65 | 66 | return $this; 67 | } 68 | 69 | private function reindex($storeId, $productIds) 70 | { 71 | if ($this->config->isEnabledBackend($storeId) === false) { 72 | return parent::rebuildIndex($storeId, $productIds); 73 | } 74 | 75 | return $this->reindexAlgolia($storeId, $productIds); 76 | } 77 | 78 | private function reindexAlgolia($storeId, $productIds) 79 | { 80 | if (!$this->config->getApplicationID($storeId) || !$this->config->getAPIKey($storeId) || !$this->config->getSearchOnlyAPIKey($storeId)) { 81 | /** @var Mage_Adminhtml_Model_Session $session */ 82 | $session = Mage::getSingleton('adminhtml/session'); 83 | $session->addError('Algolia reindexing failed: You need to configure your Algolia credentials in System > Configuration > Algolia Search.'); 84 | 85 | return; 86 | } 87 | 88 | /* Avoid Indexing twice */ 89 | if (is_array($productIds) && $productIds > 0) { 90 | return; 91 | } 92 | 93 | $this->engine->rebuildProducts($storeId); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Resource/Fulltext/Collection.php: -------------------------------------------------------------------------------- 1 | _helper()->isX3Version()) { 13 | return $this; 14 | } 15 | 16 | $query = $this->_getQuery(); 17 | if (is_null($this->_foundData) && !empty($query) && $query instanceof Mage_CatalogSearch_Model_Query) { 18 | $data = $this->getAlgoliaData($query->getQueryText()); 19 | if (false === $data) { 20 | return parent::getFoundIds(); 21 | } 22 | 23 | $this->_foundData = $data; 24 | } 25 | 26 | return parent::getFoundIds(); 27 | } 28 | 29 | /** 30 | * @return Algolia_Algoliasearch_Helper_Data 31 | */ 32 | protected function _helper() 33 | { 34 | return Mage::helper('algoliasearch'); 35 | } 36 | 37 | /** 38 | * @param string $query 39 | * 40 | * @return array|bool 41 | */ 42 | protected function getAlgoliaData($query) 43 | { 44 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 45 | $config = Mage::helper('algoliasearch/config'); 46 | $storeId = Mage::app()->getStore()->getId(); 47 | 48 | if (!$config->getApplicationID() || !$config->getAPIKey() || $config->isEnabledFrontEnd($storeId) === false) { 49 | return false; 50 | } 51 | 52 | $data = array(); 53 | 54 | if ($config->isInstantEnabled($storeId) === false || $config->makeSeoRequest($storeId)) { 55 | $algolia_query = $query !== '__empty__' ? $query : ''; 56 | 57 | try { 58 | $data = $this->_helper()->getSearchResult($algolia_query, $storeId); 59 | } catch (\Exception $e) { 60 | /** @var Algolia_Algoliasearch_Helper_Logger $logger */ 61 | $logger = Mage::helper('algoliasearch/logger'); 62 | 63 | $logger->log($e->getMessage(), true); 64 | $logger->log($e->getTraceAsString(), true); 65 | 66 | return false; 67 | } 68 | } 69 | 70 | return $data; 71 | } 72 | 73 | /** 74 | * @param string $query 75 | * 76 | * @return Algolia_Algoliasearch_Model_Resource_Fulltext_Collection 77 | */ 78 | public function addSearchFilter($query) 79 | { 80 | if ($this->_helper()->isX3Version()) { 81 | return $this; 82 | } 83 | 84 | $data = $this->getAlgoliaData($query); 85 | if (false === $data) { 86 | return parent::addSearchFilter($query); 87 | } 88 | $sortedIds = array_reverse(array_keys($data)); 89 | 90 | $this->getSelect()->columns(array( 91 | 'relevance' => new Zend_Db_Expr("FIND_IN_SET(e.entity_id, '" . implode(',', $sortedIds) . "')"), 92 | )); 93 | $this->getSelect()->where('e.entity_id IN (?)', $sortedIds); 94 | 95 | return $this; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Resource/Job.php: -------------------------------------------------------------------------------- 1 | _init('algoliasearch/job', 'job_id'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Resource/Job/Collection.php: -------------------------------------------------------------------------------- 1 | _init('algoliasearch/job'); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Source/JobMethods.php: -------------------------------------------------------------------------------- 1 | 'Save Settings', 7 | 'saveConfigurationToAlgolia' => 'Save Configuration', 8 | 'moveIndex' => 'Move Index', 9 | 'moveProductsTmpIndex' => 'Move Products Temp Index', 10 | 'deleteObjects' => 'Object Deletion', 11 | 'rebuildStoreCategoryIndex' => 'Store Category Reindex', 12 | 'rebuildCategoryIndex' => 'Category Reindex', 13 | 'rebuildStoreProductIndex' => 'Store Product Reindex', 14 | 'rebuildProductIndex' => 'Product Reindex', 15 | 'rebuildStoreAdditionalSectionsIndex' => 'Store Additional Section Reindex', 16 | 'rebuildAdditionalSectionsIndex' => 'Additional Section Reindex', 17 | 'rebuildStoreSuggestionIndex' => 'Store Suggestion Reindex', 18 | 'rebuildSuggestionIndex' => 'Sugesstion Reindex', 19 | 'rebuildStorePageIndex' => 'Store Page Reindex', 20 | 'rebuildPageIndex' => 'Page Reindex', 21 | ); 22 | 23 | /** 24 | * @return array 25 | */ 26 | public function getMethods() 27 | { 28 | return $this->_methods; 29 | } 30 | 31 | /** 32 | * @return array 33 | */ 34 | public function toOptionArray() 35 | { 36 | $options = array(); 37 | foreach ($this->_methods as $method => $label) { 38 | $option[] = array( 39 | 'value' => $method, 40 | 'label' => $label, 41 | ); 42 | } 43 | return $options; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/Source/JobStatuses.php: -------------------------------------------------------------------------------- 1 | 'New', 12 | self::STATUS_ERROR => 'Error', 13 | self::STATUS_PROCESSING => 'Processing', 14 | self::STATUS_COMPLETE => 'Complete' 15 | ); 16 | 17 | /** 18 | * @return array 19 | */ 20 | public function getStatuses() 21 | { 22 | return $this->_statuses; 23 | } 24 | 25 | /** 26 | * @return array 27 | */ 28 | public function toOptionArray() 29 | { 30 | $options = array(); 31 | foreach ($this->_methods as $method => $label) { 32 | $option[] = array( 33 | 'value' => $method, 34 | 'label' => $label, 35 | ); 36 | } 37 | return $options; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/BackendRenderingDisplayMode.php: -------------------------------------------------------------------------------- 1 | 'all', 'label' => Mage::helper('algoliasearch')->__('All categories')), 9 | array('value' => 'only_products', 'label' => Mage::helper('algoliasearch')->__('Categories without static blocks')), 10 | ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Config/Backend/EnableClickAnalytics.php: -------------------------------------------------------------------------------- 1 | getValue()); 8 | 9 | if ($value !== '1') { 10 | return parent::_beforeSave(); 11 | } 12 | 13 | $context = Mage::helper('algoliasearch/algoliahelper')->getClient()->getContext(); 14 | 15 | $ch = curl_init(); 16 | 17 | $headers = array(); 18 | $headers[] = 'X-Algolia-Api-Key: '.$context->apiKey; 19 | $headers[] = 'X-Algolia-Application-Id: '.$context->applicationID; 20 | $headers[] = 'Content-Type: application/x-www-form-urlencoded'; 21 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 22 | 23 | $postFields = json_encode(array( 24 | 'timestamp' => time(), 25 | 'queryID' => 'a', 26 | 'objectID' => 'non_existent_object_id', 27 | 'position' => 1, 28 | )); 29 | 30 | curl_setopt($ch, CURLOPT_URL, "https://insights.algolia.io/1/searches/click"); 31 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 32 | curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); 33 | curl_setopt($ch, CURLOPT_POST, 1); 34 | 35 | $result = curl_exec($ch); 36 | curl_close($ch); 37 | 38 | if ($result) { 39 | $result = json_decode($result); 40 | if ($result->status === 401 && $result->message === 'Feature not available') { 41 | Mage::throwException( 42 | Mage::helper('algoliasearch')->__('Click & Conversion analytics are not supported on your current plan. Please refer to Algolia\'s pricing page for more details.') 43 | ); 44 | } 45 | } 46 | 47 | return parent::_beforeSave(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Config/Backend/ExtraSettings.php: -------------------------------------------------------------------------------- 1 | getValue()); 8 | 9 | if (empty($value)) { 10 | return parent::_beforeSave(); 11 | } 12 | 13 | $fieldConfig = $this->getFieldConfig(); 14 | $label = (string) $fieldConfig->label; 15 | 16 | json_decode($value); 17 | $error = json_last_error(); 18 | 19 | if ($error) { 20 | Mage::throwException('JSON provided for "'.$label.'" field is not valid JSON.'); 21 | } 22 | 23 | return parent::_beforeSave(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Config/Backend/Serialized/Array.php: -------------------------------------------------------------------------------- 1 | isX3Version()) { 10 | if (!is_array($this->getValue())) { 11 | $value = $this->getValue(); 12 | $this->setValue(empty($value) ? false : \Zend_Serializer::unserialize((string) $value)); 13 | } 14 | 15 | return; 16 | } 17 | 18 | parent::_afterLoad(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Config/Backend/SynonymsFile.php: -------------------------------------------------------------------------------- 1 | '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 | } 20 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/ConversionAnalyticsMode.php: -------------------------------------------------------------------------------- 1 | 'disabled', 'label' => Mage::helper('algoliasearch')->__('[Disabled]')), 11 | array('value' => 'add_to_cart', 'label' => Mage::helper('algoliasearch')->__('Track "Add to cart" action as conversion')), 12 | array('value' => 'place_order', 'label' => Mage::helper('algoliasearch')->__('Track "Place Order" action as conversion')), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Imagetype.php: -------------------------------------------------------------------------------- 1 | 'image', 'label' => Mage::helper('core')->__('Base Image')), 11 | array('value' => 'small_image', 'label' => Mage::helper('core')->__('Small Image')), 12 | array('value' => 'thumbnail', 'label' => Mage::helper('core')->__('Thumbnail')), 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/IndexVisibility.php: -------------------------------------------------------------------------------- 1 | 'all', 'label' => Mage::helper('algoliasearch')->__('All visible products')), 13 | array('value' => 'only_search', 'label' => Mage::helper('algoliasearch')->__('Only products visible in Search')), 14 | array('value' => 'only_catalog', 'label' => Mage::helper('algoliasearch')->__('Only products visible in Catalog')), 15 | ); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/Model/System/Removewords.php: -------------------------------------------------------------------------------- 1 | 'none', 'label' => Mage::helper('algoliasearch')->__('None')), 11 | array('value' => 'allOptional', 'label' => Mage::helper('algoliasearch')->__('AllOptional')), 12 | array('value' => 'lastWords', 'label' => Mage::helper('algoliasearch')->__('LastWords')), 13 | array('value' => 'firstWords', 'label' => Mage::helper('algoliasearch')->__('FirstWords')), 14 | ); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/bin/dump.php: -------------------------------------------------------------------------------- 1 | setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); 6 | 7 | @unlink(Mage::getBaseDir('var') . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR . 'algolia_dump.log'); 8 | 9 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 10 | $config = Mage::helper('algoliasearch/config'); 11 | $configReflection = new ReflectionClass(get_class($config)); 12 | 13 | $allMethods = $configReflection->getMethods(ReflectionMethod::IS_PUBLIC); 14 | 15 | $configMethods = array(); 16 | foreach ($allMethods as $method) { 17 | if ($method->getDeclaringClass()->getName() == get_class($config)) { 18 | $parameters = $method->getParameters(); 19 | $firstParamter = reset($parameters); 20 | if ($method->getNumberOfParameters() === 1 && $firstParamter->getName() === 'storeId') { 21 | $configMethods[] = $method->getName(); 22 | } 23 | } 24 | } 25 | 26 | /** @var Mage_Core_Model_Resource $coreResource */ 27 | $coreResource = Mage::getSingleton('core/resource'); 28 | $db = $coreResource->getConnection('core_read'); 29 | 30 | $configTableName = $coreResource->getTableName('core/config_data'); 31 | 32 | $configRows = $db->query('SELECT path FROM '.$configTableName.' WHERE path LIKE "algolia%"')->fetchAll(); 33 | 34 | /** @var Mage_Core_Model_Store $store */ 35 | foreach (Mage::app()->getStores() as $store) { 36 | $storeId = $store->getId(); 37 | 38 | algolia_dump_log('-- Dump config for store ID '.$storeId.' --'); 39 | 40 | algolia_dump_log('-- Computed values --'); 41 | foreach ($configMethods as $configMethod) { 42 | $result = $config->{$configMethod}($storeId); 43 | algolia_dump_log('$config->'.$configMethod.'('.$storeId.') === '.var_export($result, true)); 44 | } 45 | 46 | algolia_dump_log('-- Raw values --'); 47 | foreach ($configRows as $row) { 48 | algolia_dump_log($row['path'].' === '.var_export(Mage::getStoreConfig($row['path'], $storeId), true)); 49 | } 50 | } 51 | 52 | echo "Dump file was successfully created.\n"; 53 | 54 | function algolia_dump_log($message) 55 | { 56 | Mage::log($message, null, 'algolia_dump.log', true); 57 | } 58 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/controllers/Adminhtml/Algoliasearch/IndexingqueueController.php: -------------------------------------------------------------------------------- 1 | _checkQueueIsActivated(); 13 | return parent::preDispatch(); 14 | } 15 | 16 | public function indexAction() 17 | { 18 | $this->_title($this->__('System')) 19 | ->_title($this->__('Algolia Search')) 20 | ->_title($this->__('Indexing Queue')); 21 | 22 | $this->loadLayout(); 23 | $this->_setActiveMenu('system/algolia/indexing_queue'); 24 | $this->renderLayout(); 25 | } 26 | 27 | public function viewAction() 28 | { 29 | $this->_title($this->__('System')) 30 | ->_title($this->__('Algolia Search')) 31 | ->_title($this->__('Indexing Queue')); 32 | 33 | $id = $this->getRequest()->getParam('id'); 34 | if (!$id) { 35 | Mage::getSingleton('adminhtml/session')->addError( 36 | Mage::helper('algoliasearch')->__('Indexing Queue Job ID is not set.')); 37 | $this->_redirect('*/*/'); 38 | return; 39 | } 40 | 41 | $job = Mage::getModel('algoliasearch/job')->load($id); 42 | if (!$job->getId()) { 43 | Mage::getSingleton('adminhtml/session')->addError( 44 | Mage::helper('algoliasearch')->__('This indexing queue job no longer exists.')); 45 | $this->_redirect('*/*/'); 46 | return; 47 | } 48 | 49 | Mage::register('algoliasearch_current_job', $job); 50 | 51 | $this->loadLayout(); 52 | $this->_setActiveMenu('system/algolia/indexing_queue'); 53 | $this->renderLayout(); 54 | } 55 | 56 | public function clearAction() 57 | { 58 | try { 59 | /** @var Algolia_Algoliasearch_Model_Queue $queue */ 60 | $queue = Mage::getModel('algoliasearch/queue'); 61 | $queue->clearQueue(true); 62 | 63 | Mage::getSingleton('adminhtml/session')->addSuccess('Indexing Queue has been cleared.'); 64 | } catch (Exception $e) { 65 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 66 | } 67 | 68 | $this->_redirect('*/*/'); 69 | } 70 | 71 | public function resetAction() 72 | { 73 | try { 74 | $queueRunnerIndexer = Mage::getModel('index/indexer') 75 | ->getProcessByCode(Algolia_Algoliasearch_Model_Indexer_Algoliaqueuerunner::INDEXER_ID); 76 | $queueRunnerIndexer->setStatus(Mage_Index_Model_Process::STATUS_PENDING); 77 | $queueRunnerIndexer->save(); 78 | 79 | Mage::getSingleton('adminhtml/session')->addSuccess('Indexing Queue has been reset.'); 80 | } catch (Exception $e) { 81 | Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); 82 | } 83 | 84 | $this->_redirect('*/*/'); 85 | } 86 | 87 | protected function _checkQueueIsActivated() 88 | { 89 | if (!Mage::helper('algoliasearch/config')->isQueueActive()) { 90 | Mage::getSingleton('adminhtml/session')->addWarning( 91 | $this->__('The indexing queue is not enabled. Please activate it in your Algolia configuration.', 92 | $this->getUrl('adminhtml/system_config/edit/section/algoliasearch'))); 93 | } 94 | } 95 | 96 | /** 97 | * Check ACL permissions. 98 | * 99 | * @return bool 100 | */ 101 | protected function _isAllowed() 102 | { 103 | return Mage::getSingleton('admin/session')->isAllowed('system/algoliasearch/indexing_queue'); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/controllers/Adminhtml/Algoliasearch/QueueController.php: -------------------------------------------------------------------------------- 1 | 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 | $this->sendResponse($queueInfo); 41 | } 42 | 43 | public function truncateAction() 44 | { 45 | try { 46 | /** @var Algolia_Algoliasearch_Model_Queue $queue */ 47 | $queue = Mage::getModel('algoliasearch/queue'); 48 | $queue->clearQueue(true); 49 | 50 | $status = array('status' => 'ok'); 51 | } catch (\Exception $e) { 52 | $status = array('status' => 'ko', 'message' => $e->getMessage()); 53 | } 54 | 55 | $this->sendResponse($status); 56 | } 57 | 58 | private function sendResponse($data) 59 | { 60 | $this->getResponse()->setHeader('Content-Type', 'application/json'); 61 | $this->getResponse()->setBody(json_encode($data)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/etc/adminhtml.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Algolia Search 8 | 93 9 | 10 | 11 | Configurations 12 | adminhtml/system_config/edit/section/algoliasearch 13 | 0 14 | 15 | 16 | Indexing Queue 17 | adminhtml/algoliasearch_indexingqueue 18 | 10 19 | 20 | 21 | Reindex SKU(s) 22 | adminhtml/algoliasearch_reindexsku 23 | 20 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | Algolia Search Configuration 40 | 100 41 | 42 | 43 | 44 | 45 | Algolia Search 46 | 47 | 48 | Indexing Queue 49 | 100 50 | 51 | 52 | Reindex SKU(s) 53 | 110 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-install-0.1.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 7 | 8 | $installer->run(" 9 | CREATE TABLE IF NOT EXISTS `{$installer->getTable('algoliasearch/queue')}` ( 10 | `job_id` int(20) NOT NULL auto_increment, 11 | `pid` int(20) NULL, 12 | `class` varchar(50) NOT NULL, 13 | `method` varchar(50) NOT NULL, 14 | `data` varchar(5000) NOT NULL, 15 | `max_retries` int(11) NOT NULL DEFAULT 3, 16 | `retries` int(11) NOT NULL DEFAULT 0, 17 | `error_log` text NOT NULL DEFAULT '', 18 | PRIMARY KEY `job_id` (`job_id`) 19 | ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 AUTO_INCREMENT=1; 20 | "); 21 | 22 | $installer->endSetup(); 23 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-0.1.0-1.4.8.php: -------------------------------------------------------------------------------- 1 | startSetup(); 7 | 8 | $table = Mage::getConfig()->getTablePrefix().'sales_flat_order_item'; 9 | $installer->run("ALTER TABLE `{$table}` ADD INDEX `IDX_ALGOLIA_SALES_FLAT_ORDER_ITEM_PRODUCT_ID` (`product_id`);"); 10 | 11 | $table = Mage::getConfig()->getTablePrefix().'review_entity_summary'; 12 | $installer->run("ALTER TABLE `{$table}` ADD INDEX `IDX_ALGOLIA_REVIEW_ENTITY_SUMMARY_ENTITY_PK_VALUE_STORE_ID` (`store_id`, `entity_pk_value`);"); 13 | 14 | $installer->endSetup(); 15 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.11.1-1.12.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 9 | 10 | $tableName = $installer->getTable('algoliasearch/queue'); 11 | 12 | $installer->getConnection()->addColumn($tableName, 'created', array( 13 | 'type' => Varien_Db_Ddl_Table::TYPE_DATETIME, 14 | 'after' => 'job_id', 15 | 'nullable' => true, 16 | 'comment' => 'Time of job creation', 17 | )); 18 | 19 | $installer->run(" 20 | CREATE TABLE IF NOT EXISTS `{$tableName}_log` ( 21 | `id` INT(20) NOT NULL auto_increment, 22 | `started` DATETIME NOT NULL, 23 | `duration` INT(20) NOT NULL, 24 | `processed_jobs` INT NOT NULL, 25 | `with_empty_queue` INT(1) NOT NULL, 26 | PRIMARY KEY `id` (`id`) 27 | ) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 AUTO_INCREMENT=1; 28 | "); 29 | 30 | $installer->endSetup(); 31 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.14.1-1.15.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 5 | 6 | $tableName = $installer->getTable('algoliasearch/queue_archive'); 7 | 8 | $installer->run(" 9 | CREATE TABLE IF NOT EXISTS `{$tableName}` ( 10 | `pid` int(11) DEFAULT NULL COMMENT 'Pid', 11 | `class` varchar(50) NOT NULL COMMENT 'Class', 12 | `method` varchar(50) NOT NULL COMMENT 'Method', 13 | `data` text NOT NULL COMMENT 'Data', 14 | `error_log` text NOT NULL COMMENT 'Error Log', 15 | `data_size` int(11) DEFAULT NULL COMMENT 'Data Size', 16 | `created_at` datetime NOT NULL COMMENT 'Created At' 17 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 18 | "); 19 | 20 | $installer->endSetup(); 21 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.15.0-1.16.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 5 | 6 | $tableName = $installer->getTable('algoliasearch/queue'); 7 | 8 | $installer->getConnection()->addColumn($tableName, 'locked_at', array( 9 | 'type' => Varien_Db_Ddl_Table::TYPE_DATETIME, 10 | 'after' => 'job_id', 11 | 'nullable' => true, 12 | 'comment' => 'Time of job creation', 13 | )); 14 | 15 | $installer->endSetup(); 16 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.16.0-1.17.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 5 | 6 | $setup = new Mage_Sales_Model_Resource_Setup('core_setup'); 7 | 8 | $setup->addAttribute( 9 | 'quote_item', 10 | 'algoliasearch_query_param', 11 | array( 12 | 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, 13 | 'grid' => false, 14 | 'comment' => 'AlgoliaSearch Conversion Query Parameters' 15 | ) 16 | ); 17 | 18 | $setup->addAttribute( 19 | 'order_item', 20 | 'algoliasearch_query_param', 21 | array( 22 | 'type' => Varien_Db_Ddl_Table::TYPE_TEXT, 23 | 'grid' => false, 24 | 'comment' => 'AlgoliaSearch Conversion Query Parameters' 25 | ) 26 | ); 27 | 28 | $installer->endSetup(); 29 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.4.8-1.5.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 7 | 8 | /* Need a truncate since now everything is json_encoded and not serialized */ 9 | $installer->run("TRUNCATE TABLE `{$installer->getTable('algoliasearch/queue')}`"); 10 | $installer->run("ALTER TABLE `{$installer->getTable('algoliasearch/queue')}` ADD data_size INT(11);"); 11 | 12 | $index_prefix = Mage::getConfig()->getTablePrefix(); 13 | $installer->run('DELETE FROM `'.$index_prefix."core_config_data` WHERE `path` LIKE '%algolia%'"); 14 | 15 | $installer->endSetup(); 16 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.5.5-1.6.0.php: -------------------------------------------------------------------------------- 1 | startSetup(); 7 | 8 | // Need to transform "removeProducts" to "rebuildProductIndex" as re-indexing was refactored and "removeProducts" do not exists anymore 9 | $installer->run("DELETE FROM `{$installer->getTable('algoliasearch/queue')}`"); 10 | 11 | $installer->endSetup(); 12 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.6.0-1.7.1.php: -------------------------------------------------------------------------------- 1 | startSetup(); 6 | 7 | $tableName = Mage::getSingleton('core/resource')->getTableName('algoliasearch/queue'); 8 | 9 | $installer->run('ALTER TABLE ' . $tableName . ' MODIFY data LONGTEXT NOT NULL'); 10 | 11 | $installer->endSetup(); 12 | -------------------------------------------------------------------------------- /app/code/community/Algolia/Algoliasearch/sql/algoliasearch_setup/mysql4-upgrade-1.7.1-1.11.1.php: -------------------------------------------------------------------------------- 1 | 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(); 22 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/layout/algoliasearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | algoliasearch/algoliasearch.css 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/algoliasearch/adminjs.phtml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/algoliasearch/notifications.phtml: -------------------------------------------------------------------------------- 1 | getQueueInfo(); 4 | ?> 5 | 6 |
7 | Algolia Search - 8 | 9 | 10 | Indexing queue information: 11 | 12 | 13 | Number of queued jobs: , 14 | all queued jobs will be processed in appr. , 15 | more information about how the indexing queue works you can find in the documentation: Indexing queue 16 | 17 | 18 | Indexing queue is not enabled. 19 | 20 | 21 | 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: Indexing queue 22 | 23 |
24 | -------------------------------------------------------------------------------- /app/design/adminhtml/default/default/template/algoliasearch/queue/status.phtml: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

5 | __('Status of the queue: %s', $this->getQueueRunnerStatus()); ?>
6 | getLastQueueUpdate()): ?> 7 | __('Last update: %s', $this->getLastQueueUpdate()); ?> 8 | 9 |

10 | getNotices() ?> 11 | 12 |

13 | 14 |
15 |
-------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete.phtml: -------------------------------------------------------------------------------- 1 | helper('catalogsearch'); 8 | 9 | $placeholder = $this->__('Search for products, categories, ...'); 10 | 11 | /** Render form with autocomplete input **/ 12 | ?> 13 | 14 |
15 | 21 |
22 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/attribute.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/category.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/menu.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/page.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/product.phtml: -------------------------------------------------------------------------------- 1 | getCustomerGroupId(); 9 | 10 | $storeId = Mage::app()->getStore()->getStoreId(); 11 | $currencyCode = Mage::app()->getStore()->getCurrentCurrencyCode(); 12 | 13 | $priceKey = '.'.$currencyCode.'.default'; 14 | if ($config->isCustomerGroupsEnabled($storeId)) { 15 | $priceKey = '.'.$currencyCode.'.group_'.$customerGroupId; 16 | } 17 | 18 | ?> 19 | 20 | 21 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/autocomplete/suggestion.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/checkout/success/conversion.phtml: -------------------------------------------------------------------------------- 1 | getOrderItemsConversionJson(); 4 | ?> 5 | 6 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/instantsearch/currentRefinements.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/instantsearch/hit.phtml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/instantsearch/refinementsItem.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/instantsearch/stats.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/algoliasearch/internals/beforecontent.phtml: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /app/etc/modules/Algolia_Algoliasearch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 1.19.0 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/locale/en_US/Algolia_Algoliasearch.csv: -------------------------------------------------------------------------------- 1 | "Algolia Search Products", "Algolia Search Products" 2 | "Rebuild products.", "Rebuild products." 3 | "Algolia Search Categories", "Algolia Search Categories" 4 | "Rebuild categories.", "Rebuild categories." 5 | "Algolia Search Pages", "Algolia Search Pages" 6 | "Rebuild pages.", "Rebuild pages." 7 | "Algolia Search Suggestions", "Algolia Search Suggestions" 8 | "Rebuild suggestions.", "Rebuild suggestions." 9 | "Rebuild additional sections.", "Rebuild additional sections." 10 | "Please enable the queueing system to do it asynchronously (CRON) if you have a lot of products in System > Configuration > Algolia Search > Queue configuration", "Please enable the queueing system to do it asynchronously (CRON) if you have a lot of products in System > Configuration > Algolia Search > Queue configuration" 11 | "Algolia Search Queue Runner", "Algolia Search Queue Runner" 12 | "Process the queue if enabled. This allow to run jobs in the queue", "Process the queue if enabled. This allow to run jobs in the queue" 13 | "Section", "Section" 14 | "Label", "Label" 15 | "Hits per page", "Hits per page" 16 | "Add Section", "Add Section" 17 | "Attribute", "Attribute" 18 | "Searchable", "Searchable" 19 | "Retrievable", "Retrievable" 20 | "Ordered", "Ordered" 21 | "Add Attribute", "Add Attribute" 22 | "Asc / Desc", "Asc / Desc" 23 | "Add Ranking Criterion", "Add Ranking Criterion" 24 | "Facet type", "Facet type" 25 | "Add Facet", "Add Facet" 26 | "Sort", "Sort" 27 | "Add Sorting Attribute", "Add Sorting Attribute" 28 | "Pages", "Pages" 29 | "Add Excluded Page", "Add Excluded Page" 30 | "Search by", "Search by" 31 | "Search for products, categories, ...", "Search for products, categories, ..." 32 | "Search:", "Search:" 33 | "in", "in" 34 | "Categories", "Categories" 35 | "Products", "Products" 36 | "Refine", "Refine" 37 | "Current search", "Current search" 38 | "Search for products", "Search for products" 39 | "SORT BY", "SORT BY" 40 | "Add to Cart", "Add to Cart" 41 | "result found", "result found" 42 | "results found", "results found" 43 | "out of", "out of" 44 | "seconds", "seconds" 45 | "Relevance", "Relevance" 46 | "No products for query", "No products for query" 47 | "You can try one of the popular search queries", "You can try one of the popular search queries" 48 | "or", "or" 49 | "See all products", "See all products" 50 | "Selected Filters", "Selected Filters" 51 | "Clear all", "Clear all" 52 | "Previous page", "Previous page" 53 | "Next page", "Next page" 54 | "to", "to" 55 | "Go", "Go" 56 | "No results", "No results" 57 | "All departments", "All departments" 58 | "See products in", "See products in" 59 | "or in", "or in" 60 | "Base Image", "Base Image" 61 | "Small Image", "Small Image" 62 | "Thumbnail", "Thumbnail" 63 | "None", "None" 64 | "AllOptional", "AllOptional" 65 | "LastWords", "LastWords" 66 | "FirstWords", "FirstWords" 67 | "Synonyms (comma-separated)", "Synonyms (comma-separated)" 68 | "Add Synonyms", "Add Synonyms" 69 | "Add One-way Synonyms", "Add One-way Synonyms" 70 | "Input", "Input" 71 | "Synonyms", "Synonyms" 72 | "One-way Synonyms", "One-way Synonyms" 73 | "Synonyms File", "Synonyms File" 74 | "Search for other ...","Search for other ..." -------------------------------------------------------------------------------- /app/locale/nl_NL/Algolia_Algoliasearch.csv: -------------------------------------------------------------------------------- 1 | "Algolia Search Products", "Algolia Zoek Producten" 2 | "Rebuild products.", "Rebuild producten." 3 | "Algolia Search Categories", "Algolia Zoek Categorieën" 4 | "Rebuild categories.", "Rebuild categorieën." 5 | "Algolia Search Pages", "Algolia Zoek Pagina's" 6 | "Rebuild pages.", "Rebuild pagina's." 7 | "Algolia Search Suggestions", "Algolia Zoek Suggesties" 8 | "Rebuild suggestions.", "Rebuild suggesties." 9 | "Rebuild additional sections.", "Rebuild additionele secties." 10 | "Please enable the queueing system to do it asynchronously (CRON) if you have a lot of products in System > Configuration > Algolia Search > Queue configuration", "Schakel het queue systeem in om het asynchroon (CRON) te doen wanneer je veel producten hebt in Systeem > Configuratie > Algolia Zoeken > Queue configuratie" 11 | "Algolia Search Queue Runner", "Algolia Zoek Queue Runner" 12 | "Process the queue if enabled. This allow to run jobs in the queue", "Gaat alle queue processen af wanneer ingeschakeld." 13 | "Section", "Sectie" 14 | "Label", "Label" 15 | "Hits per page", "Resultaten per pagina" 16 | "Add Section", "Add Sectie" 17 | "Attribute", "Attribuut" 18 | "Searchable", "Doorzoekbaar" 19 | "Retrievable", "Op te halen" 20 | "Ordered", "Gerangschikt" 21 | "Add Attribute", "Attribuut toevoegen" 22 | "Asc / Desc", "Op- / aflopend" 23 | "Add Ranking Criterion", "Ranking criterium toevoegen" 24 | "Facet type", "Facet type" 25 | "Add Facet", "Facet toevoegen" 26 | "Sort", "Sorteren" 27 | "Add Sorting Attribute", "Sortering attribuut toevoegen" 28 | "Pages", "Pagina's" 29 | "Add Excluded Page", "Uitgeslote pagina's toevoegen" 30 | "Search by", "Zoeken op" 31 | "Search for products, categories, ...", "Zoek naar producten, categorieën, ..." 32 | "Search:", "Zoeken:" 33 | "in", "in" 34 | "Categories", "Categorieën" 35 | "Products", "Producten" 36 | "Refine", "Verfijnen" 37 | "Current search", "Huidige zoekopdracht" 38 | "Search for products", "Zoek naar producten" 39 | "SORT BY", "Sorteren op" 40 | "Add to Cart", "Toevoegen aan winkelwagen" 41 | "result found", "resultaat gevonden" 42 | "results found", "resultaten gevonden" 43 | "out of", "van de" 44 | "seconds", "seconden" 45 | "Relevance", "Relevantie" 46 | "No products for query", "Geen producten voor zoekopdracht" 47 | "You can try one of the popular search queries", "Probeer een van de populaire zoektermen" 48 | "or", "of" 49 | "See all products", "Bekijk alle producten" 50 | "Selected Filters", "Geselecteerde filters" 51 | "Clear all", "Wis alles" 52 | "Previous page", "Vorige pagina" 53 | "Next page", "Volgende pagina" 54 | "to", "naar" 55 | "Go", "Gaan" 56 | "No results", "Geen resultaten" 57 | "All departments", "Alle afdelingen" 58 | "See products in", "Toon producten in" 59 | "or in", "of in" 60 | "Base Image", "Standaard afbeelding" 61 | "Small Image", "Kleine afbeelding" 62 | "Thumbnail", "Miniatuur" 63 | "None", "Geen" 64 | "AllOptional", "Alle optioneel" 65 | "LastWords", "Laatste woorden" 66 | "FirstWords", "Eerste woorden" 67 | "Synonyms (comma-separated)", "Synoniemen (komma gescheiden)" 68 | "Add Synonyms", "Synoniem toevoegen" 69 | "Add One-way Synonyms", "One-way synoniem toevoegen" 70 | "Input", "Invoer" 71 | "Synonyms", "Synoniemen" 72 | "One-way Synonyms", "One-way synoniemen" 73 | "Synonyms File", "Synoniemen bestand" -------------------------------------------------------------------------------- /app/locale/sv_SE/Algolia_Algoliasearch.csv: -------------------------------------------------------------------------------- 1 | "Algolia Search Products", "Algolia Sök Produkter" 2 | "Rebuild products.", "Bygg om produkter." 3 | "Algolia Search Categories", "Algolia Sök Kategorier" 4 | "Rebuild categories.", "Bygg om kategorier." 5 | "Algolia Search Pages", "Algolia Sök Sidor" 6 | "Rebuild pages.", "Bygg om sidor." 7 | "Algolia Search Suggestions", "Algolia Sök Förslag" 8 | "Rebuild suggestions.", "Bygg om förslag." 9 | "Rebuild additional sections.", "Bygg om extra sektioner." 10 | "Please enable the queueing system to do it asynchronously (CRON) if you have a lot of products in System > Configuration > Algolia Search > Queue configuration", "Vänligen aktivera kösystemet för att göra det asynkront (CRON) om du har en många produkter i System > Konfiguration > Algolia Sök > Queue configuration" 11 | "Algolia Search Queue Runner", "Algolia Search Queue Runner" 12 | "Process the queue if enabled. This allow to run jobs in the queue", "Bearbeta kön om den är aktiverad. Detta gör det möjligt att köra jobb i kön" 13 | "Section", "Sektion" 14 | "Label", "Etikett" 15 | "Hits per page", "Träffar per sida" 16 | "Add Section", "Lägg till Sektion" 17 | "Attribute", "Attribut" 18 | "Searchable", "Sökbar" 19 | "Retrievable", "Hämtbar" 20 | "Ordered", "Sorterad" 21 | "Add Attribute", "Lägg till Attribut" 22 | "Asc / Desc", "Stigande / Minskande" 23 | "Add Ranking Criterion", "Lägg till Ranking Kriterium" 24 | "Facet type", "Facet typ" 25 | "Add Facet", "Lägg till Facet" 26 | "Sort", "Sortera" 27 | "Add Sorting Attribute", "Lägg till Sorteringsattribut" 28 | "Pages", "Sidor" 29 | "Add Excluded Page", "Lägg till Utesluten Sida" 30 | "Search by", "Sök efter" 31 | "Search for products, categories, ...", "Sök efter produkter, kategorier, ..." 32 | "Search:", "Sök:" 33 | "in", "i" 34 | "Categories", "Kategorier" 35 | "Products", "Produkter" 36 | "Refine", "Finslipa" 37 | "Current search", "Nuvarande sökning" 38 | "Search for products", "Sök efter produkter" 39 | "SORT BY", "SORTERA EFTER" 40 | "Add to Cart", "Lägg i kundvagn" 41 | "result", "resultat" 42 | "results found", "resultat hittade" 43 | "seconds", "sekunder" 44 | "Relevance", "Relevans" 45 | "No products for query", "Inga produkter för frågan" 46 | "You can try one of the popular search queries", "Du kan prova en av de populära sökfrågorna" 47 | "or", "eller" 48 | "See all products", "Visa alla produkter" 49 | "Selected Filters", "Valda filter" 50 | "Clear all", "Rensa alla" 51 | "Previous page", "Föregående sida" 52 | "Next page", "Nästa sida" 53 | "to", "till" 54 | "Go", "Kör" 55 | "No results", "Inga resultat" 56 | "All departments", "Alla avdelningar" 57 | "See products in", "Visa produkter i" 58 | "or in", "eller i" 59 | "Base Image","Bild på produktsida" 60 | "Small Image","Bild i kategorivy" 61 | "Thumbnail","Bild i varukorg" 62 | "None", "Ingen" 63 | "AllOptional", "AllOptional" 64 | "LastWords", "LastWords" 65 | "FirstWords", "FirstWords" 66 | "Synonyms (comma-separated)", "Synonymer (comma-separerade)" 67 | "Add Synonyms", "Lägg till Synonymer" 68 | "Add One-way Synonyms", "Lägg till One-way Synonymer" 69 | "Input", "Input" 70 | "Synonyms", "Synonymer" 71 | "One-way Synonyms", "One-way Synonymer" 72 | "Synonyms File", "Fil för Synonymer" -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "algolia/algoliasearch-magento", 3 | "type": "magento-module", 4 | "license": "MIT", 5 | "homepage": "https://github.com/algolia/algoliasearch-magento", 6 | "description": "Algolia Search for Magento", 7 | "require": { 8 | "magento-hackathon/magento-composer-installer": "*" 9 | }, 10 | "require-dev": { 11 | "phpunit/phpunit": "^6.0" 12 | }, 13 | "extra": { 14 | "magento-root-dir": "/var/www/htdocs" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "": "tests/" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dev/Dockerfile.base: -------------------------------------------------------------------------------- 1 | FROM occitech/magento:php7.0-apache 2 | 3 | # packages/dependencies installation 4 | RUN apt-get update && apt-get install -y \ 5 | mysql-server \ 6 | libxml2-dev \ 7 | git-core \ 8 | wget 9 | 10 | RUN docker-php-ext-install soap 11 | RUN docker-php-ext-install mysqli 12 | 13 | COPY bin/php.ini /usr/local/etc/php/php.ini 14 | 15 | RUN sed -i -e 's/\/var\/www\/html/\/var\/www\/htdocs/' /etc/apache2/sites-enabled/000-default.conf 16 | 17 | ## download & install Magento 18 | ARG MAGENTO_VERSION 19 | 20 | RUN cd /tmp && curl -O https://demos-cdn.algolia.com/magento/archive/magento-$MAGENTO_VERSION.tar.gz && tar xf magento-$MAGENTO_VERSION.tar.gz && mv magento/* magento/.htaccess /var/www/htdocs 21 | COPY ./bin/install-magento /usr/local/bin/install-magento 22 | RUN chmod +x /usr/local/bin/install-magento 23 | 24 | ## sample dataset import 25 | RUN cd /tmp && curl -O https://demos-cdn.algolia.com/magento/archive/magento-sample-data-1.9.0.0.tar.gz && tar xf magento-sample-data-1.9.0.0.tar.gz 26 | RUN cd /var/www/htdocs/media && cp -R /tmp/magento-sample-data-1.9.0.0/media/* . && chmod -R 777 /var/www/htdocs/media 27 | RUN cd /var/www/htdocs/skin && cp -R /tmp/magento-sample-data-1.9.0.0/skin/* . 28 | RUN chown -R www-data:www-data /var/www/htdocs 29 | 30 | ## database setup 31 | RUN service mysql start && \ 32 | mysql -u root -e "CREATE DATABASE magento;" 33 | 34 | RUN service mysql start && \ 35 | mysql -u root -e "CREATE USER 'magento'@'localhost' IDENTIFIED BY 'P4ssw0rd'; GRANT ALL PRIVILEGES ON *.* TO 'magento'@'localhost'; FLUSH PRIVILEGES;" 36 | 37 | RUN service mysql start && \ 38 | mysql -u root magento < /tmp/magento-sample-data-1.9.0.0/magento_sample_data_for_1.9.0.0.sql 39 | 40 | RUN service mysql start && \ 41 | MYSQL_HOST=127.0.0.1 MYSQL_USER=magento MYSQL_PASSWORD=P4ssw0rd MYSQL_DATABASE=magento MAGENTO_LOCALE=en_US MAGENTO_TIMEZONE=Europe/Paris MAGENTO_DEFAULT_CURRENCY=USD MAGENTO_URL=http://mymagentostore.com MAGENTO_ADMIN_FIRSTNAME=Admin MAGENTO_ADMIN_LASTNAME=MyStore MAGENTO_ADMIN_EMAIL=amdin@mymagentostore.com MAGENTO_ADMIN_USERNAME=admin MAGENTO_ADMIN_PASSWORD=magentorocks1 /usr/local/bin/install-magento 42 | 43 | ## configure Magento 44 | RUN service mysql start && \ 45 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs cache:flush && \ 46 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs cache:disable && \ 47 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set dev/template/allow_symlink "1" >/dev/null 2>&1 && \ 48 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs admin:notifications >/dev/null 2>&1 && \ 49 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set admin/security/use_form_key "0" >/dev/null 2>&1 50 | 51 | # algoliasearch-magento setup 52 | RUN cd /tmp && curl -s -L -O https://raw.github.com/colinmollenhour/modman/master/modman-installer && chmod +x modman-installer && ./modman-installer 53 | RUN cd /var/www/htdocs && /root/bin/modman init && /root/bin/modman clone https://github.com/algolia/algoliasearch-magento && rm -rf .modman/algoliasearch-magento 54 | RUN cd /var/www/htdocs && /root/bin/modman clone https://github.com/algolia/algoliasearch-magento-extend-module-skeleton && rm -rf .modman/algoliasearch-magento-extend-module-skeleton 55 | 56 | # release config file 57 | COPY ./bin/algoliasearch.xml /var/www/htdocs/var/connect/algoliasearch.xml 58 | COPY ./bin/makeRelease.php /var/www/htdocs/makeRelease.php 59 | 60 | #path admin template to have credentials filled && auto login 61 | RUN sed -i 's/name="login\[username\]" value=""/name="login[username]" value="admin"/g' /var/www/htdocs/app/design/adminhtml/default/default/template/login.phtml && \ 62 | sed -i 's/name="login\[password\]" class="required-entry input-text" value=""/name="login[password]" class="required-entry input-text" value="magentorocks1"/g' /var/www/htdocs/app/design/adminhtml/default/default/template/login.phtml && \ 63 | sed -i 's/<\/script>/Event.observe(window, "load", function() {$("loginForm").submit();});<\/script>/g' /var/www/htdocs/app/design/adminhtml/default/default/template/login.phtml && \ 64 | sed -i "s/#ini_set('display_errors', 1);/ini_set('display_errors', 1);error_reporting(E_ALL);Mage::setIsDeveloperMode(true);/g" /var/www/htdocs/index.php && \ 65 | sed -i "s/\$out .= \$this->getBlock(\$callback\[0\])->\$callback\[1\]()/\$out .= \$this->getBlock(\$callback\[0\])->{\$callback\[1\]}()/g" /var/www/htdocs/app/code/core/Mage/Core/Model/Layout.php 66 | -------------------------------------------------------------------------------- /dev/Dockerfile.dev: -------------------------------------------------------------------------------- 1 | FROM algolia/base-algoliasearch-magento 2 | 3 | # packages/dependencies installation 4 | RUN apt-get update && apt-get install -y \ 5 | vim emacs-nox \ 6 | zsh 7 | 8 | RUN chsh -s /bin/zsh 9 | RUN sh -x -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | grep -v 'set -e')" 10 | COPY bin/.zshrc /root/.zshrc 11 | 12 | ARG INSTALL_XDEBUG 13 | RUN if [ $INSTALL_XDEBUG = Yes ]; then pecl install xdebug && docker-php-ext-enable xdebug; fi 14 | 15 | RUN cd /tmp && curl -O https://phpmyadmin-downloads-532693.c.cdn77.org/phpMyAdmin/4.4.9/phpMyAdmin-4.4.9-english.tar.gz && tar xf phpMyAdmin-4.4.9-english.tar.gz && mv phpMyAdmin-4.4.9-english /var/www/htdocs/phpmyadmin 16 | COPY bin/config.inc.php /var/www/htdocs/phpmyadmin/ 17 | 18 | # start script 19 | COPY ./bin/start.sh /usr/local/bin/start.sh 20 | RUN chmod +x /usr/local/bin/start.sh 21 | 22 | # GO 23 | EXPOSE 80 24 | CMD start.sh 25 | -------------------------------------------------------------------------------- /dev/Dockerfile.test: -------------------------------------------------------------------------------- 1 | FROM algolia/base-algoliasearch-magento 2 | 3 | ARG INSTALL_XDEBUG 4 | RUN if [ $INSTALL_XDEBUG = Yes ]; then pecl install xdebug && docker-php-ext-enable xdebug; fi 5 | 6 | # test script 7 | COPY ./bin/test.sh /usr/local/bin/test.sh 8 | RUN chmod +x /usr/local/bin/test.sh 9 | 10 | # GO 11 | ENTRYPOINT test.sh 12 | -------------------------------------------------------------------------------- /dev/bin/.zshrc: -------------------------------------------------------------------------------- 1 | # Path to your oh-my-zsh installation. 2 | export ZSH=$HOME/.oh-my-zsh 3 | 4 | # Set name of the theme to load. 5 | # Look in ~/.oh-my-zsh/themes/ 6 | # Optionally, if you set this to "random", it'll load a random theme each 7 | # time that oh-my-zsh is loaded. 8 | ZSH_THEME="robbyrussell" 9 | 10 | # Example aliases 11 | # alias zshconfig="mate ~/.zshrc" 12 | # alias ohmyzsh="mate ~/.oh-my-zsh" 13 | 14 | # Uncomment the following line to use case-sensitive completion. 15 | # CASE_SENSITIVE="true" 16 | 17 | # Uncomment the following line to disable bi-weekly auto-update checks. 18 | # DISABLE_AUTO_UPDATE="true" 19 | 20 | # Uncomment the following line to change how often to auto-update (in days). 21 | # export UPDATE_ZSH_DAYS=13 22 | 23 | # Uncomment the following line to disable colors in ls. 24 | # DISABLE_LS_COLORS="true" 25 | 26 | # Uncomment the following line to disable auto-setting terminal title. 27 | # DISABLE_AUTO_TITLE="true" 28 | 29 | # Uncomment the following line to disable command auto-correction. 30 | # DISABLE_CORRECTION="true" 31 | 32 | # Uncomment the following line to display red dots whilst waiting for completion. 33 | # COMPLETION_WAITING_DOTS="true" 34 | 35 | # Uncomment the following line if you want to disable marking untracked files 36 | # under VCS as dirty. This makes repository status check for large repositories 37 | # much, much faster. 38 | # DISABLE_UNTRACKED_FILES_DIRTY="true" 39 | 40 | # Uncomment the following line if you want to change the command execution time 41 | # stamp shown in the history command output. 42 | # The optional three formats: "mm/dd/yyyy"|"dd.mm.yyyy"|"yyyy-mm-dd" 43 | # HIST_STAMPS="mm/dd/yyyy" 44 | 45 | # Would you like to use another custom folder than $ZSH/custom? 46 | # ZSH_CUSTOM=/path/to/new-custom-folder 47 | 48 | # Which plugins would you like to load? (plugins can be found in ~/.oh-my-zsh/plugins/*) 49 | # Custom plugins may be added to ~/.oh-my-zsh/custom/plugins/ 50 | # Example format: plugins=(rails git textmate ruby lighthouse) 51 | plugins=(git, laravel4) 52 | 53 | source /root/.oh-my-zsh/oh-my-zsh.sh 54 | 55 | # User configuration 56 | 57 | export PATH="/opt/local/bin:/opt/local/sbin:/opt/local/bin:/opt/local/sbin:/opt/local/bin:/opt/lampp/bin:/home/maxiloc/usr/bin:/bin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin" 58 | # export MANPATH="/usr/local/man:$MANPATH" 59 | 60 | # You may need to manually set your language environment 61 | # export LANG=en_US.UTF-8 62 | 63 | # Preferred editor for local and remote sessions 64 | # if [[ -n $SSH_CONNECTION ]]; then 65 | # export EDITOR='vim' 66 | # else 67 | # export EDITOR='mvim' 68 | # fi 69 | 70 | # Compilation flags 71 | # export ARCHFLAGS="-arch x86_64" 72 | 73 | # ssh 74 | # export SSH_KEY_PATH="~/.ssh/dsa_id" 75 | 76 | PS1='`echo "\e[0;33m┌─\e[0;36m[DOCKER MAGENTO]\e[0;35m[%*]\e[0;37m[%?]\e[0;37m[%~]\e[0;33m 77 | └─>docker:~$ ";`' 78 | 79 | alias ll='ls -alF' 80 | alias la='ls -A' 81 | alias l='ls -CF' 82 | alias wp='wp --allow-root' -------------------------------------------------------------------------------- /dev/bin/config.inc.php: -------------------------------------------------------------------------------- 1 | loadLocalPackage('algoliasearch'); 17 | $data['version'] = $config->getExtensionVersion(); 18 | 19 | $model->setData($data); 20 | 21 | if ($model->createPackage()) { 22 | echo 'Release package was successfully created.'; 23 | exit(0); 24 | } 25 | 26 | echo 'Release package could not be created.'; 27 | exit(1); 28 | -------------------------------------------------------------------------------- /dev/bin/start.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # start services 4 | find /var/lib/mysql -type f -exec touch {} \; && service mysql start 5 | service apache2 start 6 | 7 | # GET / to initialize the algolia_search_indexer (Open to another cleaner way to do it :) ) 8 | if [ $EXPOSED_PORT == 80 ]; then 9 | wget --max-redirect 0 $BASE_URL 10 | else 11 | wget --max-redirect 0 0.0.0.0 12 | fi 13 | 14 | # set configuration variables & volumes 15 | cd /var/www/htdocs 16 | 17 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set algoliasearch/credentials/application_id $APPLICATION_ID 18 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set algoliasearch/credentials/search_only_api_key $SEARCH_ONLY_API_KEY 19 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set --encrypt algoliasearch/credentials/api_key $API_KEY 20 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set algoliasearch/credentials/index_prefix $INDEX_PREFIX 21 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set algoliasearch/credentials/is_instant_enabled "1" 22 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set web/unsecure/base_url $BASE_URL 23 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set web/secure/base_url $BASE_URL 24 | 25 | if [ $INSTALL_ALGOLIA == Yes ]; then 26 | /root/bin/modman deploy-all 27 | 28 | # reindex whole index 29 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs index:reindex algolia_search_indexer 30 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs index:reindex algolia_search_indexer_cat 31 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs index:reindex algolia_search_indexer_pages 32 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs index:reindex search_indexer_suggest 33 | else 34 | /root/bin/modman undeploy algoliasearch-magento 35 | /root/bin/modman undeploy algoliasearch-magento-extend-module-skeleton 36 | fi 37 | 38 | chmod -R 777 /var/www/htdocs/media 39 | chown -R www-data:www-data /var/www/htdocs/media 40 | 41 | # do it after indexing so that var/log doesn't get created as root 42 | n98-magerun --skip-root-check --root-dir=/var/www/htdocs config:set dev/log/active 1 43 | 44 | if [ $MAKE_RELEASE == Yes ]; then 45 | php makeRelease.php 46 | fi 47 | 48 | service apache2 stop 49 | exec /usr/sbin/apache2ctl -D FOREGROUND -------------------------------------------------------------------------------- /dev/bin/test.sh: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env bash 2 | 3 | # Start services 4 | echo -e "\e[93m-- Starting Apache and MySQL services --\e[0m" 5 | find /var/lib/mysql -type f -exec touch {} \; && service mysql start 6 | service apache2 start 7 | 8 | if [ "$TRAVIS" == true ]; then 9 | echo -e "\n\e[93m-- Setting the correct rights to Magento files --\e[0m" 10 | chmod -R 777 /var/www/htdocs 11 | chown -R www-data:www-data /var/www/htdocs 12 | fi 13 | 14 | # GET / to initialize Magento - required before test runs 15 | echo -e "\n\e[93m-- Fetching the Magento homepage to initialize Magento --\e[0m" 16 | wget --max-redirect 0 0.0.0.0 17 | 18 | # Apache is not needed for tests 19 | echo -e "\e[93m-- Stopping the Apache server (not needed for the tests) --\e[0m" 20 | service apache2 stop 21 | 22 | chmod -R 777 /var/www/htdocs/media 23 | chown -R www-data:www-data /var/www/htdocs/media 24 | 25 | # Repair Modman simlinks 26 | # echo -e "\n\e[93m-- Force repairing the Modman symlinks --\e[0m" 27 | # cd /var/www/htdocs 28 | # /root/bin/modman repair --force algoliasearch-magento 29 | 30 | # Again in case root created some folder with root:root 31 | chmod -R 777 /var/www/htdocs/media 32 | chown -R www-data:www-data /var/www/htdocs/media 33 | 34 | # Run tests 35 | echo -e "\n\e[93m-- Running the tests --\e[0m" 36 | cd /var/www/htdocs/.modman/algoliasearch-magento 37 | 38 | if [ $FILTER ]; then 39 | vendor/bin/phpunit tests --filter "$FILTER" 40 | else 41 | vendor/bin/phpunit tests 42 | fi -------------------------------------------------------------------------------- /doc/auto-complete.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algoliasearch-magento/b4781de31b5e41bc574b59d1b161fd2a067660a6/doc/auto-complete.gif -------------------------------------------------------------------------------- /doc/instant-search.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/algoliasearch-magento/b4781de31b5e41bc574b59d1b161fd2a067660a6/doc/instant-search.gif -------------------------------------------------------------------------------- /js/algoliasearch/click_conversion_analytics.js: -------------------------------------------------------------------------------- 1 | algoliaBundle.$(function ($) { 2 | AlgoliaAnalytics.init({ 3 | appId: algoliaConfig.applicationId, 4 | apiKey: algoliaConfig.instant.apiKey 5 | }); 6 | 7 | // "Click" in autocomplete 8 | $(algoliaConfig.autocomplete.selector).each(function () { 9 | $(this).on('autocomplete:selected', function (e, suggestion, dataset) { 10 | 11 | var sources = analyticsHelper.sources; 12 | var source = sources.filter(function(src) { 13 | return src.name == dataset; 14 | }); 15 | 16 | if (source.length > 0) { 17 | var source = source[0]; 18 | trackClick(source.indexName, suggestion.objectID, suggestion.__position, suggestion.__queryID); 19 | } 20 | }); 21 | }); 22 | 23 | // "Click" on instant search page 24 | $(document).on('click', algoliaConfig.ccAnalytics.ISSelector, function() { 25 | var $this = $(this); 26 | var lastResults = analyticsHelper.getLastResults(); 27 | 28 | // want to track results returned 29 | if (lastResults) { 30 | trackClick(lastResults.index, $this.data('objectid'), $this.data('position'), $this.data('queryid')); 31 | } 32 | }); 33 | 34 | // "Add to cart" conversion 35 | if (algoliaConfig.ccAnalytics.conversionAnalyticsMode === 'add_to_cart') { 36 | function getQueryParamFromCurrentUrl(queryParamName) { 37 | var url = window.location.href; 38 | var regex = new RegExp('[?&]' + queryParamName + '(=([^&#]*)|&|#|$)'); 39 | var results = regex.exec(url); 40 | if (!results || !results[2]) return ''; 41 | return results[2]; 42 | } 43 | 44 | $(document).on('click', algoliaConfig.ccAnalytics.addToCartSelector, function () { 45 | var objectId = $(this).data('objectid') || getQueryParamFromCurrentUrl('objectID'); 46 | var queryId = $(this).data('queryid') || getQueryParamFromCurrentUrl('queryID'); 47 | var index = algoliaConfig.indexName + "_products" || getQueryParamFromCurrentUrl('index'); 48 | 49 | trackConversion(index, objectId, queryId); 50 | }); 51 | } 52 | 53 | if (algoliaConfig.ccAnalytics.conversionAnalyticsMode === 'place_order') { 54 | 55 | if (typeof algoliaOrderConversionJson !== 'undefined') { 56 | $.each(algoliaOrderConversionJson, function(idx, itemData) { 57 | if (itemData && itemData.objectID) { 58 | trackConversion(itemData.indexName, itemData.objectID, itemData.queryID); 59 | } 60 | }); 61 | } 62 | } 63 | 64 | }); 65 | 66 | var analyticsHelper = {}; 67 | 68 | algolia.registerHook('beforeAutocompleteSources', function(sources) { 69 | analyticsHelper.sources = sources; 70 | return sources; 71 | }); 72 | 73 | algolia.registerHook('beforeInstantsearchStart', function (search) { 74 | search.once('render', function() { 75 | analyticsHelper.getLastResults = function () { 76 | return search.helper.lastResults; 77 | } 78 | }); 79 | return search; 80 | }); 81 | 82 | algolia.registerHook('beforeInstantsearchInit', function (instantsearchOptions) { 83 | instantsearchOptions.searchParameters['clickAnalytics'] = true; 84 | return instantsearchOptions; 85 | }); 86 | 87 | function trackClick(index, objectID, position, queryId) { 88 | var clickData = { 89 | index: index, 90 | eventName: "Clicked item", 91 | objectIDs: [objectID.toString()], 92 | positions: [parseInt(position)], 93 | queryID: queryId 94 | }; 95 | 96 | AlgoliaAnalytics.clickedObjectIDsAfterSearch(clickData); 97 | } 98 | 99 | function trackConversion(index, objectID, queryId) { 100 | AlgoliaAnalytics.convertedObjectIDsAfterSearch({ 101 | index: index, 102 | eventName: "Conversion", 103 | objectIDs: [objectID.toString()], 104 | queryID: queryId, 105 | }); 106 | } 107 | -------------------------------------------------------------------------------- /js/algoliasearch/internals/frontend/Function.prototype.bind.js: -------------------------------------------------------------------------------- 1 | // Magento is using a very old prototype.js version with a poor Function.prototype.bind 2 | // forced overloading, we redefine it here so that our code works 3 | // ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind 4 | Function.prototype.bind = function(oThis) { 5 | if (typeof this !== 'function') { 6 | // closest thing possible to the ECMAScript 5 7 | // internal IsCallable function 8 | throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); 9 | } 10 | 11 | var aArgs = Array.prototype.slice.call(arguments, 1), 12 | fToBind = this, 13 | fNOP = function() {}, 14 | fBound = function() { 15 | return fToBind.apply(this instanceof fNOP 16 | ? this 17 | : oThis, 18 | aArgs.concat(Array.prototype.slice.call(arguments))); 19 | }; 20 | 21 | if (this.prototype) { 22 | // native functions don't have a prototype 23 | fNOP.prototype = this.prototype; 24 | } 25 | fBound.prototype = new fNOP(); 26 | 27 | return fBound; 28 | }; 29 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/AlgoliaConnectionException.php: -------------------------------------------------------------------------------- 1 | client = $client; 15 | } 16 | 17 | public function getABTests($params = array()) 18 | { 19 | $params += array('offset' => 0, 'limit' => 10); 20 | 21 | return $this->request('GET', '/2/abtests', $params); 22 | } 23 | 24 | public function getABTest($abTestID) 25 | { 26 | if (!$abTestID) { 27 | throw new AlgoliaException('Cannot retrieve ABTest because the abtestID is invalid.'); 28 | } 29 | 30 | return $this->request('GET', sprintf('/2/abtests/%s', urlencode($abTestID))); 31 | } 32 | 33 | public function addABTest($abTest) 34 | { 35 | return $this->request( 36 | 'POST', 37 | '/2/abtests', 38 | array(), 39 | $abTest 40 | ); 41 | } 42 | 43 | public function stopABTest($abTestID) 44 | { 45 | if (!$abTestID) { 46 | throw new AlgoliaException('Cannot retrieve ABTest because the abtestID is invalid.'); 47 | } 48 | 49 | return $this->request('POST', sprintf('/2/abtests/%s/stop', urlencode($abTestID))); 50 | } 51 | 52 | public function deleteABTest($abTestID) 53 | { 54 | if (!$abTestID) { 55 | throw new AlgoliaException('Cannot retrieve ABTest because the abtestID is invalid.'); 56 | } 57 | 58 | return $this->request('DELETE', sprintf('/2/abtests/%s', urlencode($abTestID))); 59 | } 60 | 61 | public function waitTask($indexName, $taskID, $timeBeforeRetry = 100, $requestHeaders = array()) 62 | { 63 | $this->client->waitTask($indexName, $taskID, $timeBeforeRetry, $requestHeaders); 64 | } 65 | 66 | protected function request( 67 | $method, 68 | $path, 69 | $params = array(), 70 | $data = array() 71 | ) { 72 | return $this->client->request( 73 | $this->client->getContext(), 74 | $method, 75 | $path, 76 | $params, 77 | $data, 78 | array('analytics.algolia.com'), 79 | $this->client->getContext()->connectTimeout, 80 | $this->client->getContext()->readTimeout 81 | ); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/FailingHostsCache.php: -------------------------------------------------------------------------------- 1 | ttl = (int) $ttl; 33 | } 34 | 35 | 36 | /** 37 | * @param string $host 38 | */ 39 | public function addFailingHost($host) 40 | { 41 | if (! in_array($host, self::$failingHosts)) { 42 | // Keep a local cache of failed hosts in case the file based strategy doesn't work out. 43 | self::$failingHosts[] = $host; 44 | 45 | if (self::$timestamp === null) { 46 | self::$timestamp = time(); 47 | } 48 | } 49 | } 50 | 51 | /** 52 | * Get failing hosts from cache. This method should also handle cache invalidation if required. 53 | * The TTL of the failed hosts cache should be 5mins. 54 | * 55 | * @return array 56 | */ 57 | public function getFailingHosts() 58 | { 59 | if (self::$timestamp === null) { 60 | return self::$failingHosts; 61 | } 62 | 63 | $elapsed = time() - self::$timestamp; 64 | if ($elapsed > $this->ttl) { 65 | $this->flushFailingHostsCache(); 66 | } 67 | 68 | return self::$failingHosts; 69 | } 70 | 71 | public function flushFailingHostsCache() 72 | { 73 | self::$failingHosts = array(); 74 | self::$timestamp = null; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/Iterators/RuleIterator.php: -------------------------------------------------------------------------------- 1 | response = $this->index->searchRules(array( 35 | 'hitsPerPage' => $this->hitsPerPage, 36 | 'page' => $this->getCurrentPage(), 37 | )); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/Iterators/SynonymIterator.php: -------------------------------------------------------------------------------- 1 | response = $this->index->searchSynonyms('', array(), $this->getCurrentPage(), $this->hitsPerPage); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/Json.php: -------------------------------------------------------------------------------- 1 | context = $context; 49 | $this->client = $client; 50 | } 51 | 52 | /** 53 | * @param string $query 54 | * @param array|null $args 55 | * 56 | * @return mixed 57 | * 58 | * @throws AlgoliaException 59 | */ 60 | public function search($query, $args = null) 61 | { 62 | if ($args === null) { 63 | $args = array(); 64 | } 65 | $args['query'] = $query; 66 | 67 | return $this->client->request( 68 | $this->context, 69 | 'POST', 70 | '/1/places/query', 71 | array(), 72 | array('params' => $this->client->buildQuery($args)), 73 | $this->context->readHostsArray, 74 | $this->context->connectTimeout, 75 | $this->context->searchTimeout 76 | ); 77 | } 78 | 79 | /** 80 | * @param mixed $objectID 81 | * 82 | * @return mixed 83 | * 84 | * @throws AlgoliaException 85 | */ 86 | public function getObject($objectID) 87 | { 88 | return $this->client->request( 89 | $this->context, 90 | 'GET', 91 | '/1/places/' . urlencode($objectID), 92 | null, 93 | null, 94 | $this->context->readHostsArray, 95 | $this->context->connectTimeout, 96 | $this->context->searchTimeout 97 | ); 98 | } 99 | 100 | /** 101 | * @param string $key 102 | * @param string $value 103 | */ 104 | public function setExtraHeader($key, $value) 105 | { 106 | $this->context->setExtraHeader($key, $value); 107 | } 108 | 109 | /** 110 | * @return ClientContext 111 | */ 112 | public function getContext() 113 | { 114 | return $this->context; 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /lib/AlgoliaSearch/SynonymType.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tests/ 6 | 7 | 8 | 9 | 10 | app/ 11 | 12 | app/code/community/Algolia/Algoliasearch/Block/ 13 | app/code/community/Algolia/Algoliasearch/Model/System/ 14 | app/code/community/Algolia/Algoliasearch/sql/ 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /skin/adminhtml/base/default/algoliasearch/algoliasearch.css: -------------------------------------------------------------------------------- 1 | .algoliasearch-queue-notification { 2 | background: #e9f3ff url(/skin/frontend/base/default/algoliasearch/algolia-admin-menu.svg) no-repeat 27px 5px; 3 | background-size: 16px 16px; 4 | border-color: #bee1ee; 5 | } 6 | 7 | .algoliasearch-head-icon { 8 | background: url(/skin/frontend/base/default/algoliasearch/algolia-admin-menu.svg) no-repeat; 9 | background-size: 16px 16px; 10 | } 11 | 12 | .algolia-notice { 13 | border: 1px solid #dfdfdf; 14 | background-position: 10px 10px; 15 | padding-left: 35px; 16 | padding-top: 10px; 17 | margin-bottom: 1rem; 18 | color: #333; 19 | font-size: 13px; 20 | } 21 | 22 | .algoliasearch-config-info { 23 | border: 1px solid #D6D6D6; 24 | padding: 16px 20px 15px 56px; 25 | margin: 7px 0; 26 | } 27 | 28 | 29 | .algoliasearch-config-info.icon-stars { 30 | background: 19px 13px url(/skin/frontend/base/default/algoliasearch/stars-icon.svg) no-repeat; 31 | } -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/algolia-admin-menu.svg: -------------------------------------------------------------------------------- 1 | algolia-mark-squareCreated with Sketch. -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/clear-cross.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/cross-circle.svg: -------------------------------------------------------------------------------- 1 | testvg -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/is-icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/magnifying-glass.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /skin/frontend/base/default/algoliasearch/stars-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/AbstractIndexingTestCase.php: -------------------------------------------------------------------------------- 1 | algoliaHelper = Mage::helper('algoliasearch/algoliahelper'); 18 | } 19 | 20 | protected function processTest(Algolia_Algoliasearch_Model_Indexer_Abstract $indexer, $indexSuffix, $expectedNbHits, $expectedNbHitsFrench = null, $expectedNbHitsGerman = null) 21 | { 22 | $this->algoliaHelper->clearIndex($this->indexPrefix.'default_'.$indexSuffix); 23 | $this->algoliaHelper->clearIndex($this->indexPrefix.'french_'.$indexSuffix); 24 | $this->algoliaHelper->clearIndex($this->indexPrefix.'german_'.$indexSuffix); 25 | 26 | $indexer->reindexAll(); 27 | 28 | $this->algoliaHelper->waitLastTask(); 29 | 30 | $resultsDefault = $this->algoliaHelper->query($this->indexPrefix.'default_'.$indexSuffix, '', array()); 31 | $resultsFrench = $this->algoliaHelper->query($this->indexPrefix.'french_'.$indexSuffix, '', array()); 32 | $resultsGerman = $this->algoliaHelper->query($this->indexPrefix.'german_'.$indexSuffix, '', array()); 33 | 34 | $expectedNbHitsFrench = $expectedNbHitsFrench ?: $expectedNbHits; 35 | $expectedNbHitsGerman = $expectedNbHitsGerman ?: $expectedNbHits; 36 | 37 | $this->assertEquals($expectedNbHits, $resultsDefault['nbHits']); 38 | $this->assertEquals($expectedNbHitsFrench, $resultsFrench['nbHits']); 39 | $this->assertEquals($expectedNbHitsGerman, $resultsGerman['nbHits']); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /tests/AbstractTestCase.php: -------------------------------------------------------------------------------- 1 | '0', 14 | ); 15 | 16 | public function setUp() 17 | { 18 | /** @var Algolia_Algoliasearch_Helper_Config $config */ 19 | $config = Mage::helper('algoliasearch/config'); 20 | $this->indexPrefix = $config->getIndexPrefix(); 21 | 22 | foreach ($this->defaultConfig as $name => $value) { 23 | setConfig($name, $value); 24 | } 25 | 26 | resetConfigs(); 27 | } 28 | } -------------------------------------------------------------------------------- /tests/CategoriesIndexingTest.php: -------------------------------------------------------------------------------- 1 | processTest($categoriesIndexer, 'categories', 25); 9 | } 10 | 11 | public function testDefaultIndexableAttributes() 12 | { 13 | setConfig('algoliasearch/categories/category_additional_attributes2', serialize(array())); 14 | 15 | $indexer = new Algolia_Algoliasearch_Model_Indexer_Algoliacategories(); 16 | $indexer->reindexSpecificCategories(24); 17 | 18 | $this->algoliaHelper->waitLastTask(); 19 | 20 | $results = $this->algoliaHelper->getObjects($this->indexPrefix.'default_categories', array('24')); 21 | $hit = reset($results['results']); 22 | 23 | $defaultAttributes = array( 24 | 'objectID', 25 | 'name', 26 | 'url', 27 | 'path', 28 | 'level', 29 | 'include_in_menu', 30 | '_tags', 31 | 'popularity', 32 | 'product_count', 33 | 'algoliaLastUpdateAtCET', 34 | ); 35 | 36 | foreach ($defaultAttributes as $key => $attribute) { 37 | $this->assertTrue(isset($hit[$attribute]), 'Category attribute "'.$attribute.'" should be indexed but it is not"'); 38 | unset($hit[$attribute]); 39 | } 40 | 41 | $extraAttributes = implode(', ', array_keys($hit)); 42 | $this->assertTrue(empty($hit), 'Extra category attributes ('.$extraAttributes.') are indexed and should not be.'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/ProductsIndexingTest.php: -------------------------------------------------------------------------------- 1 | processTest($productIndexer, 'products', self::DEFAULT_PRODUCT_COUNT); 11 | } 12 | 13 | public function testProductsOnlySearchVisible() 14 | { 15 | setConfig('algoliasearch/products/index_visibility', 'only_search'); 16 | 17 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 18 | $this->processTest($productIndexer, 'products', 85); 19 | } 20 | 21 | public function testProductsOnlyCatalogVisible() 22 | { 23 | setConfig('algoliasearch/products/index_visibility', 'only_catalog'); 24 | 25 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 26 | $this->processTest($productIndexer, 'products', self::DEFAULT_PRODUCT_COUNT); 27 | } 28 | 29 | public function testProductsOnInStock() 30 | { 31 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 32 | $this->processTest($productIndexer, 'products', self::DEFAULT_PRODUCT_COUNT); 33 | } 34 | 35 | public function testProductsIncludingOutOfStock() 36 | { 37 | setConfig('cataloginventory/options/show_out_of_stock', '1'); 38 | 39 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 40 | $this->processTest($productIndexer, 'products', 93); 41 | } 42 | 43 | public function testDefaultIndexableAttributes() 44 | { 45 | setConfig('algoliasearch/products/product_additional_attributes', serialize(array())); 46 | setConfig('algoliasearch/instant/facets', serialize(array())); 47 | setConfig('algoliasearch/instant/sorts', serialize(array())); 48 | setConfig('algoliasearch/products/custom_ranking_product_attributes', serialize(array())); 49 | 50 | $indexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 51 | $indexer->reindexSpecificProducts(405); 52 | 53 | $this->algoliaHelper->waitLastTask(); 54 | 55 | $results = $this->algoliaHelper->getObjects($this->indexPrefix.'default_products', array('405')); 56 | $hit = reset($results['results']); 57 | 58 | $defaultAttributes = array( 59 | 'objectID', 60 | 'name', 61 | 'url', 62 | 'visibility_search', 63 | 'visibility_catalog', 64 | 'categories', 65 | 'categories_without_path', 66 | 'thumbnail_url', 67 | 'image_url', 68 | 'in_stock', 69 | 'price', 70 | 'type_id', 71 | 'algoliaLastUpdateAtCET', 72 | ); 73 | 74 | foreach ($defaultAttributes as $key => $attribute) { 75 | $this->assertTrue(isset($hit[$attribute]), 'Products attribute "'.$attribute.'" should be indexed but it is not"'); 76 | unset($hit[$attribute]); 77 | } 78 | 79 | $extraAttributes = implode(', ', array_keys($hit)); 80 | $this->assertTrue(empty($hit), 'Extra products attributes ('.$extraAttributes.') are indexed and should not be.'); 81 | } 82 | 83 | public function testIfIndexingCanBeEnabledAndDisabled() 84 | { 85 | setConfig('algoliasearch/credentials/enable_backend', '0'); 86 | 87 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 88 | $this->processTest($productIndexer, 'products', 0); 89 | 90 | setConfig('algoliasearch/credentials/enable_backend', '1'); 91 | 92 | $productIndexer = new Algolia_Algoliasearch_Model_Indexer_Algolia(); 93 | $this->processTest($productIndexer, 'products', self::DEFAULT_PRODUCT_COUNT); 94 | } 95 | 96 | public function testProductAreSearchableIfIndexingIsDisabled() 97 | { 98 | setConfig('algoliasearch/credentials/enable_backend', '0'); 99 | 100 | $resultsDefault = $this->algoliaHelper->query($this->indexPrefix.'default_products', 'lemon flower', array()); 101 | 102 | $this->assertEquals(1, $resultsDefault['nbHits']); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID); 9 | 10 | // Set Magento's base URLs 11 | setConfig('web/secure/base_url', getenv('BASE_URL')); 12 | setConfig('web/unsecure/base_url', getenv('BASE_URL')); 13 | 14 | // Set Algolia API credentials 15 | setConfig('algoliasearch/credentials/application_id', getenv('APPLICATION_ID')); 16 | setConfig('algoliasearch/credentials/search_only_api_key', getenv('SEARCH_ONLY_API_KEY')); 17 | setConfig('algoliasearch/credentials/api_key', Mage::helper('core')->encrypt(getenv('API_KEY'))); 18 | 19 | setConfig('algoliasearch/credentials/index_prefix', getenv('INDEX_PREFIX')); 20 | 21 | /** 22 | * @param array $configs 23 | */ 24 | function resetConfigs($configs = array()) 25 | { 26 | $configXmlFile = __DIR__.'/../app/code/community/Algolia/Algoliasearch/etc/config.xml'; 27 | 28 | $xml = simplexml_load_file($configXmlFile); 29 | 30 | $credentialsShortcuts = array( 31 | 'credentials/application_id', 'credentials/api_key', 'credentials/search_only_api_key', 'credentials/index_prefix' 32 | ); 33 | 34 | foreach ($xml->default->algoliasearch->children() as $section => $subsections) { 35 | foreach ($subsections as $subsectionName => $subsection) { 36 | $shortcut = $section.'/'.$subsectionName; 37 | 38 | if (in_array($shortcut, $credentialsShortcuts)) { 39 | continue; 40 | } 41 | 42 | if (!empty($configs) && !in_array($shortcut, $configs, true)) { 43 | continue; 44 | } 45 | 46 | $sectionName = 'algoliasearch/'.$shortcut; 47 | $sectionValue = (string) $subsection; 48 | 49 | setConfig($sectionName, $sectionValue); 50 | } 51 | } 52 | } 53 | 54 | function setConfig($path, $value, $storeId = null) 55 | { 56 | if ($storeId === null) { 57 | Mage::app()->getStore()->setConfig($path, $value); 58 | } 59 | 60 | for ($i = 1; $i <= 3; $i++) { 61 | if ($storeId !== null && $i !== $storeId) { 62 | continue; 63 | } 64 | 65 | Mage::app()->getStore($i)->setConfig($path, $value); 66 | } 67 | } 68 | 69 | /** 70 | * Call protected/private method of a class. 71 | * 72 | * @param object &$object Instantiated object that we will run method on. 73 | * @param string $methodName Method name to call 74 | * @param array $parameters Array of parameters to pass into method. 75 | * 76 | * @return mixed Method return. 77 | */ 78 | function invokeMethod(&$object, $methodName, array $parameters = array()) 79 | { 80 | $reflection = new \ReflectionClass(get_class($object)); 81 | $method = $reflection->getMethod($methodName); 82 | $method->setAccessible(true); 83 | 84 | return $method->invokeArgs($object, $parameters); 85 | } 86 | --------------------------------------------------------------------------------