En juillet 2023, quand j’ai décidé de quitter Twitter, j’ai écrit un article dans lequel je partageais le fait que j’ai également retiré de mon blog les liens de partage direct vers les réseaux sociaux bien connus afin de leur faire moins de publicité.
À la place, j’ai codé un petit script qui copie le titre de l’article et son adresse dans le presse-papier afin de partager l’article où on veut (y compris sur Mastodon !) en collant ces éléments. Bien sûr, j’ai codé ça de façon à ce que ça respecte les règles d’accessibilité !
Vous pouvez retrouver ce système de partage en bas de chaque article. Et, je partageais le script sur CodePen.
Dernièrement, une personne m’a demandée comment j’avais fait ce composant pour WordPress. Alors, je me suis dit que j’allais faire un article qui donne mon code WordPress (puisque sur CodePen, c’est du HTML brut pour l’exemple). Cela me permet aussi de donner un peu plus d’informations sur l’accessibilité de celui-ci.
Concrètement, nous allons avoir besoin de 3 morceaux de code (hors CSS, je vous laisse gérer ça) :
- Le code HTML et PHP qui va sous votre article et affiche le composant ;
- Une fonction PHP WordPress pour appeler le script et déclarer la chaîne de caractères du message de confirmation qu’on ajoute au DOM via JavaScript ;
- Le JavaScript qui gère la copie dans le presse-papier et l’affichage du message de confirmation puis sa disparition.
Vous pouvez utiliser ce code librement, sans oublier de laisser mon crédit dans le commentaire du code JavaScript avec l’URL de cet article, qui permettra d’avoir toute la documentation nécessaire.
Le code PHP pour WordPress
Ce code est spécifiquement adapté, ici, pour fonctionner dans WordPress mais vous pouvez, bien sûr, l’adapter à tout autre environnement.
Dans votre thème, sous le contenu d’un article
Sous le contenu des articles, on ajoute d’abord le composant avec un titre, un paragraphe d’explication, le texte à copier, le bouton de copie et la div
vide dans laquelle on placera le message de confirmation via JavaScript.
Je ne peux pas vous dire précisément dans quel fichier de votre thème placer ce code car cela dépendra de comment il est construit. Toutefois, cela pourrait être dans le fichier single.php (ou dans le morceau de gabarit (template part) appelé dedans pour mettre en forme le contenu).
Dans le code ci-dessous :
- Remplacez
textdomain
par votre domaine de texte pour les traductions ; - Les attributs
data-*
seront utiles pour le script ; - Les différents commentaires expliquent différents points importants, n’oubliez pas de les lire attentivement.
<div class="social-sharing" id="sharing">
<!-- Un titre pour le bloc afin de le retrouver facilement dans la hiérarchie du contenu (particulièrement important pour les personnes aveugles). Le titre est de niveau 2 et ne devrait, en principe, pas être d’un niveau inférieur. Ainsi, il ne sera pas considéré comme sous-titre d’un titre de plus haut niveau dans l’article (ça n’aurait pas de sens !). -->
<h2 class="social-sharing-heading"><?php _e( 'Did you like this article? Share it!', 'textdomain' ); ?></h2>
<!-- Un court paragraphe d’explication du fonctionnement du composant, visible par tout le monde. -->
<p>
<?php _e( 'Click on the button below to copy the title and the address of the post to your clipboard, or copy it from the paragraph below.', 'textdomain' ); ?>
</p>
<!-- Le texte qu’on va copier, visible par tout le monde : ça permet de savoir ce qui va se passer, de copier à la main sans utiliser le bouton (si les internautes préfèrent ou si le bouton ne fonctionnait pas).
On récupère automatiquement le titre de l’article, le nom du site et l’URL de l’article. -->
<p class="copy-text" data-copy-btn="content"><?php echo get_the_title() . ' – ' . get_bloginfo( 'name' ) . '<br>' . get_the_permalink(); ?></p>
<!-- Le bouton est un vrai bouton HTML qui fonctionnera pour les personnes naviguant au clavier. Il est caché par défaut (attribut hidden) et rendu visible via JS si la fonction permettant de copier dans le presse-papier est supportée. -->
<p><button type="button" class="copy-btn btn-default" data-copy-btn="button" hidden><?php _e( 'Copy the title and the address of the post', 'textdomain' ); ?></button></p>
<!-- Message de statut : la div qui permettra de mettre un message de confirmation. Elle doit impérativement être présente dans le DOM par défaut, non masquée en CSS, avec un attribut role="status" afin que le message soit restitué aux lecteurs d’écran lorsqu’il apparaît. -->
<div role="status" data-copy-btn="status"></div>
</div>
Pour aller plus loin sur les points d’accessibilité, vous pouvez lire ces articles :
- Sur les boutons accessibles : « Créer des boutons accessibles et dignes de ce nom en HTML », par moi-même, 2021 ;
- Sur les messages de statut (autrement nommés live regions en anglais) et les différents rôles et attributs ARIA : « Live regions ARIA :
aria-live
et ses analoguesalert
,log
,status
», par Cécile Jeanne, Access42, 2024 ; - Sur les messages de statut et les conditions de leur bonne restitution : « Live regions ARIA : comment garantir leur restitution par les lecteurs d’écran ? », par Cécile Jeanne, Access42, 2024.
Dans le fichier functions.php
Dans les fonctions du thème (functions.php), on appelle le fichier du script et on déclare la chaîne de caractères à traduire qu’on va utiliser pour le message de confirmation. On utilisera son nom de code (objectL10n.copied
) dans le script.
/**
* Mise en file d'attente des scripts du thème.
*/
function my_scripts() {
wp_enqueue_script( 'my-scripts', get_template_directory_uri() . '/js/copy-btn.js' );
/**
* Ajout de chaînes de caractères à traduire.
* @link https://codex.wordpress.org/I18n_for_WordPress_Developers#Handling_JavaScript_files
*/
wp_localize_script( 'my-scripts', 'objectL10n', array(
'copied' => esc_html__( 'The title and the address of the post have been copied to your clipboard! Paste it where you want!', 'textdomain' )
) );
}
add_action( 'wp_enqueue_scripts', 'my_scripts' );
Le code JavaScript
Ce script gère la copie du contenu (titre et URL de l’article) dans le presse-papier ainsi que l’affichage et la disparition du message de confirmation.
/**
* Copy-Btn
* Bouton pour copier du contenu dans le presse-papier
*
* Autrice : Julie Moynat
* Source et documentation : https://www.lalutineduweb.fr/bouton-partage-universel-accessible-wordpress/
*/
window.addEventListener('DOMContentLoaded', function () {
/** Si la fonctionnalité d’accès au presse-papier est supportée. */
if (navigator.clipboard) {
/** On récupère le bouton de copie. */
let button = document.querySelector('[data-copy-btn="button"]');
if( button ) {
/** On récupère ses éléments associés. */
let content = document.querySelector('[data-copy-btn="content"]').innerText;
let status = document.querySelector('[data-copy-btn="status"]');
let statusParagraph = document.createElement('p');
/** La fonctionnalité d’accès au presse-papier est supportée, donc on affiche le bouton de copie. */
button.hidden = false;
/** Au clic sur le bouton, on copie le contenu dans le presse-papier. */
button.addEventListener('click', () => {
/** Copier le contenu et ensuite… */
navigator.clipboard.writeText(content).then(() => {
/** Message de statut : afficher un message de confirmation s’il n’est pas déjà là. */
if (!status.hasChildNodes()) {
/* Ajouter le message dans le paragraphe. Le message correspond au nom de code de la chaîne de traduction déclarée dans le functions.php précédemment. */
statusParagraph.append( objectL10n.copied );
/* Ajouter le paragraphe dans la div[role="status"]. */
status.append( statusParagraph );
/* Ajouter une classe sur la div[role="status"]. */
status.classList.add('copy-status');
}
/** Retirer le message de statut après un temps (pas trop court pour laisser le temps de lire). */
let statusParagraphAfter = document.querySelector( '[data-copy-btn="status"] > p' );
setTimeout(() => {
/* Retirer le nœud texte. */
while (statusParagraphAfter.firstChild) {
statusParagraphAfter.removeChild(statusParagraphAfter.firstChild);
}
/* Retirer le paragraphe. */
while (status.firstChild) {
status.removeChild(status.firstChild);
}
/* Retirer la classe de la div[role="status"]. */
status.classList.remove('copy-status');
}, 8000);
},
() => {});
}, false);
}
}
});
Et voilà !
Bien sûr, n’oubliez pas de traduire les chaînes de caractères de votre thème et de faire un peu de styles CSS en respectant les contrastes de couleurs pour que les personnes malvoyantes puissent vous lire.
Bonne idée ! je l’ai déjà mis en place sur des sites de clients mais je n’avais jamais pensé à le mettre sur mon propre site (les cordonniers mal chaussés, tout ça).
Une question : que penses-tu de l’idée d’utiliser un
<input readonly>
au lieu du<p>
contenant l’URL ?En terme d’UX cela permet à un utilisateur qui cliquerais sur l’URL de la sélectionner directement, mais je me pose la question de l’accessibilité d’une telle approche.
Petit démo https://codepen.io/Julianoe/pen/XWvaQgM
C’est une possibilité aussi, en effet. Il faudra juste ajouter un
label
associé à ce champ.Côté utilisabilité, ça m’embête car ça ne permet pas de voir en une fois ce qu’on copie (et avec un
input
, ça peut être vraiment pénible). Pour mon exemple avec titre + URL, on pourrait utiliser untextarea
plutôt qu’uninput
mais on aura à scroller quand même dans le champ pour tout voir selon la taille d’écran.En principe, sauf incompatibilité, le bouton fait le job de copier sans avoir à sélectionner à la main donc, j’ai l’impression qu’on est sur un besoin à la marge. Il faudrait faire des tests d’utilisabilité pour savoir !
Il est en réalité possible de faciliter la sélection sans champ de texte (et même sans JavaScript) avec la propriété
user-select
. Il suffit d’ajouteruser-select: all;
(et-webkit-user-select: all;
pour Safari) sur un élément pour qu’au clic simple, il soit sélectionné en entier. Et ce sans les limitations d’affichage des « et autres « .Tous les détails sur le MDN, comme toujours.
Merci Amaury. Les balises HTML sautant dans les commentaires, il y a quelques petits trous dans ton message mais on comprend l’idée.
Effectivement, on peut ajouter ça sans trop de difficulté.
Il fallait comprendre
, mais en effet ce n’était pas indispensable au propos !