1

I've spent way too many hours digging through SO and the rest of the net looking for a solution to this, and after trying just about every suggestion I'm still at a loss.

The issue is we need dynamic content in the top bar. Currently this looks like...
Home | Categories | <LoggedInBlock> <LoggedOutBlock> <EveryoneBlock>
...where the three blocks are Static Blocks editable in the admin, and the LoggedIn and LoggedOut blocks are added in the layout via <customer_logged_in/out>.

Ultimately the goal is simply to have top menu links editable in the admin, and certain links hidden if logged in or out (whereas some links always appear). This works fine until Full Page Caching is enabled, at which point either the logged in version or logged out version get cached for all users to see regardless of their status.

Most recommendations revolve around block values like cache_lifetime/cache_tags/etc, but messing with any of these at the layout or block level seems irrelevant in regards to the Full Page Cache. The Catalognavigation FPC container isn't comparing cache ids and does it's job before the layout loads. I can only imagine Enterprise_PageCache_Model_Container_Catalognavigation needs to be overwritten to have user status somehow worked into it, but I can't say I know how to mess with these crazy caching functions.

I've considered giving up on hole punching the top menu althg and just removing the default one entirely, setting up a simple core/template block to build the menu in. Only issue with this is the categories menu in the Topmenu_Renderer block is intricately weaved into the topmenu code, to the point that trying to separate it seems impossible on the already expired time budget.

Magento EE 1.14.1

2
  • 1
    Just as an FYI. Generating the top nav. puts a fairly large burden on MySQL. If you're not caching it at all - you'll see a backlog of queries that will render the site completely offline. Mar 4, 2015 at 21:22
  • The solution I outlined below shouldn't have that issue, since it wraps the top menu and allows the categories dropdown to cache as normal.
    – Robert S
    Mar 6, 2015 at 2:59

2 Answers 2

0

If you remove them entirely from the layout doing something like below in the default tags in your local.xml

<reference name="header">
  <action method="unsetChild"><name>top.links</name></action>
</reference>

or per page like

<remove name="top.links" />

Then create a mini module with one controller method such as

public function indexAction()
{   
    $this->loadLayout();
  $this->renderLayout();
}

add this to your local.xml

<dynamicblocks_index_index>

    <reference name="root">
        <action method="setTemplate"><template>dynamicblocks/index.phtml</template></action>
    </reference>   


</dynamicblocks_index_index>

then in your dynamicblocks/index.phtml

<?php echo $this->getLayout()->getBlock('top.links')->toHtml() ?>

This whole page should just render your toplinks and by loading it from the website through an ajax call it won't get cached.

0

I finally was able to resolve this in a proper way. The solution was to side-step the crazy Catalognavigation caching altogether by wrapping it in a new block. We can even use the page/html_wrapper block type to limit our changes to simply our theme's local.xml and the page/html/topmenu.phtml template.

/app/design/frontend/INTERFACE/THEME/template/page/html/topmenu.phtml:
<?php if($this->getHtml('level-top')) echo $this->getChildHtml();

We're just stripping topmenu.phtml down to it's bare essentials, removing the <nav> and <ol> html containers. We could move these to a new template file, but even better we can recreate them in our layout...

/app/design/frontend/INTERFACE/THEME/layout/local.xml:

<reference name="header">
    <action method="unsetChild"><name>top.menu</name></action>
    <block type="page/html_wrapper" name="top.menu.nav" as="topMenu" before="top.container" translate="label">
        <action method="setHtmlTagName"><value>nav</value></action>
        <action method="setElementId"><value>nav</value></action>

        <block type="page/html_wrapper" name="top.menu.list">
            <action method="setHtmlTagName"><value>ol</value></action>
            <action method="setElementClass"><value>nav-primary</value></action>

            <block type="core/text_list" name="top.menu" translate="label">
                <label>Navigation Bar</label>
                <block type="page/html_topmenu" name="catalog.topnav" template="page/html/topmenu.phtml">
                    <block type="page/html_topmenu_renderer" name="catalog.topnav.renderer" template="page/html/topmenu/renderer.phtml"/>
                </block>
            </block>

            <block type="cms/block" name="my_custom_nav_block">
                <action method="setBlockId"><block_id>my_custom_nav_block</block_id></action>
            </block>
        </block>
    </block>
</reference>

Two html_wrapper blocks recreate the <nav> and <ol> elements. The as="topMenu" has to be moved to the top wrapper so the navigation prints the whole thing instead of just the top.menu piece.

I can now create my_custom_nav_block in the CMS static blocks and it'll be within the list but outside the nightmarish topnav caching. This is great because the categories dropdown is still cached, but now any block can easily be added to the list as desired by referencing top.menu.list (or whatever you want to name your topmost wrapper block), including with things like <customer_logged_in>.

The only caveat I've noticed so far is that the categories dropdown will always have the first and last CSS classes on it, thinking it's the only item in the list. For our theme at least this isn't an issue as we aren't utilizing those classes, and CSS selectors can easily be used in place of that .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.