Provide Frontend Layout Handle to Adminhtml to Render Frontend Page/Blocks

adminhtmlfrontendlayoutupdate-handle

I'm currently working on a project which requires an area in the Admin panel which allows the admin to modify order related data (custom data set on order items) that can only be handled through a custom made GUI using Backbone/FabricJS. This GUI operates as a pseudo Product Page to load product related data relevant to the tasks performed within the GUI. This is done through a route defined in my module, which also has an associated layout file with a single layout handle for the frontend route to the GUI. I would like to provide access to this GUI from within the Admin panel (specifically from the order edit page as a link/button), however it is proving difficult to add that layout handle (including it's updates) to the adminhtml layout.

Can anyone suggest a way to load frontend layout handles to the adminhtml layout XML to provide such functionality?

Frontend Layout XML

<?xml version="1.0" encoding="UTF-8"?>
<layout>
    <gui_index_index>
        <reference name="root">
            <action method="setTemplate"><template>page/gui.phtml</template></action>
        </reference>
        <remove name="footer"/>
        <remove name="left"/>
        <remove name="header"/>
        <reference name="head">

            <!-- don't index the customizer -->
            <action method="setRobots"><value>NOINDEX,NOFOLLOW</value></action>

            <!--add productjs for options pricing-->
            <action method="addJs"><script>varien/product.js</script></action>
            <!--remove extraneous css -->
            <action method="removeItem"><type>skin_css</type><name>css/styles.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/widgets.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/cloud-zoom.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/slider.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/local.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/mobile.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/animation.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/settings.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/captions.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/override.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/print.css</name></action>
            <action method="removeItem"><type>skin_css</type><name>css/responsive.css</name></action>
            <!--remove extraneous js -->
            <action method="removeItem"><type>js</type><name>lib/ccard.js</name></action>
            <action method="removeItem"><type>js</type><name>scriptaculous/builder.js</name></action>
            <action method="removeItem"><type>js</type><name>scriptaculous/dragdrop.js</name></action>
            <action method="removeItem"><type>js</type><name>scriptaculous/controls.js</name></action>
            <action method="removeItem"><type>js</type><name>scriptaculous/slider.js</name></action>
            <action method="removeItem"><type>js</type><name>lib/ccard.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/cloud-zoom.1.0.2.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.ui.totop.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.hoverIntent.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.masonry.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.anystretch.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.mousewheel.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.easing.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.flexslider-min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.themepunch.plugins.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.themepunch.revolution.min.js</name></action>
            <action method="removeItem"><type>js</type><name>queldorei/jquery.jcarousel.min.js</name></action>
            <action method="removeItem"><type>skin_js</type><name>js/enterprise/catalogevent.js</name></action>
            <action method="removeItem"><type>skin_js</type><name>js/enterprise/wishlist.js</name></action>
            <action method="removeItem"><type>skin_js</type><name>js/script.js</name></action>
            <!--add customizer css / js -->
            <action method="addItem"><type>skin_css</type><name>css/customizer.css</name></action>
            <action method="addItem"><type>skin_css</type><name>js/bootstrap-timepicker/bootstrap-timepicker.css</name></action>
            <action method="addItem"><type>skin_js</type><name>js/customizer/customizer.js</name></action>
            <!--add smallipop css from git submodule repo -->
            <action method="addItem"><type>js_css</type><name>lib/smallipop/css/jquery.smallipop.min.css</name></action>
        </reference>
        <reference name="content">
            <block type="core/text_list" name="product.json">
                <block type="catalog/product_view" name="product.options.json" template="gui/product/view/view.phtml">
                    <block type="gui/catalog_product_view" name="product.info.options.wrapper" as="product_options_wrapper" template="gui/product/view/options/wrapper.phtml" translate="label">
                        <label>Info Column Options Wrapper</label>
                        <block type="catalog/product_view_options" name="product.info.options" as="product_options" template="catalog/product/view/options.phtml">
                            <action method="addOptionRenderer"><type>text</type><block>catalog/product_view_options_type_text</block><template>catalog/product/view/options/type/text.phtml</template></action>
                            <action method="addOptionRenderer"><type>file</type><block>catalog/product_view_options_type_file</block><template>catalog/product/view/options/type/file.phtml</template></action>
                            <action method="addOptionRenderer"><type>select</type><block>catalog/product_view_options_type_select</block><template>catalog/product/view/options/type/select.phtml</template></action>
                            <action method="addOptionRenderer"><type>date</type><block>catalog/product_view_options_type_date</block><template>catalog/product/view/options/type/date.phtml</template></action>
                        </block>
                        <block type="gui/bundle_catalog_product_view_type_bundle" name="product.info.bundle.options" as="type_bundle_options" template="bundle/catalog/product/view/type/bundle/options.phtml">
                            <action method="addRenderer"><type>select</type><block>bundle/catalog_product_view_type_bundle_option_select</block></action>
                            <action method="addRenderer"><type>multi</type><block>bundle/catalog_product_view_type_bundle_option_multi</block></action>
                            <action method="addRenderer"><type>radio</type><block>bundle/catalog_product_view_type_bundle_option_radio</block></action>
                            <action method="addRenderer"><type>checkbox</type><block>bundle/catalog_product_view_type_bundle_option_checkbox</block></action>
                        </block>
                    </block>
                </block>
                <block type="gui/bundle_catalog_product_view_type_bundle" name="bundle.tojson" template="gui/product/view/type/bundle.phtml" />
                <block type="gui/catalog_product_view" name="product.sides" template="gui/product/view/sides.phtml" />
            </block>
            <block type="core/template" name="options_js" template="catalog/product/view/options/js.phtml" output="toHtml"/>
        </reference>
        <reference name="product.options.json">
            <block type="bundle/catalog_product_view_type_bundle" name="product.info.bundle" as="product_type_data" template="bundle/catalog/product/view/type/bundle.phtml">
                <action method="addPriceBlockType"><type>bundle</type><block>bundle/catalog_product_price</block><template>gui/product/view/price.phtml</template></action>
            </block>
        </reference>
        <reference name="before_body_end">
            <block type="core/text" name="amd.js.loader">
                <action method="setText"><text><![CDATA[<script data-main="/js/customizer/main" src="/js/lib/requirejs/require.js"></script>]]></text></action>
            </block>
            <block type="core/text" name="font.js.loader">
                <action method="setText"><text><![CDATA[<script src="//ajax.googleapis.com/ajax/libs/webfont/1.5.0/webfont.js"></script>]]></text></action>
            </block>
        </reference>
    </gui_index_index>
    <gui_project_load>
        <update handle="gui_index_index"/>
        <remove name="product.json"/>
    </gui_project_load>
