Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy


Add to Technorati Favorites Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

Dynamically switching the theme in Orchard

(c) Bertrand Le Roy 2010It may sound a little puzzling at first, but in Orchard CMS, more than one theme can be active at any given time. The reason for that is that we have an extensibility point that allows a module (or a theme) to participate in the choice of the theme to use, for each request. The motivation for building the theme engine this way was to enable developers to switch themes based on arbitrary criteria, such as user preferences or the user agent (if you want to serve a mobile theme for phones for example). The choice is made between the active themes, which is why there is a difference between the default theme and the active themes.

In order to have a say in the choice of the theme, all you have to do is implement IThemeSelector. That interface is quite simple as it only has one method, GetTheme, that takes the current RequestContext and returns a ThemeSelectorResult or null if the implementation of the interface does not want to participate in the current request (we'll see an example in a moment). ThemeSelectorResult itself is just a ThemeName string property and an integer Priority. We're using a priority so that an arbitrary number of implementations of IThemeSelector can contribute to the choice of a theme.

If you look for existing implementations of the interface in Orchard, you'll find four:

  • AdminThemeSelector: selects the TheAdmin theme with a very high priority (100) if the current request is for a page that is part of the admin. Otherwise, null is returned, which enables other implementations to choose the theme.
  • PreviewThemeSelector: selects the preview theme if there is one, with a high priority (90), and null otherwise. This enables administrators to view the site under a different theme while everybody else continues to see the current default theme.
  • SiteThemeSelector: this is the implementation that is doing what you expect most of the time, which is to get the current theme from site settings and set it with a priority of –5.
  • SafeModeThemeSelector: this is the fallback implementation, which should almost never win. It sets the theme as the safe mode theme, which has no style and just uses the default templates for everything. The priority is very low (-100).

While this extensibility mechanism is great to have, I wanted to bring that level of choice into the hands of the site administrator rather than just developers. In order to achieve that, I built the Vandelay Theme Picker module.

The module provides administration UI to create rules for theme selection.The theme picker admin UI

It provides its own extensibility point (the IThemeSelectionRule interface) and one implementation of a rule: UserAgentThemeSelectorRule. This rule gets the current user agent from the context and tries to match it with a regular expression that the administrator can configure in the admin UI.

You can for example configure a rule with a regular expression that matches IE6 and serve a different subtheme where the stylesheet has been tweaked for such an antique browser. Another possible configuration is to detect mobile devices from their agent string and serve the mobile theme. All those operations can be done with this module entirely from the admin UI, without writing a line of code.

The module also offers the administrator the opportunity to inject a link into the front-end in a specific zone and with a specific position that enables the user to switch to the default theme if he wishes to. This is especially useful for sites that use a mobile theme but still want to allow users to use the full desktop site.

While the module is nice and flexible, it may be overkill. On my own personal blog, I have only two active themes: the desktop theme and the mobile theme. The desktop and mobile themes side by side

I'm fine with going into code to change the criteria on which to switch the theme, so I'm not using my own Theme Picker module. Instead, I made the mobile theme a theme with code (in other words there is a csproj file in the theme). The project includes a single C# file, my MobileThemeSelector for which the code is the following:

public class MobileThemeSelector : IThemeSelector {
    private static readonly Regex _Msie678  =
new Regex(@"^Mozilla\/4\.0 \(compatible; MSIE [678]" +
@"\.0; Windows NT \d\.\d(.*)\)$",
RegexOptions.IgnoreCase); private ThemeSelectorResult _requestCache; private bool _requestCached; public ThemeSelectorResult GetTheme(RequestContext context) { if (_requestCached) return _requestCache; _requestCached = true; var userAgent = context.HttpContext.Request.UserAgent; if (userAgent.IndexOf("phone",
StringComparison.OrdinalIgnoreCase) != -1 || _Msie678.IsMatch(userAgent) || userAgent.IndexOf("windows live writer",
StringComparison.OrdinalIgnoreCase) != -1) { _requestCache = new ThemeSelectorResult { Priority = 10, ThemeName = "VuLuMobile" }; } return _requestCache; } }

The theme selector selects the current theme for Internet Explorer versions 6 to 8, for phones, and for Windows Live Writer (so that the theme that is used when I write posts is as simple as possible).

What's interesting here is that it's the theme that selects itself here, based on its own criteria.

This should give you a good panorama of what's possible in terms of dynamic theme selection in Orchard. I hope you find some fun uses for it. As usual, I can't wait to see what you're going to come up with…

Comments

Confused N00b said:

This is probably the dumbest question in the world, but how do you actually USE it?  I had no problem installing it and it is listed in modules, but I don't see any way to configure it.

# March 10, 2011 3:21 AM

Confused N00b said:

Oops! I found it in the menu under Themes | Picker.  Sorry, it was such a subtle change to the menu that I missed it.

For ref: ~/Admin/VandelayThemePicker

# March 10, 2011 3:28 AM

techieg said:

Great job! I actually need this feature since I am working on a site that has a public-facing theme that is different from the backend user/administration theme (and mobile as well). The link you posted for it above is broken, where can I get it?

# March 16, 2011 10:00 AM

Bertrand Le Roy said:

I fixed the link.

# March 16, 2011 1:25 PM

Swayam said:

Menu item doesn't show up in Orchard 1.1

# April 27, 2011 6:30 PM

Bertrand Le Roy said:

What menu item?

# April 27, 2011 6:33 PM

Arra Derderian said:

After install I can't seem to find the admin menu link that goes to /Admin/VandelayThemePicker

# September 15, 2011 9:23 PM

Bertrand Le Roy said:

@Arra: wrong version of Orchard maybe?

# September 15, 2011 9:26 PM

Robert Maier said:

Hey!

I'm using Orchard v.1.2.41.0 and installed your module. I don't have a menu item in the admin-panel called themes/Picker.

Any tipps for me? :)

