Jump to:

3392 Posts in 976 Topics by 852 members

Template Questions

SilverStripe Forums » Template Questions » Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING

Moderators: martimiz, Sean, biapar, Willr, Ingo, swaiba, simon_w

Page: 1
Go to End
Author Topic: 771 Views
  • davepolyester
    Avatar
    Community Member
    44 Posts

    Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    Hi all,

    I've built a site (in SS 2.4.7) for a client to use as a knowledgebase and, as such, it contains a vast number of pages with much more hierarchical depth than your average site.

    We've been having speed issues which may be a result of hosting on Dreamhost, but I've noticed that the menu system seems to affect the page load speed greatly.
    A page with the menu switched on takes about 6-8 seconds to load, but the same page with the menu switched off takes about 2 seconds.
    I'm concerned this means each page load is having to dig the whole content of every page out of the database so it can populate the menu with all the Titles of every sub page!

    The menu is a fairly standard 'Suckerfish' style flyout, with about six levels of depth, and I've attached my template code for you to check out. Please let me know if you spot anything dodgy in there that could help.

    I wonder if there might be a way to delay the populating of deeper levels of the menu until someone actually hovers over the menu?

    Any advice on dealing with this kind of site in SS will be much appreciated.

    BTW, am getting YSlow scores of about 83-94 so the site overall should be pretty speedy I think.

    Cheers!

    Attached Files
  • kaanuni
    Avatar
    Community Member
    22 Posts

    Re: Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    First of all if there is a will there is a way. So yes you can 'delay the populating deeper levels of the menu until someone actually hovers over the menu'. It would however be complicated. You would need to use ajax/json. It appears you are using css for the menu except for old browsers. So what you would do is load the first level of the menu and add a onmouseover="loading_function($li_id)" property to the <li>'s or use jQuery to the same effect (note whatever way you do it you will have to add id properties to the menu items). Next you will need to define loading_function in a javascript file so that it reads a url on your server to get the sub menu items. And finally you will have to create a new template and page type for this url, possibly with a custom controller so that it returns one level of menus in json format.

    However, besides not being the easiest solution this is not the best solution either, since it won't work for browsers that have disabled javascript. There are other options:

    1- Overload the getMenu method of your controller and use custom SQL to fetch only the columns you need. Or write a new function like getSimpleMenu (probably a better idea).
    2- Write a getEntireMenu method in your controller that uses custom SQL to fetch the relevant columns for site tree for the entire menu and output it. This will allow you to optimize the code for your menu depth and will result in less function calls. However you will either have to include HTML in your controller (which is icky) or output javascript (which is not only equally icky, but also sucks for SEO).
    3- Use partial or total caching, read: http://doc.silverstripe.org/framework/en/reference/partial-caching http://doc.silverstripe.org/framework/en/2.4/reference/partial-caching

    Method #1 is not terrible and you can do it along side #3 for even better performance. Method #2 is a bad idea in that it requires a lot of effort and any gains come at the expense of breaching the mvc model. #3 is quicker to implement and will likely give the largest performance boost on average.

    In this instance you would wrap your menu with this:

    <% cached 'navigation', List(Page).max(LastEdited) %> ***
    <% cached 'navigation', Aggregate(Page).Max(LastEdited) %>
    <% end_cached %>

    *** The struck out line is for 3.0, my bad.

    Now I haven't tried this, but according to the page at the link I posted, the section wrapped in this will be cached until any page on the site is edited. So if after you are done making edits you refresh a page on your site with the navigation, your visitors will always get a cached copy of the menu.

    Alternatively you can cache entire pages. You can read up on that here: http://doc.silverstripe.org/framework/en/reference/staticpublisher
    http://doc.silverstripe.org/framework/en/2.4/reference/staticpublisher

  • davepolyester
    Avatar
    Community Member
    44 Posts

    Re: Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    Thanks Kaanumi for your fantastic response. Great to get such excellent detail around possible solutions, their pros and cons, and how they'll work rather than just a simple "Do this..." with no explanation.

    I agree with you that the caching option should be the best method. I certainly don't want to introduce any ajax or other javascript to my menus, I much prefer lean, mean CSS styled versions.

    I'll take a look at the links in your posts and come back with any questions and the results from my implementation.

    Thanks once again!

  • davepolyester
    Avatar
    Community Member
    44 Posts

    Re: Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    Success! Partial-caching is now my best friend! By caching my menus I've reduced page load times from 8-10 seconds down to 2-5 seconds.
    Ran into a few gotchas though:

    1) If a <% require %> tag is inside the <% cache %> tag, it ceases to be called once the content is cached. I had a CSS file in this situation and my menu would completely restyle itself once it was cached, defaulting to another CSS file further up the chain.

    2) I can't use the same menu for the Secure and Public sections of the site. If I do, the public end up seeing the Secure pages listed in their menu, though they can't access them of course.

    3) I've had to tweak my CSS as, for some reason, the a.Section and a.Current tags seem to cache sometimes too, resulting in the menu continuing to display a previously visited page as the Current page. This seems a bit intermittent so I'm confused, but I've simply disabled my styling for Current pages so it won't affect end users.

    Thanks once again Kaanumi for pointing me towards the partial-caching feature - it has saved Silverstripe from being dumped by the client on this project!

  • Willr
    Avatar
    Forum Moderator
    5462 Posts

    Re: Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    2) Use the CurrentMember flag as part of your cache key.

    3) Add ID as part of the cache key

    <% cached 'Menu', Aggregate(SiteTree).Max(LastEdited), ID, CurrentMember.ID %>

  • davepolyester
    Avatar
    Community Member
    44 Posts

    Re: Menu Slowing Load Times - SOLVED WITH PARTIAL CACHING Link to this post

    Thanks for the CurrentMember.ID tip Will, that should fix the anomalies for me. Unfortnately I'm still getting some issues:

    If I log in with one user, then log out and log back in with a second user who has different page view permissions, the second user still sees the menu as it appeared to the first user, including items that should be restricted. (If they click the items they are told they don't have access.)

    Is there something else I need to do to force the menu to render according the current user's page access rights?

    Could it be caused by the fact that the cached menus are all in Includes, not directly in any page template?

    Thanks again.

    771 Views
Page: 1
Go to Top

Want to know more about the company that brought you SilverStripe? Then check out SilverStripe.com

Comments on this website? Please give feedback.