Showing posts with label layouts. Show all posts
Showing posts with label layouts. Show all posts

Thursday, 4 September 2014

By default every Magento product list page has to modes of view. They are List and Grid. We can set default mode through admin. For this , we need to go to

System  >  Configuration  >  Catalog  >  Frontend  >  List mode
and set default option there. However what about if we need to show different categories in different modes ? Obviously every one think to do this programmatically. But it's somewhat handy. So I decided to drop out programmatic option. So the last option remains there is layout updation. It looks indeed awesome. It will work like a charm.

In Detail

Let us take an example. Suppose we have three categories. They are category 1, category 2 and category 3. We need to show category 2 in grid mode and rest of the categories in list mode.

For this, first create local.xml file.

File: app\design\frontend\[your_package]\[your_theme]\layout\local.xml

 
  
   
    _current_grid_modegrid
   
  
  
   
    _current_grid_modelist
   
  
  
   
    _current_grid_modelist
   
  
 
We are done. Now remove the cache and then load the categories. You see the magic, don't you ? :)

Code in Detail

First I need to tell you about local.xml file. It is a special layout udpation file which will process by Magento after processing every other layout update XML files. Hence this layout updation file is more powerful in literal sense. For an example, for quick layout changes or updations, we can obviously use local.xml file.

product_list_toolbar block is the focused block here. This block holds management of product list modes. This block is defined in app\code\core\Mage\Catalog\Block\Product\List\Toolbar.php. I need your attention on Mage_Catalog_Block_Product_List_Toolbar::getCurrentMode() method. It looks like this

    public function getCurrentMode()
    {
        $mode = $this->_getData('_current_grid_mode');
        if ($mode) {
            return $mode;
        }
        $modes = array_keys($this->_availableMode);
        $defaultMode = current($modes);
        $mode = $this->getRequest()->getParam($this->getModeVarName());
        if ($mode) {
            if ($mode == $defaultMode) {
                Mage::getSingleton('catalog/session')->unsDisplayMode();
            } else {
                $this->_memorizeParam('display_mode', $mode);
            }
        } else {
            $mode = Mage::getSingleton('catalog/session')->getDisplayMode();
        }

        if (!$mode || !isset($this->_availableMode[$mode])) {
            $mode = $defaultMode;
        }
        $this->setData('_current_grid_mode', $mode);
        return $mode;
    }
This function's job is to return the current product list mode. But please note the line just above the return statement. ie

    $this->setData('_current_grid_mode', $mode);
This reveals the fact that, the property _current_grid_mode actually holds the mode information. So this is what we are doing through your layout update. ie

 
  _current_grid_modegrid
 

Note 1:
When I tried

    grid
it didn't work. It reveals the fact that, we cannot use the magic methods of Magento through layout update. Because.. you know experience is the greatest teacher in the world :)

Thanks for go through this. I will catch you later :)

Tuesday, 22 July 2014

On 18:56 by Unknown in , ,    1 comment
Some times, it would be great if we can add a collapse/expand functionality in CMS Pages in Magento. A perfect example would be a read more option. When we display very long documents through CMS pages, it would be nice if we shrink the content part to a small section and add a read more link bottom of it. When user clicks on that link, the content will be expanded.

We can achieve this functionality by implementing a custom extension. I will show you the steps that we need to take to achieve this. So our extension should have a name Programmerrkt_AdvancedCms.

First step is activating our module. For this add this file in etc/modules

Location : app/etc/modules/Programmerrkt_AdvancedCms.xml


Next step is to define configuration of our module. Let us do that.

Location : app/code/local/Programmerrkt/AdvancedCms/etc/config.xml


This file tells to Magento that our module has a layout file for frontend section. That's it. Our layout file is the heart of our module. It is going to hold the important parts of our module. Let us define our layout file.

Location : app/design/frontend/<.your_package>/<.your_theme>/layout/programmerrkt_advancedcms.xml


So here we defined layout for cms_page handler. Magento will look for this layout handler whenever a request for CMS page is made. So this handler would be a perfect handler for us. Next we added jquery and readmore.js in header section. Then at last we defined a template file script.phtml for holding our custom javascript code. Note that we included this template at the bottom of page.This is achieved by using the block before_body_end. This will ensure that, our custom code will invoked perfectly.

Now our script.phtml should look like this.

Location : app/design/frontend/<.yourpackag>/<.your_theme>/template/programmerrkt/advancedcms/readmore/script.phtml

	

As you can see readmore() method is called on an element with an id readomore-demo. So it is required that, you need to enclose all the content your cms page inside this id. Demo is shown here.
We are done. Our output will look like this.

So only thing you need to change is edit script.phtml file according to your needs.

Note: Remember you need to add jquery for proper working of this module. If you have jquery installed, then remove the code that add jquery in layout file. Also you need to download readmore.js and has to include it in skin/frontend/<.your_package/<.your_theme>/js/customjs/readmore.js. Similarly add css file in skin/frontend/<.your_package/<.your_theme>/css/customcss/readmore.css. You can use this css file to decorate links appear in your cms page.

