3

I've added a custom field into my media attachments:

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 )
    );

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

Which is fine and dandy, but now I'd like to add Colorpicker ( I understand it is deprecated ) to the above field. Unfortunately, jQuery doesn't seem to have an effect as the Media Library is dynamic. I've tried handlers but I can't seem to catch the input to even place a generic val() into it.

I believe once I understand how to modify the field I should be able to grasp then how to attach Colorpicker to the field.

How can I use JS or jQuery to modify the field above on an attachment to attachment basis in the Media Library?

1 Answer 1

3

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 );
8
  • Did you get a working demo? I keep getting an error like jQuery isn't included on the attachment_fields_to_edit filter for the jquery snippet. jQuery(...).myColorPicker is not a function to be precise.
    – Howdy_McGee
    Commented Jun 30, 2015 at 18:29
  • Yes, had a working demo, I suppose try putting the jquery snippet in a ready clause (will update answer) - but anyway I'm getting a strange "cannot call methods on iris prior to initialization" bug occasionally so answer seems doubtful...
    – bonger
    Commented Jun 30, 2015 at 18:37
  • I'm messing around with it as your code is definitely helpful, gives me something to work with. It may ( or may not ) be easier to work with the 'input' => 'html', parameter to the array, pass the entire input markup and script into it most likely. Then you can easily ( $form_fields['text_color']['html'] = "<script>etc."
    – Howdy_McGee
    Commented Jun 30, 2015 at 18:40
  • I see, it was the conditional in the admin_print_footer_scripts that was killing me. I'm running this both in a post type and on a wp_editor() in a metabox if that makes a difference. Thanks for you help!
    – Howdy_McGee
    Commented Jun 30, 2015 at 19:01
  • 1
    I tracked down the "iris" bug (which was after all reproducible) and opened a ticket for it on trac core.trac.wordpress.org/ticket/32856, I'll update the answer with the workaround...
    – bonger
    Commented Jul 1, 2015 at 14:46

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.