</layout>

Adminhtml Layout XML:

<?xml version="1.0" encoding="UTF-8"?>
<layout>
    <adminhtml_gui_index>
              <update handle="gui_index_index" />
    </adminhtml_gui_index>
</layout>

Adminhtml Index Action:

public function indexAction()
{

    $appEmulation = Mage::getSingleton('core/app_emulation');

    $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation('default','frontend');

/*        Mage::getDesign()->setArea('frontend');
        Mage::getDesign()->setTheme((string)Mage::app()->getConfig()->getNode('stores/default/design/theme/template'));
        Mage::getDesign()->setPackageName((string)Mage::app()->getConfig()->getNode('stores/default/package/name'));
*/
    //$this->getLayout()->getUpdate()->addHandle('gui_index_index');
    //$this->loadLayoutUpdates();

    //$this->loadLayout('gui_index_index', true, true);
    $this->loadLayout();
    //$this->getLayout()->getUpdate()->load('gui_index_index');
    //$this->getLayout()->generateXml();
    //var_dump(Mage::app()->getLayout()->getUpdate()->getHandles());die();
    $this->renderLayout();

    $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);

}

Best Answer

In general, the cheapest way to achieve this is via environment app emulation, which it seems you're already doing. I would go ahead and pursue this route and look elsewhere in your layout definitions and local.xml for remove and unset definitions.

Something the below should coax the admin into loading the frontend root block for your design, but you should expect to have to refactor your domain logic out of controllers because it seems like your layout depends on the controller route. This can easily be handled by rather depending on assign:

public function indexAction()
{
    $product = Mage::getModel('catalog/product')->load(24); //obviously this is being loaded in some other way

    $appEmulation = Mage::getSingleton('core/app_emulation');

    $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation('default','frontend');

    $this->loadLayout();
    $this->getLayout()->getBlock('root')->assign(array('current_product',$product));
    $this->renderLayout();

    $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);

}
Related Topic