Additional Note: readmore.js requires jquery greater than 1.7.0

Thursday, 26 June 2014

On 12:06 by Unknown in , ,    No comments
The main reason, in fact the inspiration behind this blog is this THREAD. In this thread, the user want to add layout that render by controller B by using controller A along with its layouts. For those who didn't understand the thread, I will explain the situation little bit.
So I have a module Programmerrkt_Checkout, which is used to provide two checkout views for my site. So in my module there are two controllers. Let us call them as Controller A and Controller B. Whenever url request these two controllers, it will show its own layouts in frontend. Let us create our module. Our config file should look like this

config.xml

Location:app/code/local/Programmerrkt/Checkout/etc/config.xml

As you can see, our config file do mainly 2 things here
  • Controller Rewrite
  • Layout updation
Controller Rewrite :-
It rewrites Mage_Checkout's CartController. This is because Our module is intended to provide two views for checkout/cart
Layout Updation :-
We defined our layout xml file here. It is using to hold the layouts of our controllers.

programmerrkt_checkout.xml

Location:app/code/design/frontend/base/default/layout/programmerrkt_checkout.xml

Here checkout_a_index is the layout handler for controller A. Similarly checkout_b_index is the layout handler for controller B. When www.yoursite.com/index.php/checkout/a loads it will loads content inside in checkout_a_index handler. When www.yoursite.com/index.php/checkout/b loads, it will load content that reside under checkout_b_index handler.
Now how these handlers are loading for A and B view. This is achieved through controllers. Let us look code inside our controllers

Controller B

Location:app/code/local/Programmerrkt/Checkout/controllers/BController.php

This is our controller B. As you can see it call load and render layouts. This will render content comes inside in checkout_b_index handler in its content section. (There are other layout handlers that are loading while do this. An example is default handler).

Controller A

Location:app/code/local/Programmerrkt/Checkout/controllers/AController.php
As I already stated it will render blocks that comes under checkout_a_index handler.

View

From the layout files, you can see that we are setting two templates to set view for A and B. Let me show the content in this file

a.phtml

Location:app/design/frontend/base/default/template/programmerrkt/checkout/a.phtml

b.phtml

Location:app/design/frontend/base/default/template/programmerrkt/checkout/b.phtml
Now load the url www.yourdomain.com/index.php/checkout/a, you will see following output

I am Controller A

I am content of A controller and I lies is layout definition for A controller
Similarly load the url www.yourdomain.com/index.php/checkout/b, you will see following output

I am Controller B

I am content of B controller and I lies is layout definition for B controller

The Real Problem

Now everything is perfect. Here the problem begins. Now we want to load the layout content of controller B, when url request for controller A. ie when www.yourdomain.com/index.php/checkout/a is requested, it should provide following output

I am Controller A

I am content of A controller and I lies is layout definition for A controller

I am Controller B

I am content of B controller and I lies is layout definition for B controller
How can we accomplish that ? Well, in my mind there are two awesome methods that we can depend on. They are
  • Use an event Observer to add layout handler of controller B to controller A
  • Make changes to codes in Controller A in such a way that it will load layout of controller B also
Using Controller
We can achieve what we want here by changing our controller A code like this

Controller A

Location:app/code/local/Programmerrkt/Checkout/controllers/AController.php
Here what we are done is `manual coding` and replacing of loadLayout() . Why we are doing loading of layout manually? The answer is, if we add $update->addHandle('checkout_b_index') before or after of loadLayout(), it does not make any effect on output. The reason is well explained by alanstorm in this THREAD.
Take a look on loadLayout() definition.

Action.php

Location:app/code/core/Mage/Core/controller/Varien/Action.php
This code reveals the fact that, in your controller we are actually using the same method that is used by default loadLayout() method,except for the addition of of a custom handle before calling loadLayoutUpdates(). (!important).
That's it. We achieved the desired result through controller. Now let us move on to our second approach. That is observer method
Event Observation
This is the most understandable method. Here we are observing for an event `controller_action_layout_load_before`. Add this code to config.xml

Config.xml

Location:app/code/local/Programmerrkt/Checkout/etc/config.xml
Add this code to observer

Observer.php

Location:app/code/local/Programmerrkt/Checkout/Model/Observer.php
when this event is listening, according to my understanding, magento resides in between `$this->addActionLayoutHandles()` and `$this->loadLayoutUpdates()`. That means it already loaded default, store, theme and action handles. So we are in the perfect position. We can add layout handle of controller B, if the current action is `checkout_a_index` (I used `if` condition for check that.). Note: This is a good tutorial that depicts this observer calling LINK
Now go and load url www.yourdomain.com/index.php/checkout/a. You can see the desired output in your page. :)