3

I've been searching for a couple of days now so I'll keep my question as short as possible to get out of your ways.

What I'm trying to do should be very basic with jQuery (append) I guess but for some strange reason I can't get it done while adding .js to the backend. Also this custom hack is just temporary, until the Gutenberg editor releases into the core and all this will not be needed anymore.

Q:

Simply add a "Hello world!" string to the Image Details modal where the red text on the screenshot(s) below is.

--

Screenshots below is a quick summit from what I'm doing.

enter image description here

This Image Details modal pops up when you press Edit image on a single image that is not part of your Media Library and doesn't have a Post_ID. Placeholder (URL) images for example.

Screenshot nr. 2. This Image Details modal is what you get when you click Edit image on a image that is added to a post the Media Library before. The beautiful Replace button below the preview thumbnail is poking my eyes, I want him, he's my Chuck Norris!

enter image description here

4

Here's an alternative technique to manipulating the template. I adapted the solution below from this post.

In the approach below, the print_media_templates hook, which is triggered at the bottom of wp-includes/media-template.php, is used to output some JavaScript that removes the default image details underscores template (<script type="text/html" id="tmpl-image-details">) and replaces it with a duplicated version which we can modify to suit our needs.

I've added Hello, world! in the modified template, and the Replace button too (more on that in a second). One of the drawbacks of this approach is that if/when the WordPress core is updated, our forked template won't reflect any changes to this particular media template.

Another problem here is that simply adding the button is not enough. You can activate the button by removing the HTML comments (<!-- and -->) that I wrapped it in if you want to proceed anyway. Using the standard Replace button on an image that is not part of the media library will trigger an error in the console, but seems to work never-the-less. Ideally, a custom button should be created or the JS controller that handles the Replace button's functionality should be implemented (which I'm not sure how to do).

