Modify Custom Field in Media Library using JavaScript

One way to do it (which is probably evil) is to select the control by adding a block of javascript using the tr field of $form_fields:

function set_image_data( $form_fields, $post ) {

    $form_fields['text_color'] = array(
        'label' => 'Text Color',
        'input' => 'text',
        'value' => get_post_meta( $post->ID, '_text_color', true )
    );
    ob_start();
    ?>
    <script type="text/javascript">
    jQuery('[name$="[text_color]"]').myColorPicker();
    </script>
    <?php
    $text_color_js = ob_get_clean();
    $form_fields['text_color_js'] = array(
        'tr' => $text_color_js, // Adds free-form stuff to table.
    );

    return $form_fields;
}
add_filter( 'attachment_fields_to_edit', 'set_image_data', 10, 2 );

The javascript is using a customized version of wpColorPicker that overrides the close to trigger a change event (needed since the hidden text_color field never gets/loses focus so doesn’t do it itself):

add_action( 'admin_print_footer_scripts', function () {
        ?>

        <script type="text/javascript">
        jQuery(function ($) {
            // Extend wpColorPicker to trigger change on close.
            $.widget('custom.myColorPicker', $.wp.wpColorPicker, {
                close: function () {
                    this._super();
                    if (this.initialValue !== this.element.val()) {
                        this.element.change();
                    }
                }
            });
        });
        </script>

        <?php
}, 50 );

You could optionally wrap the above in a conditional so that it only includes the script on upload but it may not fire in some cases.

if ( get_current_screen()->base == 'upload' ) {}

Then there’s standard stuff to load wp-color-picker and save the data:

add_action( 'admin_enqueue_scripts', function () {
    if ( get_current_screen()->base == 'upload' ) {
        wp_enqueue_style( 'wp-color-picker' );
        wp_enqueue_script( 'wp-color-picker' );
    }
});
add_filter( 'attachment_fields_to_save', function ( $post, $attachment ) {
    if ( isset( $attachment['text_color'] ) ) {
        update_post_meta( $post['ID'], '_text_color', $attachment['text_color'] );
    }
    return $post;
}, 10, 2 );

Update

This usage threw up a bug in wpColorPicker (see trac https://core.trac.wordpress.org/ticket/32856) in that if the color picker is left open and the Attachment Details modal is closed, an exception is thrown which puts things into a funny state. The workaround is not to call this._super(); in the (very conveniently overridden) close but to replicate the code instead, with the fix:

add_action( 'admin_print_footer_scripts', function () {

        ?>
        <script type="text/javascript">
        jQuery(function ($) {
            // Extend wpColorPicker to trigger change on close.
            $.widget('custom.myColorPicker', $.wp.wpColorPicker, {
                close: function () {
                    this.element.hide();
                    if ( this.element.iris( 'instance' ) ) {
                        this.element.iris( 'toggle' );
                    }
                    this.button.addClass( 'hidden' );
                    this.toggler.removeClass( 'wp-picker-open' );
                    $( 'body' ).off( 'click.wpcolorpicker', this.close );
                    if (this.initialValue !== this.element.val()) {
                        this.element.change();
                    }
                }
            });
        });
        </script>
        <?php

}, 50 );

Leave a Comment