I need a way to change the themes "Live Preview" url within the Appearance->Themes page? I want the themes thumbnails to link to a demo site showcasing the theme and not open the customizer. I looked into the code some but I am not seeing much for a solution, but was wondering if someone else has a trick for this. Thanks

3 Answers 3


External Live Previews For Themes

The Live Preview buttons, on the /wp-admin/themes.php page, are generated from the tmpl-theme micro template:

<script id="tmpl-wpse" type="text/template">


        <div class="theme-actions">

        <# if ( data.active ) { #>
                <# if ( data.actions.customize ) { #>
                        <a class="button button-primary customize load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Customize' ); ?></a>
                <# } #>
        <# } else { #>
                <a class="button button-secondary activate" href="{{{ data.actions.activate }}}"><?php _e( 'Activate' ); ?></a>
                <a class="button button-primary load-customize hide-if-no-customize" href="{{{ data.actions.customize }}}"><?php _e( 'Live Preview' ); ?></a>
        <# } #>



We can modify the template data via the wp_prepare_themes_for_js filter.

Here's an example:

 * External Live Previews
add_filter( 'wp_prepare_themes_for_js', function(  $prepared_themes )
    // Edit this to your needs:

    $externals = [ 
        'twentysixteen' => 'http://foo.tld/demo/twentysixteen/', 
        'twentyfifteen' => 'http://bar.tld/demo/twentyfifteen/' 

    foreach( $externals as $slug => $url )
        if( isset( $prepared_themes[$slug]['actions']['customize'] ) )
            $prepared_themes[$slug]['actions']['customize'] = $url;

    return $prepared_themes;
} );

But this will not work as expected, because of the load-customize class, that will trigger a click event and open up an iframe overlay with:

$('#wpbody').on( 'click', '.load-customize', function( event ) {

    // Store a reference to the link that opened the Customizer.
    Loader.link = $(this);
    // Load the theme.
    Loader.open( Loader.link.attr('href') );

When we click on the Live Preview button, with an external url, it will trigger an error like:

Uncaught SecurityError: Failed to execute 'pushState' on 'History': A history state object with URL 'http://foo.tld/demo/twentysixteen/' cannot be created in a document with origin 'http://example.tld' and URL 'http://example.tld/wp-admin/themes.php'.

We could prevent this, by double clicking (not really a reliable option) or by removing the load-customize class for the external preview links. Here's one such hack:

 * Remove the .load-customize class from buttons with external links
add_action( 'admin_print_styles-themes.php', function()
{ ?>
        jQuery(document).ready( function($) {
            $('.load-customize').each( function( index ){
                if( this.host !== window.location.host )
                    $( this ).removeClass( 'load-customize' );
            } );
    </script> <?php
} );

where I got the this.host idea from @daved here.

Another more drastic approach would be to override the tmpl-theme template.

  • Sorry it has taken awhile to get back to you. The later portion of your code (removing the load-customize class for the external preview links) is not working right. I am working within the wp-contents/mu-plugins folder (multisite setup). Nothing happens when I add that snippet...meaning when I click the preview link I still get the same error that was created by the first snippet you offered. Should the action be 'admin_print_scripts' as your snippet is not printing the script. I tried 'admin_print_scripts' but then I get the 'jQuery is not defined' error, but the snippet is printed. Mar 17, 2016 at 12:18
  • I got it to work by enqueuing the js and adding your snippet in the external .js file. However, I also need the same thing to happen for all the 'Live Preview' links such as when you click the 'View Details' button it also gives you the option to 'Live Preview' from the popup window. Another place is the theme switching within the Customizer. Thanks again for your help. Mar 17, 2016 at 14:04
  • Glad to hear that worked, I only tested this on a single install, where it worked also for the overlay (pop-up). Regarding the Customizer you might try to override the tmpl-customize-control-theme-content micro template, maybe it's even possible to extend WP_Customize_Theme_Control to your custom needs? or play with the attribute_escape filter ;-) @DavidLabbe
    – birgire
    Mar 17, 2016 at 17:23
  • How did you go with this @DavidLabbe?
    – Tim Malone
    Jul 6, 2016 at 3:58

Wordpress seems to call wp_customize_url to get the theme preview URL, and there's not much there in the way of filters that you can hook into (https://developer.wordpress.org/reference/functions/wp_customize_url/). You could potentially hook into the admin_url filter to make changes - but returning a different URL when customize.php is sent through will obviously affect every instance of the customizer, not just the Live Preview function. If this doesn't concern you, then this could be what you need:

add_filter("admin_url", "my_live_preview", 10, 3);
function my_live_preview($url, $path, $blog_id){
  if($path == "customize.php"){ $url = "http://offsitethemepreviewurl.com"; }
  return $url;

This $url will then be appended by ?theme=name-of-theme which would allow you to determine at that page what theme is being requested.

This may or may not suit.

If it doesn't, I think you're left with some front-end JavaScript to change the URL. You'll need to enqueue a JavaScript file in the admin using admin_enqueue_scripts (see https://codex.wordpress.org/Plugin_API/Action_Reference/admin_enqueue_scripts for help), then reference the Live Preview link:

jQuery(".theme-browser .theme[aria-describedby*='twentysixteen'] .button.load-customize")
  .attr("href", "http://offsitethemepreviewurl.com/");

This should change the Load Preview link for the twentysixteen theme to http://offsitethemepreviewurl.com.

I haven't tested either of these solutions... but I think they'll work :)

  • 1
    You might want to add a .removeClass( 'load-customize') to the jQuery chain, to prevent a Javascript pushState security error, regarding external urls.
    – birgire
    Mar 12, 2016 at 13:38

If you are in wp customizer, here is how you can change the current preview URL via Javascript:

Try this one when you plan to change the current URL from controls panel: wp.customize.previewer.previewUrl( url )

or try this one while you intend to change the URL from preview frame: wp.customize.preview.send( "url", url )

Moreover, here is how to get the current preview URL from the controls panel: wp.customize.previewer.previewUrl()

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.