Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Some plugins use the 'template', 'option_template' and 'option_stylesheet' to dynamically serve (alternative) wordpress templates. For example, Nathan Rice's ServeDefaultToIESix. For Example -

add_filter('template', 'change_theme');
add_filter('option_template', 'change_theme');
add_filter('option_stylesheet', 'change_theme');

function change_theme() 
{
    // Alternate theme
    return 'AwesomeTheme';
}

Above code only works from a wordpress plugin. What i need, is to switch to alternative template, located in one of the subfolders of the current theme(template). Examples: display an alternative HTML5 theme, serve mobile users a minimal version of the site.. etc.

I tried to use 'theme_root' and 'theme_root_uri' as below. But that isn't working.

// Extra lines to change the theme's root.
add_filter('theme_root', 'change_theme_root');
add_filter('theme_root', 'change_theme_root_uri');
//
add_filter('template', 'change_theme');
add_filter('option_template', 'change_theme');
add_filter('option_stylesheet', 'change_theme');

function change_theme() 
{
    // Display Alternate theme
    return 'AwesomeTheme';
}

function change_theme_root()
{
    // Return the new theme root
    return WP_CONTENT_DIR . 'themes/OrigTheme/lib/AltThemes';
}

function change_theme_root_uri()
{ 
     // Return the new theme root uri
     return get_bloginfo('wpurl') . '/wp-content/themes/OrigTheme/lib/AltThemes';
}

Is this the correct way of doing it? Or does anyone know of the possible way to do so? Thanks in advance.

share|improve this question
    
How do you detect on which device users access your blog? –  kaiser Mar 24 '11 at 15:23
    
That is done with the help of PHP ,JS scripts and user agent string. PHP browser detection backed up by JS object detection(as user agent is unreliable and browser detection, not a good practice). –  OpenOne Mar 24 '11 at 20:29

4 Answers 4

up vote 4 down vote accepted

You could also write your own simple get_template_part alias function:
The following allows 3 subfolders for template parts that sit in a theme root folder named devices.

<?php
// STYLESHEETS
    function print_device_styles( $client = 'desktop' ) 
    {
        $client = apply_filters( 'set_theme_client', $client );
        wp_enqueue_style( $client.'-css' );
    }
    add_action( 'wp_head', 'print_device_styles', 11 );

