Currently I have two different controllers and Magento checkout is split into two ways, let's say A and B, thus URL is checkout/A checkout/B - both available for customer. Both of them are onepage checkout. For both of them I have layout XML file; for B I'm removing many blocks from whole page so it's very simplified. I would like to move these changes to one URL, so by some settings there will be displayed checkout A or checkout B randomly. How to force in custom controller changes that I made with layout XML file?
-
did you have 2 modules for each checkouts ?– Rajeev K TomyCommented Jun 26, 2014 at 11:06
-
One module that overrides default Magento Checkout.– Filip GórczyńskiCommented Jun 26, 2014 at 11:47
-
so one controller that you referenced is default one and other one is from your module itself. Am I right ?– Rajeev K TomyCommented Jun 26, 2014 at 11:50
-
I have 2 controllers in one module. Onepage checkout overrides Magento OnepageCheckout. Second controller - Simplified version of Magento OnePageCheckout.– Filip GórczyńskiCommented Jun 26, 2014 at 12:14
3 Answers
Here I am demonstrating what is your current state(According to my understanding) and how to solve your problem.
So you have basically two controllers that is defined for checkout. The url paths that invoke your controllers then somewhat look like this www.yoursite.com/index.php/checkout/a
(For controller with name A
) and www.yoursite.com/index.php/checkout/b
(For controller with name B
). I assume indexAction()
method in your controllers are used to load and render the layouts. They loads their own layouts. Everything is perfect untill here. Now you want to render layout that render by controller B along with layouts of controller A, when www.yoursite.com/index.php/checkout/a
is requested.
You can achieve this in two ways (There may be other ways).
Through an event observer
through controller A
Through an event observer
We are going to listen to the event controller_action_layout_load_before
. This event will call before any layout loads. We will inject the layout of controller B to that of control A. So
Config.xml
<config>
<frontend>
<events>
<controller_action_layout_load_before>
<observers>
<checkout_controller_action_layout_load_before>
<class>programmerrkt_checkout/observer</class>
<method>controllerActionLayoutLoadBefore</method>
</checkout_controller_action_layout_load_before>
</observers>
</controller_action_layout_load_before>
</events>
</frontend>
</config>
Observer
<?php
class Programmerrkt_Checkout_Model_Observer
{
const LAYOUT_HANDLE_TO_CHECK_WITH = 'checkout_a_index';
const LAYOUT_HANDLE_TO_ATTACH = 'checkout_b_index';
public function controllerActionLayoutLoadBefore(Varien_Event_Observer $observer)
{
/** @var $layout Mage_Core_Model_Layout_Update */
$update = $observer->getEvent()->getLayout()->getUpdate();
$handles = $update->getHandles(); //get all handles
//If layout handle of controller A is not in action, will not attach the handles
if(in_array(self::LAYOUT_HANDLE_TO_CHECK_WITH , $handles))
{
$update->addHandle(self::LAYOUT_HANDLE_TO_ATTACH);
}
}
}
Through Controller Method
Now we can load layout of controller B through controller A. This is little tricky. This is because we cannot use loadLayout()
method, if we are planning to use controller for this purpose. Why ? this THREAD gives an answer for that (checkout alanstorm's answer). In short, if we add handle of controller B (checkout_b_index
in this case), before or after the method loadLayout()
, its not going to make any difference. So what we need to do is, we need to replace loadLayout() with our codes, so that checkout_index_b
handle also added to the layout tree of controller A.
So your controller A should look like this.
public function indexAction()
{
//code follows some what replaces loadLayout() method
$update = $this->getLayout()->getUpdate();
$update->addHandle('default'); //attach layout handle of for controller A
$this->addActionLayoutHandles();
$update->addHandle('checkout_b_index'); //attach layout handle of controller B
$this->loadLayoutUpdates();
$this->generateLayoutXml();
$this->generateLayoutBlocks();
$this->_isLayoutLoaded = true;
$this->renderLayout();
}
That's it. Now load the url www.yoursite.com/index.php/checkout/a
. You can see content of both A and B in there.
Check my blog for better understanding http://rajeev-k-tomy.blogspot.in/2014/06/add-layout-to-another-layout.html
In your controller, you can always add another layout handle:
$update = $this->getLayout()->getUpdate();
$update->addHandle('layout_b_changes');
And then you make all the relevant changes in your layout XML file.
-
What shoul layout_b_changes in addHandle() contain? I tried with layout XML element name, block name, and few other but nothing worked. Commented Jun 26, 2014 at 12:33
-
Don't forget to add
$this->loadLayoutUpdates();
for the changes to take effect Commented Jun 26, 2014 at 19:29
Source code from page http://makandracards.com/magento/8209-adding-a-layout-handle-from-a-controller solved my problem.
-
Please add at least an abstract of the page, so when the link is dead, your answer is still valuable. Commented Jun 26, 2014 at 22:39