├── README.md ├── app ├── code │ └── community │ │ └── SomethingDigital │ │ └── RecentlyViewed │ │ ├── Block │ │ └── Viewed.php │ │ ├── Model │ │ └── Adminhtml │ │ │ └── System │ │ │ └── Config │ │ │ └── SdRecentlyViewedPosition.php │ │ └── etc │ │ ├── config.xml │ │ └── system.xml ├── design │ └── frontend │ │ └── base │ │ └── default │ │ ├── layout │ │ └── sd_recentlyviewed │ │ │ └── recent.xml │ │ └── template │ │ └── sd_recentlyviewed │ │ ├── items.phtml │ │ ├── product.phtml │ │ └── productid.phtml └── etc │ └── modules │ └── SomethingDigital_RecentlyViewed.xml ├── composer.json ├── modman └── skin └── frontend └── base └── default └── js └── sd_recentlyviewed └── recent.js /README.md: -------------------------------------------------------------------------------- 1 | # SomethingDigital_RecentlyViewed 2 | 3 | Localstorage-based recently viewed products 4 | 5 | Overview 6 | -- 7 | 8 | Inspired by Ivan Chepurnyi's [talk about improving Magento write performance](de.slideshare.net/ivanchepurnyi/making-magento-flying-like-a-rocket-a-set-of-valuable-tips-for-developers?related=1). This replaces the in-built Recently Viewed product block with a localstorage implementation. 9 | 10 | Features 11 | -- 12 | 13 | - Target the location of the block in admin via CSS selector 14 | - Control the number of items displayed (uses default Magento value) 15 | - Disable writes to report tables (recommended to use in conjunction with [Quafzi_PerformanceTweaks](https://github.com/quafzi/magento-performance-tweaks) 16 | 17 | 18 | Screenshots 19 | -- 20 | 21 | 22 | 23 | 24 | License 25 | -- 26 | 27 | The MIT License 28 | 29 | Copyright (c) 2015 Something Digital http://www.somethingdigital.com 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy 32 | of this software and associated documentation files (the "Software"), to deal 33 | in the Software without restriction, including without limitation the rights 34 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 35 | copies of the Software, and to permit persons to whom the Software is 36 | furnished to do so, subject to the following conditions: 37 | 38 | The above copyright notice and this permission notice shall be included in 39 | all copies or substantial portions of the Software. 40 | 41 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 42 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 43 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 44 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 45 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 46 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 47 | THE SOFTWARE. 48 | -------------------------------------------------------------------------------- /app/code/community/SomethingDigital/RecentlyViewed/Block/Viewed.php: -------------------------------------------------------------------------------- 1 | 'top', 'label' => 'Top' ), 8 | array( 'value' => 'bottom', 'label' => 'Bottom' ), 9 | array( 'value' => 'above', 'label' => 'Above' ), 10 | array( 'value' => 'below', 'label' => 'Below' ), 11 | ); 12 | 13 | return $position; 14 | } 15 | } -------------------------------------------------------------------------------- /app/code/community/SomethingDigital/RecentlyViewed/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 0.1.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | SomethingDigital_RecentlyViewed_Block 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | sd_recentlyviewed/recent.xml 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | .col-right.sidebar 36 | top 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /app/code/community/SomethingDigital/RecentlyViewed/etc/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | text 11 | 100 12 | 1 13 | 1 14 | 1 15 | 16 | 17 | 18 | 19 | select 20 | SomethingDigital_RecentlyViewed_Model_Adminhtml_System_Config_sdRecentlyViewedPosition 21 | 200 22 | 1 23 | 1 24 | 1 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/layout/sd_recentlyviewed/recent.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | skin_js 17 | js/sd_recentlyviewed/recent.js 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 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/sd_recentlyviewed/items.phtml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/sd_recentlyviewed/product.phtml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/design/frontend/base/default/template/sd_recentlyviewed/productid.phtml: -------------------------------------------------------------------------------- 1 | getId() : null; 5 | $categoryId = $category ? $category->getId() : null; 6 | // The view count includes the current product being viewed on the PDP. 7 | // Since the current product being viewed is not rendered in this list, the 8 | // number of displayed recent products on the PDP is actually one less than 9 | // the value for viewed_count of recent products. By adding one to max display 10 | // count for the current product being viewed, the default Magento 11 | // config values intuitively reflects the number of recent products visible on PDP. 12 | $maxDisplay = Mage::getStoreConfig('catalog/recently_products/viewed_count') + 1; 13 | ?> 14 | -------------------------------------------------------------------------------- /app/etc/modules/SomethingDigital_RecentlyViewed.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | community 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sdinteractive/somethingdigital_recentlyviewed", 3 | "license": "MIT", 4 | "description": "Add LocalStorage-based recently viewed products", 5 | "homepage": "https://github.com/sdinteractive/SomethingDigital_RecentlyViewed", 6 | "type": "magento-module", 7 | "require": { 8 | "php": ">=5.3" 9 | }, 10 | "authors": [ 11 | { 12 | "name": "Something Digital", 13 | "email": "info@somethingdigital.com", 14 | "homepage": "http://www.somethingdigital.com/", 15 | "role": "Author/Maintainer" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /modman: -------------------------------------------------------------------------------- 1 | #SomethingDigital_RecentlyViewed 2 | app/code/community/SomethingDigital/RecentlyViewed app/code/community/SomethingDigital/RecentlyViewed 3 | app/design/frontend/base/default/layout/sd_recentlyviewed app/design/frontend/base/default/layout/sd_recentlyviewed 4 | app/design/frontend/base/default/template/sd_recentlyviewed app/design/frontend/base/default/template/sd_recentlyviewed 5 | skin/frontend/base/default/js/sd_recentlyviewed skin/frontend/base/default/js/sd_recentlyviewed 6 | app/etc/modules/*.xml app/etc/modules/ -------------------------------------------------------------------------------- /skin/frontend/base/default/js/sd_recentlyviewed/recent.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var SomethingDigitalRecentlyViewed = Class.create(); 4 | 5 | SomethingDigitalRecentlyViewed.prototype = { 6 | items: null, 7 | initialize: function(){ 8 | this.initStorage(); 9 | this.render(); 10 | }, 11 | 12 | initStorage: function(){ 13 | var recentlyViewed = this.getRecentlyViewed(this.getLoadedStorage()); 14 | this.reloadStorage(recentlyViewed); 15 | }, 16 | 17 | getLoadedStorage: function(){ 18 | if(!this.items){ 19 | this.items = JSON.parse(localStorage.getItem('recently-viewed')) || []; 20 | } 21 | return this.items; 22 | }, 23 | 24 | reloadStorage: function(recentlyViewed){ 25 | localStorage.setItem('recently-viewed',JSON.stringify(recentlyViewed)); 26 | }, 27 | 28 | reduceRecent: function(memo,a){ 29 | if (a && a.id){ 30 | if(memo.indexOf(a.id) === -1){ 31 | memo.push(a.id); 32 | } 33 | } 34 | return memo; 35 | }, 36 | 37 | getRecentlyViewed: function(recentlyViewed){ 38 | 39 | if(typeof sdRecentlyViewed == 'undefined'){ 40 | return recentlyViewed; 41 | } 42 | 43 | //get unique keys 44 | var uniqueKeys = recentlyViewed.reduce(this.reduceRecent, []), 45 | index = uniqueKeys.indexOf(sdRecentlyViewed.productId); 46 | 47 | //add if current product is not in the unique keys 48 | if(index === -1 && $('recently-viewed')){ 49 | 50 | recentlyViewed.push({ 51 | id: sdRecentlyViewed.productId, 52 | html: $('recently-viewed').innerHTML 53 | }); 54 | 55 | if(recentlyViewed.length > sdRecentlyViewed.maxDisplay){ 56 | recentlyViewed.shift(); 57 | } 58 | 59 | //move to end if current product *is* in unique keys 60 | } else if (index != -1) { 61 | var obj = recentlyViewed.splice(index, 1)[0]; 62 | recentlyViewed.push(obj); 63 | } 64 | 65 | return recentlyViewed; 66 | }, 67 | 68 | getRenderedItems: function(){ 69 | var items = this.getLoadedStorage(); 70 | 71 | return items.map(function(a){ 72 | // Don't render the current product since it is already being viewed on PDP 73 | if (a){ 74 | if (a.id == sdRecentlyViewed.productId) { 75 | return ''; 76 | } 77 | return a.html; 78 | } 79 | }).join(''); 80 | }, 81 | 82 | render: function(){ 83 | 84 | if(!this.items || this.items.length <= 1){ 85 | return; 86 | } 87 | 88 | var rvTemplate = $('recently-viewed-product-list'), 89 | target = $$(sdRecentlyViewed.insertAt)[0]; 90 | 91 | if(!rvTemplate || !target){ 92 | return; 93 | } 94 | 95 | var html = rvTemplate.innerHTML.replace('{{items}}',this.getRenderedItems()); 96 | $(target).insert({top: html}); 97 | 98 | } 99 | } 100 | 101 | document.observe('dom:loaded',function(){ 102 | new SomethingDigitalRecentlyViewed(); 103 | }); 104 | --------------------------------------------------------------------------------