Il y a quelques mois, Bruno Bichet nous montrait sa méthode pour créer simplement des boutons dans l’éditeur TinyMCE. Une méthode efficace 100% CSS. Ma méthode n’est pas une alternative à celle de Bruno mais un complément car le but n’est pas le même.
Pour cela, j’en passerais par deux exemples différents, visant à styler les liens pointant vers des fichiers média.
Styler automatiquement les liens vers les pdf, fichiers Excel, etc.
En CSS pur c’est faisable facilement :
1
a[href$=".pdf"] { ... }
Mais bien sûr certains navigateurs (dont je ne donnerais pas le nom…) ne connaissent pas ces sélecteurs CSS.
Et si à la place, une classe CSS était ajoutée automatiquement?
C’est parti, il faut d’abord trouver le hook adéquat, il s’agit de « media_send_to_editor », qui permet de traiter un lien avant de l’envoyer dans l’éditeur. Celui-ci ne concerne pas les images.
123456
add_filter('media_send_to_editor', 'sf_add_media_type_class', 10, 3);
function sf_add_media_type_class($html, $send_id, $attachment) {
// Code
}
D’abord on doit vérifier la présence d’une url, ensuite on pourra retourner le lien modifié.
123456789
add_filter('media_send_to_editor', 'sf_add_media_type_class', 10, 3);
function sf_add_media_type_class($html, $send_id, $attachment) {
if ( !empty($attachment['url']) ) {
// Code
}
return $html;
}
En résumé je reprends le code d’origine de WordPress et je le modifie pour ajouter les classes nécessaires.
Le script va générer 2 classes : une classe « file_link » générique, et une autre sous la forme « file_link_pdf » selon le type de contenu.
Pour cela on défini d’abord les types de fichier que l’on veut voir apparaitre dans un array, et si l’extension correspond on ajoute la classe.
Ce qui donne au final :
0102030405060708091011121314151617
add_filter('media_send_to_editor', 'sf_add_media_type_class', 10, 3);
function sf_add_media_type_class($html, $send_id, $attachment) {
if ( !empty($attachment['url']) ) {
$types = array( 'doc', 'docx', 'xls', 'xlsx', 'zip', 'ppt', 'mov', 'pdf' );
$ext = end(explode('.', $attachment['url']));
$html = $attachment['post_title'];
$rel = '';
if ( strpos($attachment['url'], 'attachment_id') || get_attachment_link($send_id) == $attachment['url'] )
$rel = ' rel="attachment wp-att-' . esc_attr($send_id) . '"';
$class = in_array($ext, $types) ? ' file_link_'.$ext : '';
$html = '<a class="file_link'.$class.'">'.$html.'</a>';
}
return $html;
}
Et voilà, à chaque fois qu’un lien vers un pdf, un zip ou autre sera envoyé vers l’éditeur, il sera affublé de nos classes CSS, il ne vous restera qu’à faire votre style CSS :)
Action supplémentaire de l’utilisateur : zéro.
Ajouter une classe pour une lightbox
Dans la même veine on pourrait détecter que le lien mène vers une image afin d’ajouter une classe « thickbox » par exemple, dans le but d’utiliser une lightbox.
Là nous allons opérer différemment et proposer à l’utilisateur une case à cocher afin qu’il choisisse lui-même s’il veut utiliser une lightbox ou pas. Ça nous permettra de voir comment ajouter une case à cocher ou tout autre input dans la fenêtre media, et récupérer les données par la suite.
En gros, on utiliser une post_meta.
D’abord on utilise le hook « attachment_fields_to_edit » pour ajouter la boite à cocher. Ce hook concerne aussi bien les images que les autres types de média, il faut donc filtrer le media selon son « post_mime_type ».
Nota : dans add_filter( )
j’utilise une priorité 11 pour que notre case à cocher apparaisse après les champs déjà présents (alignement, taille de l’image). Pour la faire apparaitre avant, priorité 10.
123456789
add_filter("attachment_fields_to_edit", "thickbox_attachment_fields_to_edit", 11, 2);
function thickbox_attachment_fields_to_edit($form_fields, $post) {
if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
// Code
}
return $form_fields;
}
Nous allons utiliser une post_meta appelée « _thick », nous la récupérons avec un get_post_meta( )
pour savoir si la case à cocher doit être cochée ou non, et nous créons nos label et input.
Résultat :
01020304050607080910111213
add_filter("attachment_fields_to_edit", "thickbox_attachment_fields_to_edit", 11, 2);
function thickbox_attachment_fields_to_edit($form_fields, $post) {
if ( substr($post->post_mime_type, 0, 5) == 'image' ) {
$thick = get_post_meta($post->ID, '_thick', true);
$html = '<label style="font-weight:bold">'
.'<input type="checkbox" name="attachments[' . $post->ID . '][thick]" value="1" '.(isset($thick) && $thick ? " checked='checked'" : "").'/> '
.__("Open this media in the lightbox")
.'</label>';
$form_fields["thickbox"] = array( "label" => __("Lightbox"), "input" => "html", "html" => $html );
}
return $form_fields;
}
Phase 2 : l’enregistrement. Cette fois c’est le filtre « attachment_fields_to_save » qui nous intéresse pour sauver la valeur de la case à cocher.
15161718192021222324
add_filter("attachment_fields_to_save", "thickbox_attachment_fields_to_save", 10, 2);
function thickbox_attachment_fields_to_save($post, $attachment) {
if ( substr($post['post_mime_type'], 0, 5) == 'image' ) {
if( isset($attachment['thick']) && (int) $attachment['thick'] )
update_post_meta($post['ID'], '_thick', (int) $attachment['thick']);
else
delete_post_meta($post['ID'], '_thick');
}
return $post;
}
Dernière étape, ajouter la classe CSS au lien. Le filtre « image_send_to_editor » nous sera utile, et ne s’applique qu’aux images justement. Comme dans le premier exemple, je récupère la fonction d’origine de WordPress et je la modifie pour ajouter la classe CSS. On devra récupérer la valeur de la case à cocher aussi avec get_post_meta( )
encore.
Nota : j’ajoute également l’attribut title au lien, car les lightbox l’utilisent souvent pour donner un titre à la fenêtre.
262728293031323334353637383940
add_filter( 'image_send_to_editor', 'thickbox_get_image_send_to_editor', 10, 8 );
function thickbox_get_image_send_to_editor($html, $id, $caption, $title, $align, $url='', $size='medium', $alt = '') {
$html = get_image_tag($id, $alt, $title, $align, $size);
$thick = get_post_meta($id, '_thick', true);
$rel = $rel ? ' rel="attachment wp-att-' . esc_attr($id).'"' : '';
$class = isset($thick) && (int) $thick ? ' class="thickbox"' : '';
$class .= isset($title) && $title ? ' title="'.esc_attr($title).'"' : '';
if ( $url )
$html = '<a>'.$html.'</a>';
return $html;
}
Voilà, terminé.
See ya!
Commentaires
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Bonjour Greg,
Merci pour cet article de très bonne qualité, comme toujours !
Pour information la technique de sélection par attribut, ex :
a[href$=.pdf]
Fonctionne parfaitement sur IE7, mais ne fonctionne pas sur IE6.
Comme IE6 est mort… enfin, je dis ça… :D
Le hook sur la fenêtre media est vraiment intéressant, merci ;)
Au plaisir de te lire.
Geoffrey
PS : sympa la checkbox en CSS sous le formulaire de commentaire ;)
Commentaire de Greg.
Salut et merci Geoffrey :)
Et voilà comment tuer tout l’intérêt de l’article hahahaha x)
En effet je me suis trop habitué à travailler en tenant compte de IE6, du coup, je garde mes habitudes de « rien ne marche ». Donc, tout ça pour dire que tu as parfaitement raison, le sélecteur d’attribut fonctionne avec IE7 (en plus j’ai lu des salades à une époque, puisque ce n’est pas du CSS3 mais du CSS2.1, anyways…).
Bon, je relativise sur l’utilité de ce tweak en me disant que certains clients veulent encore de la compatibilité IE6 (étrangement, quand on bosse avec des allemands ou autre, ils s’en foutent :) ), et que ce sélecteur a un mauvais rendement (perfs) dans le navigateur (ouais, tu sais les mecs qui se prennent la tête à savoir si une id est plus rapide qu’une class ou pas ^^).
J’aurais bien aimé hooker les liens classiques aussi (lien vers un site, une page interne…) mais ça ne me parait pas faisable à moins de reprendre entièrement la fenêtre de création de lien hélas :/
A bientôt
PS : pour les checkbox en CSS j’en ai même fait un article avec demo :) https://scri.in/check (d’ailleurs il faut que je revois un point au début de l’article, pour masquer les checkbox, la technique est imparfaite).
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Re,
Merci pour le lien, j’ai dû louper cet article dans le passé :)
Excellent boulot !
Mon intervention n’était vraiment pas destinée à casser ton article mais bien à apporter une précision sur la compatibilité :)
Effectivement ce tweak à toute sa place dans certains projets plutôt contraignants en terme de compatibilité IE.
Pour les liens internes/externes il est possible de faire ça « à l’ancienne » en filtrant le contenu du post avant enregistrement (peut-être ? sur content_filtered_save_pre ?), en vérifiant si la valeur de l’attribut href de chaque lien possède la chaine « http » et si elle est différente de la valeur de bloginfo(‘url’) alors on ajoute une classe « external », par exemple.
Ça risque d’être riche en expressions régulières, mais ça doit être faisable.
Je pose presque la question, je ne suis pas développeur à la base et je suis encore en pleine découverte des entrailles de WordPress.
Merci pour ton partage et ta réactivité,
Bonne soirée ;)
Commentaire de Greg.
Mon intervention n’était vraiment pas destinée à casser ton article mais bien à apporter une précision sur la compatibilité :)
T’inquiète, je ne l’ai absolument pas mal pris, c’était plus une réflexion que je me faisais ;)
En effet, la méthode du regex à la sauvegarde pourrait être une bonne idée. A voir si c’est faisable, mais je ne suis pas vraiment à l’aise avec les regex donc je passe mon tour cette fois ^^
Merci
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Re !
Je viens de faire un petit truc rapidement :
01020304050607080910111213141516
À voir s’il n’existe pas une possibilité de filtrer la chose directement lors de l’enregistrement de l’article en base de données.
Le défaut de cette technique c’est qu’elle ne vérifie pas si l’attribut class n’est pas déjà existant sur le lien. (conflit, toussa…)
Commentaire de Greg.
Je pensais aussi aux attributs qui vont sauter hélas.
Pour le hook à l’enregistrement du post on peut utiliser :
010203040506070809101112131415161718192021222324252627
Pas testé mais ça pourrait le faire.
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Yay ! Ça pourrait le faire.
Faut juste que je précise la regexp pour conserver les attributs et classes existantes, je pense que c’est possible, même si je ne suis jamais allé aussi loin dans l’expression régulière.
J’essaye de tester ça avant la semaine prochaine ;)
Merci pour le coup de main !
Commentaire de Greg.
Nota : attention aux doubles classes « external » ;) (ajoutée à chaque enregistrement du post).
Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Hello Greg,
Oui il fallait aussi y faire attention.
Je suis resté sur le filtre qui check le contenu avant affichage, mais globalement voilà où j’en suis :
01020304050607080910111213141516171819
Cela marche dans pas mal de cas, sauf si jamais une classe est déjà attribuée ET qu’un autre attribut traine sur le lien. Je n’arrive d’ailleurs pas à comprendre pourquoi ce comportement, puisque en absence de classe et en présence d’un autre attribut que href, la fonction fonctionne bien.
Petit point des liens pris en compte :
0102030405060708091011121314151617181920212223
Je suis sûr que je me casse la tête pour rien et qu’il existe une solution plus simple… :p
Commentaire de Greg.
Salut.
Quel boulot en effet :|
Je pense que dans ce cas il serait plus simple de passer par un sélecteur CSS3 :
1
Ou la méthode exposée par Bruno en enveloppant les liens externes dans un span.external par exemple (ce qui ne rend pas la chose automatique, mais c’est facilement faisable avec tinyMCE en créant un style particulier).
Ça aurait l’avantage de ne pas reposer sur un regex qui :
– serait lancé à chaque affichage de la page (perf),
– pourrait omettre certains cas de figure.
Solution 3 : demander aux devs de WP de nous mettre un hook dans la fenêtre de création de lien ^^
Commentaire de Toutine.
Coucou !
Ce tuto a l’air tip top mais personnellement le script :
0102030405060708091011121314151617
ne fonctionne pas chez moi :( avez vous une idée de la raison de ce non fonctionnement ? Mercii !
Commentaire de Greg.
Toutine,
je ne sais pas si c’est à cause du copier/coller ou des commentaires, mais il manque pas mal de choses à la fin, à la ligne
$html = ...
, elle est grandement incomplète.Commentaire de Geoffrey @ Geoffrey.Crofte.fr.
Hello,
Votre code est erroné.
Le lien créé n’a ni classe, ni href, ni aucun autre attribut. (ligne 14 de votre code)
Bon courage.
Commentaire de Greg.
Pas assez rapide, petit scarabée =D
Commentaire de Maxi.
Bonjour !
Merci pour ce code qui fonctionne à la perfection chez moi :)
J’ai juste 2-3 points à éclaircir, si c’est possible bien entendu ( néophyte inside ), je précise que j’ai utilisé ce bout de code pour ajouter la class « zoombox » sur les liens de mes images, avec la case à cocher.
-Est-il possible de cocher l’option lightbox par défaut ?
-Comment je pourrais faire pour ajouter cette même class sur les liens des images déjà uploadées sur le site, sans avoir à ouvrir les 250 images une par une ( ça pourrait être long ^^ )
-Une éventuelle option pour ajouter une class « zgallery1 » sur les liens de toutes les images d’un même article ( pour la gellerie donc :) )
Merci d’avance et encore merci pour tout
( je voulais pas faire de pub pour zoombox, mais j’ai plus confiance en grafikart.fr qu’autre chose ^^ )