add_action( 'print_media_templates', 'wpse_print_media_templates' );
function wpse_print_media_templates() { ?>
    <script>
        // Idea via http://unsalkorkmaz.com/wp3-5-media-gallery-edit-modal-change-captions-to-title/
        jQuery( document ).ready( function( $ ){
            jQuery( "script#tmpl-image-details:first" ).remove();
        });
    </script>

    <script type="text/html" id="tmpl-image-details">
        <div class="media-embed">
            <div class="embed-media-settings">
                <div class="column-image">
                    <div class="image">
                        <img src="{{ data.model.url }}" draggable="false" alt="" />

                        <# if ( data.attachment && window.imageEdit ) { #>
                            <div class="actions">
                                <input type="button" class="edit-attachment button" value="<?php esc_attr_e( 'Edit Original' ); ?>" />
                                <input type="button" class="replace-attachment button" value="<?php esc_attr_e( 'Replace' ); ?>" />
                            </div>
                        <# } else if ( ! data.attachment && window.imageEdit ) { #>
                            <!--
                                <div class="actions">
                                    <input type="button" class="replace-attachment button my-theme"  value="<?php esc_attr_e( 'Replace' ); ?>" />
                                </div>
                             -->
                        <# } #>
                        <h1>Hello, world!</h1>
                    </div>
                </div>
                <div class="column-settings">
                    <?php
                    /** This filter is documented in wp-admin/includes/media.php */
                    if ( ! apply_filters( 'disable_captions', '' ) ) : ?>
                        <label class="setting caption">
                            <span><?php _e('Caption'); ?></span>
                            <textarea data-setting="caption">{{ data.model.caption }}</textarea>
                        </label>
                    <?php endif; ?>

                    <label class="setting alt-text">
                        <span><?php _e('Alternative Text'); ?></span>
                        <input type="text" data-setting="alt" value="{{ data.model.alt }}" />
                    </label>

                    <h2><?php _e( 'Display Settings' ); ?></h2>
                    <div class="setting align">
                        <span><?php _e('Align'); ?></span>
                        <div class="button-group button-large" data-setting="align">
                            <button class="button" value="left">
                                <?php esc_html_e( 'Left' ); ?>
                            </button>
                            <button class="button" value="center">
                                <?php esc_html_e( 'Center' ); ?>
                            </button>
                            <button class="button" value="right">
                                <?php esc_html_e( 'Right' ); ?>
                            </button>
                            <button class="button active" value="none">
                                <?php esc_html_e( 'None' ); ?>
                            </button>
                        </div>
                    </div>

                    <# if ( data.attachment ) { #>
                        <# if ( 'undefined' !== typeof data.attachment.sizes ) { #>
                            <label class="setting size">
                                <span><?php _e('Size'); ?></span>
                                <select class="size" name="size"
                                    data-setting="size"
                                    <# if ( data.userSettings ) { #>
                                        data-user-setting="imgsize"
                                    <# } #>>
                                    <?php
                                    /** This filter is documented in wp-admin/includes/media.php */
                                    $sizes = apply_filters( 'image_size_names_choose', array(
                                        'thumbnail' => __('Thumbnail'),
                                        'medium'    => __('Medium'),
                                        'large'     => __('Large'),
                                        'full'      => __('Full Size'),
                                    ) );

                                    foreach ( $sizes as $value => $name ) : ?>
                                        <#
                                        var size = data.sizes['<?php echo esc_js( $value ); ?>'];
                                        if ( size ) { #>
                                            <option value="<?php echo esc_attr( $value ); ?>">
                                                <?php echo esc_html( $name ); ?> &ndash; {{ size.width }} &times; {{ size.height }}
                                            </option>
                                        <# } #>
                                    <?php endforeach; ?>
                                    <option value="<?php echo esc_attr( 'custom' ); ?>">
                                        <?php _e( 'Custom Size' ); ?>
                                    </option>
                                </select>
                            </label>
                        <# } #>
                            <div class="custom-size<# if ( data.model.size !== 'custom' ) { #> hidden<# } #>">
                                <label><span><?php _e( 'Width' ); ?> <small>(px)</small></span> <input data-setting="customWidth" type="number" step="1" value="{{ data.model.customWidth }}" /></label><span class="sep">&times;</span><label><span><?php _e( 'Height' ); ?> <small>(px)</small></span><input data-setting="customHeight" type="number" step="1" value="{{ data.model.customHeight }}" /></label>
                            </div>
                    <# } #>

                    <div class="setting link-to">
                        <span><?php _e('Link To'); ?></span>
                        <select data-setting="link">
                        <# if ( data.attachment ) { #>
                            <option value="file">
                                <?php esc_html_e( 'Media File' ); ?>
                            </option>
                            <option value="post">
                                <?php esc_html_e( 'Attachment Page' ); ?>
                            </option>
                        <# } else { #>
                            <option value="file">
                                <?php esc_html_e( 'Image URL' ); ?>
                            </option>
                        <# } #>
                            <option value="custom">
                                <?php esc_html_e( 'Custom URL' ); ?>
                            </option>
                            <option value="none">
                                <?php esc_html_e( 'None' ); ?>
                            </option>
                        </select>
                        <input type="text" class="link-to-custom" data-setting="linkUrl" />
                    </div>
                    <div class="advanced-section">
                        <h2><button type="button" class="button-link advanced-toggle"><?php _e( 'Advanced Options' ); ?></button></h2>
                        <div class="advanced-settings hidden">
                            <div class="advanced-image">
                                <label class="setting title-text">
                                    <span><?php _e('Image Title Attribute'); ?></span>
                                    <input type="text" data-setting="title" value="{{ data.model.title }}" />
                                </label>
                                <label class="setting extra-classes">
                                    <span><?php _e('Image CSS Class'); ?></span>
                                    <input type="text" data-setting="extraClasses" value="{{ data.model.extraClasses }}" />
                                </label>
                            </div>
                            <div class="advanced-link">
                                <div class="setting link-target">
                                    <label><input type="checkbox" data-setting="linkTargetBlank" value="_blank" <# if ( data.model.linkTargetBlank ) { #>checked="checked"<# } #>><?php _e( 'Open link in a new tab' ); ?></label>
                                </div>
                                <label class="setting link-rel">
                                    <span><?php _e('Link Rel'); ?></span>
                                    <input type="text" data-setting="linkRel" value="{{ data.model.linkClassName }}" />
                                </label>
                                <label class="setting link-class-name">
                                    <span><?php _e('Link CSS Class'); ?></span>
                                    <input type="text" data-setting="linkClassName" value="{{ data.model.linkClassName }}" />
                                </label>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </script>       
    <?php
}
  • 1
    Thanks, this is a better way of making changes. I'll submit the button conditional part in this code to the WordPress core because I feel this check should be native. Replacing an image for another images should always be possible - not only when an image if part of the library. – Jack Ottermans May 26 '17 at 10:11
3

The beautiful Replace button below the preview thumbnail is poking my eyes, I want him, he's my Chuck Norris!

"Chuck Norris doesn’t program with a keyboard. He stares the computer down until it does what he wants" (src)

For those of us who need the keyboard to program, then there's a way to inject the button after the .image img selector if it's missing:

replace

where we extend the ImageDetails media view and override the resetFocus() method:

add_action( 'print_media_templates', function() { ?> 
   <script>
    jQuery(document).ready( function( $ ) {
        wp.media.view.ImageDetails = wp.media.view.ImageDetails.extend({
            resetFocus: function() {
               this.$( '.link-to-custom' ).blur();
               this.$( '.embed-media-settings' ).scrollTop( 0 );
               // Inject Replace button if it's missing:
               if( ! this.$('.replace-attachment' ).length ) {
                   this.$( '<div class="actions"> <input type="button"  class="replace-attachment button my-theme" value="Replace" /></div>' ).insertAfter('.image img');
               }
            }
        });
    }); 
   </script> 
<?php } );

We could also override the initialize() method and hook into the post-render event, like in the question here by @Druzion.

Here's a working and modified version from that question:

add_action( 'print_media_templates', function() { ?> 
   <script>
    jQuery(document).ready( function( $ ) {
        wp.media.view.ImageDetails = wp.media.view.ImageDetails.extend({
            initialize: function() {
                this.on( 'post-render', this.add_settings );
            },
            add_settings: function() {
                // Inject Replace button if it's missing:
                if( ! this.$('.replace-attachment' ).length ) {
                    this.$('.image').append( '<div class="actions"><input type="button" class="replace-attachment button my-theme" value="Replace" /></div>');
                }
            }
        });
    }) 
   </script> 
<?php } );

Note the this.$ usage instead of $.

Similarly we could override the render() method, like I played with here.

Another approach is to replace parts of the default templates, using output buffering and substring replacements, as @bonger did here.

Also note the javascript error, from the Replace button usage, mentioned by @Dave Romsey

0

I'm so ashamed for doing this technique but if nobody (online) wants to help in three days asking all over the place you become somewhat desperate to find solutions. 🤢

function hijack_caption_off_filter() {

    $shame = '<input type="button" class="replace-attachment button my-theme" value="Replace" />';

    echo $shame;

}
add_filter( 'disable_captions', 'hijack_caption_off_filter' );

I want to mention that people should not do stuff like this. What I did here is, I hijacked a caption boolean filter [True/False] and echoed my button through it just to get him to show up on the media_template.

  • 1
    WP v3.5+ Media is notoriously difficult to work with, in part due to lack of docs. It's more likely that folks aren't sure how to help with your question, and not that they don't want to. The trouble with adding the replace button through this method (aside from the hackyness which you've acknowledged) or others, seems to be that images from external URLs are not proper attachments, e.g. data.attachment, so although the functionality seems to work, it generates an error in the console. So, in addition to adding the button, the media controller's (?) behavior needs to be overridden as well. – Dave Romsey May 25 '17 at 23:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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