Contenu principal

WP 3.5 et les champs personnalisés de la fenêtre modale des médias

WordPress 3.5 nous a été livré il y a à peu près deux semaines avec, entre autres, une toute nouvelle fenêtre des médias qui avait bien besoin d’un coup de jeune. Bien entendu, de tels gros changements impliquent également des changements pour nous, développeurs, sans parler… des obligatoires bugs de jeunesse.

Autant cette nouvelle fenêtre modale est une bonne chose pour l’utilisateur selon moi, autant pour les développeurs elle représente un peu le 21-12-2012, mais le vrai, celui qui te pète à la gueule, qui tache et qui engendre des veuves (j’en fait pas trop, c’est bon ?). Bon, je ne vais pas m’étendre sur tous les problèmes engendrés, parmi lesquels on peut compter quelques petites incohérences ergonomiques, bugs CSS, impossibilité de modifier les champs d’origine, JS et ajax à profusion (avec les bugs qui vont avec), manque cruel de hooks, etc (mention spéciale pour l’introduction d’un smarty-like).

Bon, je vais arrêter de faire du mauvais esprit et plutôt aborder le sujet du jour : les champs personnalisés que l’on voudrait ajouter avec nos plugins.

Le premier point important est que tout est fait en ajax, donc si par exemple vous avez fait ceci pour des raisons d’optimisation, vous êtes foutu ^^ :

1234

if ( is_admin() && (!defined('DOING_AJAX') || !DOING_AJAX) ) {
	add_filter('attachment_fields_to_edit', 'my_plugin_attachment_fields_to_edit', 11, 2);
	// ...
}

Maintenant il y a deux méthodes pour séparer les champs que l’on va ajouter dans la fenêtre modale et ceux de la page normale d’édition d’un média.
La première consiste à utiliser DOING_AJAX :

12345

if ( is_admin() && defined('DOING_AJAX') && DOING_AJAX ) {
	// Fenêtre modale
} elseif ( is_admin() ) {
	// Page d'édition d'un média
}

La deuxième consiste à utiliser de nouveaux paramètres lors de l’ajout des champs 

010203040506070809101112

add_filter('attachment_fields_to_edit', 'my_plugin_attachment_fields_to_edit', 11, 2);
function my_plugin_attachment_fields_to_edit($form_fields, $post) {

	$form_fields['my-plugin'] = array(
		'label' => __('Salut'),
		'input' => 'html',
		'html' => __("Un champs perso"),
		'show_in_edit' => false,
		'show_in_modal' => true,
	);
	return $form_fields;
}

Ces deux nouveaux paramètres sont show_in_edit et show_in_modal, et sont à true par défaut.

Bon, ça c’était le tour de chauffe, juste une nouvelle habitude à prendre :)

Là on va s’attaquer à un peu plus lourd puisqu’il s’agit d’un bug, qui sera probablement réparé dans la 3.5.1, mais en attendant il faut faire avec.

Situation :
Vous ajoutez par exemple une case à cocher pour modifier le code html envoyé à l’éditeur (comme ajouter un shortcode).
Changement de comportement :
Cette case à cocher doit entrainer une action, comme l’enregistrement d’une meta, que vous ajoutez en utilisant le filtre attachment_fields_to_save.
Le changement s’effectue dans la manière dont est lancé ce hook : il n’est plus déclenché au moment où on clique sur « Insérer dans l’article » mais à chaque fois que l’on coche/décoche la case (via ajax).
Le problème :
Lorsque l’on coche la case, les infos sont bien envoyées.

action                       save-attachment-compat
id                           325
attachments[325][my-plugin]  1
nonce                        g5h684d87
post_id                      342

Mais lorsque l’on la décoche, l’info se perd, la valeur « décochée » n’est pas envoyée.

action                       save-attachment-compat
id                           325
nonce                        g5h684d87
post_id                      342

Dès lors, l’ajax répond par un échec.

Après moultes tentatives avec diverses façons de faire, je n’en ai trouvé qu’une qui fonctionne au final, celle qui est mentionnée sur le trac WP (que j’ai découvert après avoir trouvé la solution u_u) : utiliser un input hidden additionnel.

Concrètement ça donne ça :

01020304050607080910111213141516171819202122232425262728

add_filter('attachment_fields_to_edit', 'my_plugin_attachment_fields_to_edit', 11, 2);
function my_plugin_attachment_fields_to_edit($form_fields, $post) {

	$html =	 '<label>'
			.'<input type="checkbox" name="attachments['.$post->ID.'][my-plugin]" value="1" /> '
			.__("Allez, fais pas l'radin")
		.'</label>'
		.'<input type="hidden" name="attachments['.$post->ID.'][my-plugin-hidden]" value="1"/>';
	
	$form_fields['my-plugin'] = array(
		'label' => __('Salut'),
		'input' => 'html',
		'html' => $html
	);
	return $form_fields;
}


add_filter('attachment_fields_to_save', 'my_plugin_attachment_fields_to_save', 10, 2);
function my_plugin_attachment_fields_to_save($post, $attachment) {

	if ( isset($attachment['my-plugin']) && $attachment['my-plugin'] )
		update_post_meta($post['ID'], '_my-plugin', 1);
	else
		delete_post_meta($post['ID'], '_my-plugin');

	return $post;
}

Pour résumer, la valeur du champs caché est toujours envoyée, et empêche l’ajax de renvoyer un échec. Au niveau de l’enregistrement de la meta, rien ne change. Au final, un petit bug tout bête qui fait perdre énormément de temps si on ne connait pas le patch provisoire.
Voilà, j’espère que ceci vous fera économiser du temps, bien que l’article arrive un peu tard par manque de temps pour me pencher sur ce problème.

Pour terminer sur une bonne note, et toujours en relation avec les médias, il est quand même à noter une meilleure prise en compte des taxonomies. Plus besoin de « vil-hacker » dans tous les sens pour avoir une vrai metabox. Enfin… jusqu’au moment où il faudra toucher à la fenêtre modale, là j’ai comme l’impression que ça va être une autre histoire :p

See ya!

[update] 27-01-2013
Bonne nouvelle. L’astuce de l’input hidden n’est plus nécessaire avec WordPress 3.5.1, l’appel ajax ne retourne plus un echec car un « menu_order » est envoyé :)