I'm using switch_theme() to switch between default and mobile themes for my visitors in real time. Here's my code :

// Get the user agent
$user_agent = $_SERVER['HTTP_USER_AGENT'];

// Preg match for mobile browsers (courtesy : detectmobilebrowsers.com)
$preg_match = preg_match( '/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$user_agent) || preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i', substr( $user_agent, 0, 4 ) );

// If user is on a mobile browser
if( $preg_match ) {

    // Switch theme
    switch_theme( 'theme_mobile' );


// Else show default theme
else {

    // Switch theme
    switch_theme( 'theme_default' );


The problem is that sometimes the switching doesn't work, for example I'm on a desktop browser but it still switches so mobile. I suspect it has something to do with heavy traffic load on the website (approx. 100 visitors online at any moment). Is there a way to optimize that ?

  • 1
    I think Media queries are a far better solution. Commented Mar 5, 2014 at 11:03
  • @Brad Dalton, the mobile theme has significantly different functionalities than the default one, that's why media queries were dropped as a choice. For mobile we have a very simple theme with very little server load. It's not just an aesthetic issue.
    – mike23
    Commented Mar 5, 2014 at 11:12
  • 1
    I would not abuse theme_switch for this purpose. (Just off the top of my head: sounds like a novel way to allow your site to get DDoSed, using its own functionality against it. Also: what happens when one person is viewing the site via mobile and another person is viewing the site via desktop browser?) If you can reliably use $_SERVER['HTTP_USER_AGENT'], then why not just use it directly in the template files, to enable/output functionality conditionally? Commented Mar 5, 2014 at 12:42

1 Answer 1


First of all, you should know that $_SERVER['HTTP_USER_AGENT'] is not fully reliable because its output is based on http request User-Agent header, and so it can be easily omitted or disguised.

That said, sure your method will detect the majority of mobile requests, but be aware the mayority is not totality.

Now, you know that current theme is based essentially on a option: template (and if you have active a child theme the option is stylesheet). This option contain the slug of the theme (normally the theme folder name).

What switch_theme does is updating that option, so runs a query on database. In addition, you need to also run that function even if the default theme (setted in admin) is the non-mobile and the request is from non mobile.

The optimized solution is to use the shortcut filter for options: "pre_option_{$option}", that is fired before any option is getted, and if the function hooked there returns a non false value that value is returned without any database query.

That brings 2 advantages:

  1. you don't need to run any db query when need to output the non-default theme
  2. you don't need to do anything when need to use the default theme

The code is pretty easy, just 3 lines:

if( wp_is_mobile() ) {
    add_filter( 'pre_option_template', function() { return 'theme_mobile'; } );
    add_filter( 'pre_option_stylesheet', function() { return 'theme_mobile'; } );

I've used wp_is_mobile function for sake of semplicity, it's not 100% reliable, but how said in first lines, nothing using $_SERVER['HTTP_USER_AGENT'] is 100% reliable.

Please note that:

  1. if the mobile theme is a child theme (and parent theme is the same for both mobile and not mobile) you must use the only 'pre_option_stylesheet'
  2. my code require PHP 5.3+ due to the usage of a closure
  • Thank you for the detailed answer. Strangely when I test "pre_option_template" there is no effect whatsoever. With "pre_option_stylesheet", the stylesheet does change, but my mobile theme is not a child theme so that doesn't help much.
    – mike23
    Commented Mar 5, 2014 at 17:41
  • 1
    @mike23 yep, you're right, you need to perform both "pre_option_template" and "pre_option_stylesheet" to make it works when swapping parent template. Answer updated. That's because changing onlt theme, WP notify a differ from theme and child theme, and thinks default parent theme is a child of mobile one.
    – gmazzap
    Commented Mar 5, 2014 at 18:32
  • Awesome, now it's all right.
    – mike23
    Commented Mar 5, 2014 at 18:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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