8th January 2016

The Curious Incident of the Wrong Theme being used after a Cache Clear in Drupal 7

John Ennew
Technical Director

If you are using Drupal 7, have multiple themes enabled, are using hook_custom_theme() to choose the right one and find that after a cache clear the first page load chooses the wrong theme, then this blog post is for you.

On a couple of recent projects we have been using hook_custom_theme() to set one of several active themes for a given page request. This is a really useful hook allowing us to change the look and feel for different parts of the site. For example, we might use a different theme if a page is part of a Drupal Group which makes it look like a sub-site.

We were seeing an odd behaviour where the site default theme would load on the first page request after a cache clear, rather than the one we were returning from our hook_custom_theme implementation. Debugging showed that hook_custom_theme() was being fired and our implementation was returning the right option during the first page load.

Subsequent page requests following the first after a cache clear would result in the correct theme being used. The problem was that if that first page was opened by an anonymous user it would get varnish cached and all users would see the page in the wrong theme for a few hours.

The reason

The problem is the functions we were putting into hook_custom_theme().

hook_custom_theme() along with hoot_url_inbound_alter() and hook_boot() all get called very early in the drupal boot cycle and not everything has been properly initialised at this point, including the correct theme. If you call code that assumes this has happened then odd things can happen.

Following a cache clear the menu needs to be rebuilt - and this is a complex operation which calls a lot of code and prematurely sets the site to use the default theme.

If you access the menu, for example by using ​menu_get_item, ​menu_get_object or even node_load​ in these functions you will trigger a menu build too early and initialise the default theme. 

Solutions

The solutions are to keep the code in the hooks which run before the theme is initialised as simple as possible.

For example, do you need to load the menu to decide the theme or can it be infered from the current path? Rather than load the whole node, can you do a simple db_select on the node table to get the information you need?