Using local storage for magento performance improvement

  • Sharebar

Using local Storage for magento performance improvement

So one of my biggest headaches with Magento is that it generates content over and over and over again.
Content that has been generated already. Even with Full Page Caching enabled we still need to hit the server to get some information like the recently viewed products…. Heck even with Varnish we still need to pull a rabbit out of the hat in order to maintain a sustainable and scalable infrastructure. Each store and client is different but that doesn’t mean performance needs to be different, right?

Why use local storage for magento performance improvement

For once cookies is a technology of the past and are very limited and size and quantity. 4KB of data is not enough for most applications and each browser sets a different number of cookies that it allows.

Also one of the things I love the most about Twitter and Facebook is that they don’t constraint themselves to an specific technology or programming language. Rather they explore all of the possibilities and create from there. In other words both Social Networks create frameworks or services that will help them scale based on the right tool required for the job. So, according to what I know in Facebook and Twitter is not about what is the best programming language but which one is best suited for the task? How is this related? Well if we are speeding up Magento we need to find the right tools or paradigm to do so even if it means getting outside of our comfortable zone.

By now we you should definitely be aware of what PHP Offloading means and why it is important, especially if you are using Nginx, which you are doing right? All of these “offloading” is to help define a concept that is very important to me: Optimized Driven Development (ODD), not sure that there is a definition for it but to me it means:

Use the right tool for the job

Why do we need to go through the trouble of doing this?

For the sake of doing things right… putting that aside for a moment, we are doing this to improve the customer experience and hence the client satisfaction. The best thing is that this could be pretty awesome.

Also because we are performance junkies who want to see better benchmark every time, right?

So, how do we do it

So let’s continue offloading php as much as we can by removing the need of hole punching the recently viewed products.
This is the default product_viewed.phtml template under app/design/frontend/base/default/template/reports:

if ($_products = $this->getRecentlyViewedProducts()):
<div class="block block-list block-viewed">
    <div class="block-title">
        <strong><span><?php echo $this->__('Recently Viewed Products') ?></span></strong>
    </div>
    <div class="block-content">
        <ol id="recently-viewed-items">
        <?php foreach ($_products as $_item): ?>
            <li class="item">
                <p class="product-name"><a href="<?php echo $this->getProductUrl($_item) ?>"><?php echo $this->helper('catalog/output')->productAttribute($_item, $_item->getName() , 'name') ?></a></p>
            </li>
        <?php endforeach; ?>
        </ol>
        <script type="text/javascript">decorateList('recently-viewed-items');</script>
    </div>
</div>
endif;

Now as you may see we are relying on PHP once more to tell us the products that a person previously seen. Obviously this is not good as we are just wasting resources.
You can also see that block being “holepunched” or include dynamically if you read the cache.xml under app/code/core/Enterprise/PageCache/etc.

To change this let’s approach it the same way we approached the header by relying on the client (read browser) to take care of it.

I’d add the following JavaScript to the category and product pages.

var storage = {
    storage: null,
    dummy: "dummy_data",
    local: "local"
    session: "session",
    isAvailable: true,
    verify: function (){
        this.setStorage();
        try{
            this.set(this.dummy,this.dummy)
            
            if (this.get(this.dummy) == this.dummy){
                this.isAvailable = true;
            }else{
                this.isAvailable = false;
            }
        }
        catch(e){
            this.isAvailable = false;
        }

       return  this.isAvailable
    },    
    set: function (key,value){
        this.getStorage().setItem(key,value)
    },    
    get: function (key){
        this.getStorage().getItem(key)
    },
    update: function(key,value){
        this.set(key,value)
    },
    remove: function(key){
        this.getStorage().removeItem(key)
    },
    getStorage: function(type){
        type = type || this.local
        
        if (type == this.local){
           this.setStorage(localStorage)
        }else{
            this.setStorage(sessionStorage)
        }
        
        return this.storage
    },
    
    setStorage: function(storage){
        this.storage  = storage
        
        return this
    },

}

Now in the product view template add the following snippet (homework see if you can add it without modifying the template file directly)

<script type="text/javascript">
    if (storage.verify()){
        var prodKey = "<?php md5('product_key_'.$_product->getId())?>"
        var recently-viewed = { prodKey: "<li class='item'>
        <p class='product-name'>
                <a href='<?php echo $_product->getProductUrl()'>
                        <?php echo $_helper->productAttribute($_product, $_product->getName(), 'name') ?>
                </a>
        </p>
        </li>"
        }
        
       var products = JSON.parse(storage.get(prodKey));
       if (!products){
          storage.set('recently.viewed', recently-viewed);
       }

    }
</script>

As you can see now is very trivial to get the recently viewed products from local storage, which greatly improves your magento store performance just as much as that little cookie did before.

Words of warning

If you are still supporting IE version < 9, then this won't work. As you may know IE is the incarnation of the ..... and the source of many gray hairs for all of the developers I know.

You must implement the storage.get functionality and change the template to now use local storage instead of the php code presented above. If possible it will be cool if you can share the code you come with.

If you would like the storage to be session based instead, who wants to keep 40 recently viewed products? Then used session storage instead, so once the browser is closed the storage is cleared automatically for you.

To me the most awesome thing about this:

var prodKey = "<?php md5('product_key_'.$_product->getId())?>" + Mage.Cookies.get('frontend')

Becomes really redundant and unnecessary because the local storage lives in the client the same way the cookie is so essentially it is customer based...

VN:F [1.9.22_1171]
Rating: 7.5/10 (4 votes cast)
VN:F [1.9.22_1171]
Rating: +3 (from 3 votes)
Using local storage for magento performance improvement, 7.5 out of 10 based on 4 ratings
 Using local storage for magento performance improvement

About Luis Tineo

Husband, Father, performance improvement junkie, biker and video gamer, Linux user and in my day job I'm a Systems Architect at Blue Acorn.

Tags: , ,

  • fbrnc

    Great! Thanks for sharing! :)

    VA:F [1.9.22_1171]
    Rating: 0.0/5 (0 votes cast)
    VA:F [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • http://www.kingletas.com letas

      You are very welcome… any thoughts on how to deal with IE? Maybe using SQLite databases?

      VN:F [1.9.22_1171]
      Rating: 0.0/5 (0 votes cast)
      VN:F [1.9.22_1171]
      Rating: 0 (from 0 votes)
  • Pingback: PHP offloading for better performance