How to hook in and modify the new revisions UI (3.6+)?

Let’s say I want to add some post_meta into the “new” revisions UI. I’m saving some meta on revisions only, and want to display it on this screen.

enter image description here

Normally, I’d open up wp-admin/revisions.php look for some hooks and code away. But the revisions page is all done with Backbone. I don’t know Backbone (totally willing to learn). However, I can’t find anything about how to modify existing admin Backbone views in WordPress.

Has anyone successfully modified this interface and can provide an example of how it can be done?

1
1

Unfortunately, there is no standardized best practice instituted by WordPress for hooking into Backbone templates. There have been plans suggested to bring the familiar filters and actions API to Javascript in WordPress, but there is a lack of traction in this movement. Carl Danley created a library which does just that, which is helpful if you’re trying to build/jerry-rig code in the most minute way to all you to do what you’re trying to do.

Basically, you’re trying to override what’s going on in revisions.view.Meta‘s microtemplate.

There isn’t a simple way to override the microtemplate markup itself. What I’d suggest is overriding the .template() method of any constructor that extends from revisions.view.Meta, those being revisions.view.MetaFrom and revisions.view.MetaTo. To do this, here’s some boilerplate:

add_action( 'admin_footer-revision.php', function() {
    $post = get_post();
    ?>
    <script id="tmpl-revisions-meta-override" type="text/html">
        <# if ( ! _.isUndefined( data.attributes ) ) { #>
            <div class="diff-title">
                <# if ( 'from' === data.type ) { #>
                    <strong><?php _ex( 'From:', 'Followed by post revision info' ); ?></strong>
                <# } else if ( 'to' === data.type ) { #>
                    <strong><?php _ex( 'To:', 'Followed by post revision info' ); ?></strong>
                <# } #>
                <div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>">
                    {{{ data.attributes.author.avatar }}}
                    <div class="author-info">
                    <# if ( data.attributes.autosave ) { #>
                        <span class="byline"><?php printf( __( 'Autosave by %s' ),
                            '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
                    <# } else if ( data.attributes.current ) { #>
                        <span class="byline"><?php printf( __( 'Current Revision by %s' ),
                            '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
                    <# } else { #>
                        <span class="byline"><?php printf( __( 'Revision by %s' ),
                            '<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
                    <# } #>
                        <span class="time-ago">{{ data.attributes.timeAgo }}</span>
                        <span class="date">({{ data.attributes.dateShort }})</span>
                    </div>
                    Your custom text here
                <# if ( 'to' === data.type && data.attributes.restoreUrl ) { #>
                    <input  <?php if ( wp_check_post_lock( $post->ID ) ) { ?>
                        disabled="disabled"
                    <?php } else { ?>
                        <# if ( data.attributes.current ) { #>
                            disabled="disabled"
                        <# } #>
                    <?php } ?>
                    <# if ( data.attributes.autosave ) { #>
                        type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Autosave' ); ?>" />
                    <# } else { #>
                        type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Revision' ); ?>" />
                    <# } #>
                <# } #>
            </div>
        <# if ( 'tooltip' === data.type ) { #>
            <div class="revisions-tooltip-arrow"><span></span></div>
        <# } #>
    <# } #>
    </script>
    <script>
    (function($) {
        wp.revisions.view.MetaFrom.prototype.template = wp.template('revisions-meta-override');
        wp.revisions.view.MetaTo.prototype.template = wp.template('revisions-meta-override');
    })(jQuery);
    </script>
    <?php
} );

And to explain that. We’re hooking into the footer of the revisions admin page, so we’re guaranteed that the constructors revisions.view.MetaFrom and revisions.view.MetaTo have been defined, but before the revisions module bootstrapper has been triggered. This is important, because we want to modify the constructors before they are put to use. I copied the contents of revisions.view.Meta‘s microtemplate verbatim into an overridden version of the template #tmpl-revisions-meta-override, but notice I’ve added Your custom text here in the template where it looks like you want your custom text. Then, I override both constructor’s template() method, using the modified microtemplate’s ID as a reference.

Voila. Now, it depends what you want to do with your custom text. If you want to plop some text in there, go for it. If you want to output text specific to that revision, you’ll want to check out Carl Danley’s aforementioned library, and trigger a filter hook passing along data so that you can output something specific to the data at hand.

I know, this is insane. But this is where we’re at with overriding Javascript in WordPress Backbone templates. We should be having discussions about how we can bake in customizability like you’re asking for into core, but we’re not because there’s a lack of interest/momentum. Feel free to spark conversation at our weekly WordPress core developer chats. I will be there.

Leave a Comment