WordPress cache a menu with Transient API

I want to plain to cache a page menu, that takes about 50 queries on page load.

At the moment I have cache setting code with Transient API

Read More
$housemenu = get_transient('housemenu_key');
    if (!$housemenu) {
        $housemenu = wp_nav_menu(
            array(
                'menu' => '',
                'menu_class' => 'sf-menu',
                'menu_id' => 'nav',
                'walker' => new description_walker()
            )
        );
        echo 'not-set';
        set_transient(
            'housemenu_key',
            $housemenu,
            60*60*3
        );
    }
echo $housemenu;

$housemenu = get_transient('housemenu_key'); returns a nothing. If i set like this:

$housemenu = 'return corrent';
echo 'not-set';

All works perfect. Why this menu is not working? Menu can be a walker transient?

Use: WordPress 3.8

Related posts

3 comments

  1. wp_nav_menu() doesn’t return anything by default, it just echoes out formatted html.

    For wp_nav_menu() to return a value you will need to pass 'echo' => false into it’s arguments, like so:

    $housemenu = wp_nav_menu( array(
        'menu' => '',
        'menu_class' => 'sf-menu',
        'menu_id' => 'nav',
        'walker' => new description_walker(),
        'echo' => 'false'
    ));
    

    It should be noted that by caching the entire menu in a transient, you will lose it dynamic nature. For instance if it cached it while on your home page all of the active classes applied to the menu items will ALWAYS reflect the home page. Thus if you were to visit a different page the active classes on the menu items would be wrong.

    This will cause quite a bit of pain if you wish to convey via CSS which page the current user is on.

  2. By default wp_nav_menu() echoes result and returns nothing. You need to set 'echo' => false in its arguments to flip the behavior and be able to assign result to a variable.

  3. one problem exists there… WordPress has built-in page detection, to give the CSS classes to current page in menu… and if cached, then your navigation menu-items will never get “current-page” class or etc..

    however, there are 2 solutions:

    Solution 1

    Before caching, once, add classes to <a> items:

    function add_menu_atts( $atts, $item, $args ) { 
       $atts['class'] = $item->type.'-'.$item->ID;      return $atts;  
    }
    add_filter( 'nav_menu_link_attributes', 'add_menu_atts', 8, 3 );
    

    and then cache the menu… it will have such output:

    <ul class="..." id="...">
    <li class="........"><a class="post_type-312" href="......">Post titleee (it's id is 312)</a></li>
    <li class="........"><a class="taxonomy-42" href="....">Category titleee (it's id is 42)</a></li>
    </ul>
    

    so, attach “current-item” class from javascript (in page body you should pass variable to javascript, to find out if you are on a post,page,category or etc..)… i.e.:

    <script>
    var CurrentPageType="post_type";  //or "taxonomy"(for categories); or author or etc...
    var CurrentItemId=612;
    var element = document.getElementsByClassName(CurrentPageType +'-'+ CurrentItemId)[0]; element.className +=" current-menu-item";
    </script>
    

    solution 2

    for typical,non wp-sites.
    i have tried to code a JS script, which may solve the problem..
    So, in case you cache the menu, and want to get “current-menu-item” class, then put this function in your page source/cache (better to be in the end of body):

    <script> Highlight_Current_Menu_link("current_item__from_JS", "parent_div_id" ); </script> 
    or
    <script> Highlight_Current_Menu_link("current_item__from_JS"); </script> 
    

    at first, add this code in header(better inside .js file):

    <script>
    function Highlight_Current_Menu_link(Added_class_name, Ancestor_to_search_in, link_to_find){
        var Added_class_name = Added_class_name || "current_item__from_JS";  
        var link_to_find = link_to_find || window.location.pathname;
        var Ancestor_to_search_in = typeof Ancestor_to_search_in === "undefined" ? document.body : getElementById(Ancestor_to_search_in);
        var A_elements = Ancestor_to_search_in.getElementsByTagName("a");
        for(var i=0; i<A_elements.length; i++){
            var condition=false;
            var href=A_elements[i].href.replace(window.location.origin,""); 
            if(href.indexOf('#')>-1 && href==link_to_find)  {condition=true;}
            else if( RemoveHashString(link_to_find).indexOf(RemoveHashString(href)) >- 1 && 
                href.substring(0, href.lastIndexOf("/")).trim() == link_to_find.substring(0, link_to_find.lastIndexOf("/")).trim()
                ) {
                 condition= true;
            }
            if (condition) { A_elements[i].className += " "+Added_class_name; }
        }
    }
            function RemoveHashString(str){  var hash=str.split("#")[1];  return str.replace("#"+hash,'');  }
    </script>
    

    and determine your desired style to the attached class

    <style>
    .current_item__from_JS{background:red;}
    </style>
    

Comments are closed.