# September 19, 2011 8:58 AM

Bertrand Le Roy said:

@Robert: once the feature is enabled, there is an additional tab under Themes.

# September 19, 2011 6:24 PM

Arra Derderian said:

I have Orchard v.1.2.41.0 installed. I enabled and disabled the plugin but am not seeing the item on the left hand nav under Themes.

# September 19, 2011 7:26 PM

Bertrand Le Roy said:

@Arra: it appears as a tab on the right side when you click on themes.

# September 19, 2011 7:32 PM

Arra Derderian said:

Weird. I only have "Installed", "Gallery", "Updates". I can browse to the URL if I hardcode it in and all works. Just not seeing the link.

# September 19, 2011 7:40 PM

Bertrand Le Roy said:

@Arra: are you sure you enabled the right feature?

# September 19, 2011 7:44 PM

Arra Derderian said:

@Bertrand: VandelayThemePicker under Design.

# September 19, 2011 7:57 PM

Bertrand Le Roy said:

@Arra: yeah, well, I don't know. Works on my machine. Do you have the latest Orchard and Vandelay Industries module?

# September 19, 2011 8:05 PM

Arra Derderian said:

@Bertrand: Vandelay = 1.0

Orchard is v.1.2.41.0

I will check the logs.

# September 19, 2011 8:41 PM

Bertrand Le Roy said:

The latest version of this code can be found in orchardproject.net/.../1.2.3

# September 19, 2011 9:02 PM

Philip Senechal said:

The link that is generated to return to the default theme results in an error page.

The URL it's attempting to redirect to is:

www.mysite.com/.../UseDefault

The error I get is: No route in the route table matches the supplied values.

Looking at the Controller, it's redirecting to Controller: Home, Action: Index, Namespace: HomePage.

Has that changed in 1.4 to a new route value?

# April 24, 2012 4:07 PM

Bertrand Le Roy said:

@Philip: you don't need that module for the preview feature any more. It's been available out of the box for many months.

# May 1, 2012 11:39 PM