// TEMPLATE PARTS
    function get_device_template_part( $args = array( 'file' => NULL, 'suffix' => 'default', 'client' => 'desktop', 'media' => 'screen' ) 
    {
        if ( ! $args['file'] )
            wp_die( sprintf( __('You have to specify a file name if you want to load a template part with the %1$s function.', 'textdomain', '<pre>get_device_template_part()</pre>' );

        $template_path = user_trailingslashit( get_stylesheet_directory().'/devices/templates-'.$args['client'] );
        $ui_path = user_trailingslashit( get_stylesheet_directory().'/ui/css-'.$args['client'] );
        $ui_suffix = '.css'; // could be switched between '.dev.css' & '.css'

        // add styles & template directory
        if ( is_condition_mobile() ) 
        {
            $args['client'] = 'mobile';
            $args['screen'] = 'handheld';
        }
        elseif ( is_condition_tablet() )
        {
            $args['client'] = 'tablet';
            $args['screen'] = 'handheld';
        }

        // register styles
        // wp_register_style( 'mobile-css', /theme_root/ui/css-mobile/mobile.css, false 'handheld' );
        wp_register_style( $args['client'].'-css', $ui_path.$args['client'].$ui_suffix, false, $args['screen'] );

            // Requires PHP 5.3+ (for lower versions, use a plain function).
        add_filter( 'set_theme_client', function('set_theme_client') { return $args['client'];} );

            // {$template}-{$suffix}.php
        if ( file_exists( $template_path.$args['file'].'-'.$args['suffix'].'.php' ) )
        {
            require( $template_path.$args['file'].'-'.$args['suffix'].'php' );
        }
            // {$template}.php
        elseif ( file_exists( $template_path.$args['file'].'.php' ) )
        {
            require( $template_path.$args['file'].'.php' );
        }
            // {$template}-default.php
        elseif ( file_exists( $template_path.$args['file'].'-default.php' ) )
        {
            require( $template_path.$args['file'].'-default.php' );
        }
    }

// CALL THEM in a template file
// This will require a file named {$template}-{$suffix}.php from your devices folder
// based on your conditional functions that detect your devices
// If not found, it will search for a file named {$template}.php
// and if it wasn't found it will search for a file named {$template}-default.php
    get_device_template_part( array( 'file' => 'nav', 'suffix' => 'main' ) );
?>


Feel free to add your conditional device detection to: https://gist.github.com/886501

share|improve this answer
    
Thanks. Additional question, Is it a good practice to use OO php for most of the code on wordpress themes? –  OpenOne Mar 25 '11 at 17:15
    
@OpenOne Yes, OOP is good practice. I have several classes in my framework, that generate my base at init. Extending is easy if i need some additions for a specific theme and i don't have to take care of writing the base functionality again and again (re-useability). Also classes are easier portable and keep your namespace clean. I use public functions only for template tags. And most template tags do nothing than calling class functions. –  kaiser Mar 26 '11 at 17:43
    
Thanks. I am thinking about extending the current objects for devices(desktop/mobile) and preferences(HTML4/5) document. I would like to use classes to output everything. The result looks very clean, but am not sure if i am making it too complex(for the user). –  OpenOne Mar 27 '11 at 3:57
    
@OpenOne Take a look at this: sencha.com/products/touch - it's free for developers and looks pretty good. If you want me to take a look i'll give you my email and you can send it to me. –  kaiser Mar 27 '11 at 9:59

Have you tried hooking the template_directory filter? There are also hooks for each of the individual template elements and stylesheet_directory.

share|improve this answer
    
Yes i did try that. Using add_filter on template_directory and template_directory_uri does no good, Even though get_template_directory(and uri) displays the new location. Additionally, it kinda breaks the current theme - On reloading the admin themes section, It switches back to the default theme - twentyten. –  OpenOne Mar 24 '11 at 20:20

Generally Plugins and Themes have the same possiblities. But at some points, there's a big difference. Themes come later and therefore have less power. Plus: a lot of functions only work for plugins.

What you're trying to do is modifying core-behavior. In some places core offers hooks to even completely exchange parts of it and in others it offers hooks to extend its functionality. But keep in mind that the core never really wants its behavior to be really changed when it comes to themes (see subfolders and get_template_part()). So i would step back from switching themes 'inside' a theme (it's like modding the main query) and look for some other approach:

// inside one of your template files:
do_action( 'main_nav_hook' );

// inside your functions.php
define( 'THEME_DESKTOP_DIR', user_trailingslashit( get_stylesheet_directory().'/desktop' ) );
define( 'THEME_MOBILE_DIR',  user_trailingslashit( get_stylesheet_directory().'/mobile' ) );
define( 'THEME_TABLET_DIR', user_trailingslashit( get_stylesheet_directory().'/tablett' ) );

function add_main_nav_desktop()
{
    // do stuff
    require_once( THEME_DESKTOP_DIR.'template_nav.php' );
}
function add_main_nav_mobile()
{
    // do stuff
    require_once( THEME_MOBILE_DIR.'template_nav.php' );
}
function add_main_nav_tablett()
{
    // do stuff
    require_once( THEME_TABLET_DIR.'template_nav.php' );
}

// Hook the actions
if ( is_condition_mobile() )
{
    add_action( 'main_nav_hook', 'add_main_nav_mobile' );
}
elseif ( is_condition_tablet() )
{
    add_action( 'main_nav_hook', 'add_main_nav_tablet' );
}
else
{
    add_action( 'main_nav_hook', 'add_main_nav_desktop' );
}

This is a really simple and basic approach, but it's more likely to work.

share|improve this answer
    
Actually My previous approach was similar to this, doing some includes based on devices. But no Browser/object detection method is perfect, which presents us the risk - no output. Also is there a near complete, well maintained, open, device information database out there? –  OpenOne Mar 27 '11 at 4:05

I found out that add_filter('template', ...) and add_filter('stylesheet', ...) must be called at the same time for it to work... at least in my case.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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