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