I've noticed 3 scenarios relating to links in the customizer preview frame.

1) Clicking a link to an external url does nothing. This is good.

2) Clicking a link to a same origin/domain url results in refreshing the customizer preview with that url's content. Again, good.

3) Clicking on a link with a hash or anchor tag refreshes the customizer preview and whether or not you happen to be customizing the site's home page, that is where you end up unless you refresh the browser to get back to customizing the page/post you were originally at.

When wanting to style a mobile menu for example, the classic "hamburger" element uses an anchor tag that triggers this undesired refresh. I want to be able to reveal the menu just as the click event would on the published front-end and then use my nifty customizer tools to style my menu that my plugin allows for.

Other elements also come in to play, such as icons, tabs and other subtle front-end click animations that "reveal" additional content on the page.

For example, this could be a theme's code that would exploit this behavior:

<a href="#" class="show-me">
    <i class="some-nifty-icon-gizmo-that-animates-into-view"></i>

Is there a way to unbind this baked-in click event listener on a per element basis?

I've tried the usual event.preventDefault and event.stopPropagation to get around this but no luck so far. I've also tried the jQuery "off" and "unbind" methods but can't seem to nail it.

It looks like it's coming from /wp-includes/js/customize-preview.min.js and all anchor tag click events bubble up to the body element.

A way around this at the moment is to manipulate the DOM via browser inspector to add whatever class or css is needed that the original click event would have completed.

Edit: Please, this is not about theme coding standards and semantics, the examples provided above are just that, examples of which any and all plugins could run into. While I necessarily wouldn't use an anchor tag for a menu button, we (as software developers) still have to plan for these things.

1 Answer 1


Update: The fix here has been incorporated into WordPress Core trunk for the upcoming 4.5 release (now in alpha). See r36371.

I think the problem with the unbinding of the event handler is that it is being done too early. Try doing it at the preview-ready Customizer event. For example, enqueue the following JS in your Customizer preview (with customize-preview as a script dependeny) which short-circuits the click.preview logic if the link clicked has an in-page link target or if it uses the javascript: protocol:

if ( /\/customize\.php$/.test( window.location.pathname ) ) {
    wp.customize.bind( 'preview-ready', function() {
        var body = $( 'body' );
        body.off( 'click.preview' );
        body.on( 'click.preview', 'a[href]', function( event ) {
            var link = $( this );
            if ( /^(#|javascript:)/.test( link.attr( 'href' ) ) ) {
            wp.customize.preview.send( 'scroll', 0 );
            wp.customize.preview.send( 'url', link.prop( 'href' ) );
    } );

The inclusion of the href type really should be part of Core and I'll add it to my todo list to get that committed as part of the 4.5 cycle.

Note the test for customize.php is to ensure that transactions with the natural URL being used as the Customizer preview iframe URL hasn't been implemented yet, because that change will mean changes to the click.preview logic.

  • Thank you Weston, tested with success! Another one of those forehead slaps, I already had another script being enqueued upon the customize-preview dependency and can't even fathom why it didn't occur to me to throw my unbind method over there. But I'm glad I learned this lesson as your method of first testing of the inclusion of customize.php in the parent url against the preview iframe url makes so much more sense If I understand the logic is to protect against unnecessarily executing this method in the future when things change. Commented Jan 20, 2016 at 9:13
  • In my answer I posted a much more simple code that is working, just if you want to try.
    – cybmeta
    Commented Jan 20, 2016 at 10:49
  • @PhilipIngram This issue is now fixed in Core: core.trac.wordpress.org/changeset/36371 Commented Jan 21, 2016 at 6:09
  • Great news!!! Up voted for the update!!! Definitely I'm going to delete my answer.
    – cybmeta
    Commented Jan 21, 2016 at 6:18

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.