Si vous avez déjà collé un shortcode trouvé sur un forum et obtenu soit une page blanche, soit un joli [mon_shortcode] affiché tel quel… le problème n’est pas le shortcode. C’est presque toujours où et comment vous l’enregistrez, et surtout comment vous gérez les entrées/sorties.
Le problème / Le besoin
Un shortcode WordPress sert à insérer un contenu dynamique dans l’éditeur, un widget, ou un page builder en tapant une balise comme [bpcab_…]. Le besoin typique : afficher une année automatiquement, une liste d’articles filtrée, un encart réutilisable, ou un petit formulaire.
Ce guide s’adresse aux blogueurs débutants (et aux intermédiaires qui ont déjà “cassé” un site avec un snippet). À la fin, vous saurez :
- créer un shortcode simple et fiable ;
- accepter des attributs (paramètres) ;
- gérer la sécurité (échappement, validation) ;
- charger du CSS/JS proprement ;
- éviter les pièges de performance et de cache.
Avant le premier bloc de code : je vous recommande de coller ce code dans un mini-plugin (plugin personnalisé) plutôt que dans functions.php. C’est plus stable lors des changements de thème. Vous pouvez aussi utiliser un mu-plugin si vous voulez que ce soit “impossible à désactiver”. Je détaille les emplacements exacts dans la section “Prérequis”.
Fonctions WordPress que vous allez utiliser (toutes compatibles WordPress 6.9.4 / PHP 8.1+) :
- add_shortcode() : enregistre un shortcode ;
- shortcode_atts() : fusionne vos attributs par défaut avec ceux fournis ;
- do_shortcode() : exécute des shortcodes dans une chaîne (à utiliser avec parcimonie) ;
- wp_enqueue_style() / wp_enqueue_script() : charge CSS/JS correctement ;
- wp_kses_post(), esc_html(), esc_url() : sécurise la sortie HTML.
Résumé rapide
- Vous créez un plugin “Shortcodes BPCAB” et vous y enregistrez vos shortcodes via
add_shortcode(). - Vous commencez par un shortcode ultra-simple (année dynamique), puis vous passez aux attributs.
- Vous ajoutez un shortcode plus “pro” : une liste d’articles avec requête WP_Query, cache, et échappement.
- Vous apprenez à charger CSS/JS uniquement quand le shortcode est utilisé.
- Vous testez proprement (mode debug, environnement de staging, et scénarios de panne réalistes).
Quand utiliser cette solution
- Vous voulez un bloc réutilisable dans plusieurs articles/pages, sans dupliquer du contenu.
- Vous devez insérer du contenu dynamique (ex. derniers articles d’une catégorie) dans un endroit où un bloc Gutenberg ne suffit pas.
- Vous travaillez avec un page builder (Divi 5, Elementor, Avada) et vous avez besoin d’un “point d’ancrage” simple : un champ texte qui accepte un shortcode.
- Vous souhaitez encapsuler une logique (requête, calcul, rendu HTML) dans un seul endroit maintenable.
Quand ne PAS utiliser cette solution
- Pour construire une mise en page complète : préférez des blocs Gutenberg, des patterns, ou des modules du builder. Un shortcode qui recrée une grille entière finit souvent en “usine à CSS”.
- Pour du contenu éditorial (texte long, images) : utilisez des blocs réutilisables / synced patterns plutôt qu’un shortcode.
- Pour des fonctionnalités lourdes (gros formulaires, e-commerce) : un plugin dédié est plus approprié. Un shortcode peut être l’interface, mais pas tout le système.
- Quand vous avez besoin d’accessibilité et d’édition visuelle : les blocs (Block Editor) offrent une meilleure expérience que des attributs de shortcode.
Prérequis / avant de commencer
Versions et environnement
- WordPress : 6.9.4 (ou plus récent).
- PHP : 8.1 minimum recommandé. Si vous êtes en 7.4, vous allez croiser des incompatibilités avec des plugins modernes et parfois des warnings. Référence PHP : versions supportées.
- Un accès FTP/SFTP ou au gestionnaire de fichiers de votre hébergeur.
Sauvegarde et sécurité
- Faites une sauvegarde (fichiers + base) avant de toucher au code. J’ai souvent vu un simple point-virgule manquant bloquer l’accès à l’admin.
- Ne modifiez jamais les fichiers du cœur WordPress (wp-includes, wp-admin).
Où coller le code (choisissez 1 option)
- Option recommandée : plugin personnalisé
Créez un fichier :
wp-content/plugins/bpcab-shortcodes/bpcab-shortcodes.phppuis activez-le dans Extensions. - Option “toujours actif” : mu-plugin
Créez :
wp-content/mu-plugins/bpcab-shortcodes.php. Les mu-plugins ne s’activent pas via l’admin, ils sont chargés automatiquement. - Option dépannage rapide : functions.php du thème enfant
Uniquement si vous avez un thème enfant. Sinon, à la prochaine mise à jour du thème, vous perdez tout.
Outils utiles
- Activer le debug sur staging : Debugging in WordPress.
- Un plugin de snippets peut aider, mais j’ai vu des “code snippets” se désactiver silencieusement après un fatal error. Pour apprendre, le plugin custom reste le plus clair.
L’approche naïve (et pourquoi l’éviter)
Le code que je vois le plus souvent chez les débutants ressemble à ça : tout est collé dans functions.php, la sortie n’est pas échappée, et on fait confiance aux attributs.
<?php
// Exemple naïf : à NE PAS copier tel quel.
add_shortcode('promo', function($atts) {
// Problème 1 : aucune valeur par défaut fiable
$texte = $atts['texte'];
// Problème 2 : sortie non échappée (risque XSS)
return '<div class="promo">' . $texte . '</div>';
});
Pourquoi ça pose problème :
- Sécurité : si un auteur peut éditer une page et passer
texte="<script>...", vous créez une surface XSS. Même si WordPress filtre beaucoup, ne comptez pas dessus. - Robustesse : si
texten’est pas fourni, vous aurez des notices PHP (et parfois des pages cassées selon la config). - Maintenance : le jour où vous changez de thème, vous perdez le shortcode (et vous voyez des [promo] partout).
La bonne approche — tutoriel pas à pas
Objectif : construire une petite “boîte à shortcodes” propre, progressive, et compatible WordPress 6.9.4+.
Étape 1 — Créer le plugin
- Créez le dossier :
wp-content/plugins/bpcab-shortcodes/ - Créez le fichier :
bpcab-shortcodes.php - Collez le code de base ci-dessous, puis activez l’extension dans l’admin.
<?php
/**
* Plugin Name: BPCAB Shortcodes
* Description: Une collection de shortcodes pédagogiques (WordPress 6.9.4+, PHP 8.1+).
* Version: 1.0.0
* Author: Votre Nom
* Requires at least: 6.9
* Requires PHP: 8.1
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Sécurité : empêche l'accès direct au fichier.
}
Étape 2 — Ajouter un shortcode simple (année dynamique)
Celui-ci est parfait pour démarrer : aucun attribut, aucune requête. Vous remplacez un “2026” figé par une année automatique.
<?php
// Shortcode : [bpcab_annee]
function bpcab_shortcode_annee(): string {
// gmdate() évite certains effets de fuseau horaire côté serveur.
// Pour la plupart des sites, date('Y') fonctionne aussi.
return esc_html( gmdate( 'Y' ) );
}
add_shortcode( 'bpcab_annee', 'bpcab_shortcode_annee' );
Test : ajoutez [bpcab_annee] dans un article. Vous devez voir l’année courante.
Étape 3 — Ajouter des attributs (encart “promo”)
Un shortcode devient utile quand il est paramétrable. Les attributs sont les paramètres dans la balise : [bpcab_promo titre="..."].
Vous allez :
- définir des valeurs par défaut avec
shortcode_atts(); - valider/sanitisiser les entrées ;
- échapper la sortie.
<?php
// Shortcode : [bpcab_promo titre="Offre" texte="..." lien="https://..." bouton="J'en profite"]
function bpcab_shortcode_promo( $atts = array(), $content = null, $tag = '' ): string {
$atts = shortcode_atts(
array(
'titre' => 'À ne pas manquer',
'texte' => '',
'lien' => '',
'bouton' => 'En savoir plus',
),
(array) $atts,
(string) $tag
);
// Sanitization (nettoyage) des attributs.
$titre = sanitize_text_field( $atts['titre'] );
$texte = sanitize_textarea_field( $atts['texte'] );
$lien = esc_url_raw( $atts['lien'] );
$bouton = sanitize_text_field( $atts['bouton'] );
// Rendu HTML : on échappe à la sortie.
$html = '<div class="bpcab-promo" role="note">';
$html .= '<strong class="bpcab-promo__titre">' . esc_html( $titre ) . '</strong>';
if ( $texte !== '' ) {
$html .= '<p class="bpcab-promo__texte">' . esc_html( $texte ) . '</p>';
}
if ( $lien !== '' ) {
$html .= '<p class="bpcab-promo__cta">';
$html .= '<a class="bpcab-promo__bouton" href="' . esc_url( $lien ) . '">' . esc_html( $bouton ) . '</a>';
$html .= '</p>';
}
$html .= '</div>';
return $html;
}
add_shortcode( 'bpcab_promo', 'bpcab_shortcode_promo' );
Test :
[bpcab_promo titre="Guide gratuit" texte="Recevez la checklist en PDF" lien="https://exemple.com" bouton="Télécharger"]
Étape 4 — Charger du CSS proprement (sans polluer tout le site)
Le réflexe débutant : coller du CSS dans le shortcode. Ça marche, mais ça finit vite en doublons, et ça complique le cache.
Approche propre : vous enregistrez une feuille CSS et vous ne la chargez que si le shortcode est présent sur la page.
<?php
/**
* Déclare les assets (CSS/JS) du plugin.
*/
function bpcab_shortcodes_register_assets(): void {
$ver = '1.0.0';
wp_register_style(
'bpcab-shortcodes',
plugins_url( 'assets/shortcodes.css', __FILE__ ),
array(),
$ver
);
}
add_action( 'wp_enqueue_scripts', 'bpcab_shortcodes_register_assets' );
/**
* Si un shortcode est détecté dans le contenu, on charge le CSS.
* Note : has_shortcode() ne détecte pas toujours les shortcodes injectés par des builders,
* mais c’est un bon premier niveau.
*/
function bpcab_maybe_enqueue_assets(): void {
if ( is_admin() ) {
return;
}
$post = get_post();
if ( ! $post instanceof WP_Post ) {
return;
}
$needs_css = false;
if ( has_shortcode( $post->post_content, 'bpcab_promo' ) || has_shortcode( $post->post_content, 'bpcab_annee' ) ) {
$needs_css = true;
}
if ( $needs_css ) {
wp_enqueue_style( 'bpcab-shortcodes' );
}
}
add_action( 'wp', 'bpcab_maybe_enqueue_assets' );
Créez ensuite le fichier : wp-content/plugins/bpcab-shortcodes/assets/shortcodes.css
.bpcab-promo{
border: 1px solid rgba(0,0,0,.12);
padding: 16px;
border-radius: 10px;
background: #fff;
}
.bpcab-promo__titre{
display:block;
margin-bottom: 8px;
}
.bpcab-promo__bouton{
display:inline-block;
padding: 10px 14px;
border-radius: 8px;
text-decoration: none;
border: 1px solid rgba(0,0,0,.18);
}
Étape 5 — Un shortcode “complexe” : liste d’articles filtrée + cache
Cas réel : vous voulez afficher les derniers articles d’une catégorie, avec limite, et sans exploser les performances. J’ai souvent vu ce shortcode écrit avec query_posts() (mauvaise idée) ou sans cache (mauvaise idée sur pages très visitées).
On va utiliser WP_Query et un cache via Transients (Transients API).
<?php
// Shortcode : [bpcab_posts categorie="actus" limit="5" afficher_date="1"]
function bpcab_shortcode_posts( $atts = array(), $content = null, $tag = '' ): string {
$atts = shortcode_atts(
array(
'categorie' => '', // slug de catégorie
'limit' => 5,
'afficher_date' => 0, // 1 ou 0
),
(array) $atts,
(string) $tag
);
$categorie = sanitize_title( $atts['categorie'] );
$limit = absint( $atts['limit'] );
$limit = $limit > 0 ? min( $limit, 20 ) : 5; // garde-fou
$show_date = (int) $atts['afficher_date'] === 1;
// Clé de cache dépendante des paramètres.
$cache_key = 'bpcab_posts_' . md5( wp_json_encode( array( $categorie, $limit, $show_date ) ) );
$cached = get_transient( $cache_key );
if ( is_string( $cached ) && $cached !== '' ) {
return $cached;
}
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $limit,
'no_found_rows' => true, // perf : pas de pagination
'ignore_sticky_posts' => true,
);
if ( $categorie !== '' ) {
$args['category_name'] = $categorie;
}
$q = new WP_Query( $args );
if ( ! $q->have_posts() ) {
$html = '<div class="bpcab-posts"><p>' . esc_html__( 'Aucun article trouvé.', 'bpcab-shortcodes' ) . '</p></div>';
set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );
return $html;
}
$html = '<div class="bpcab-posts">';
$html .= '<ul class="bpcab-posts__liste">';
while ( $q->have_posts() ) {
$q->the_post();
$titre = get_the_title();
$url = get_permalink();
$html .= '<li class="bpcab-posts__item">';
$html .= '<a class="bpcab-posts__lien" href="' . esc_url( $url ) . '">' . esc_html( $titre ) . '</a>';
if ( $show_date ) {
// get_the_date() renvoie déjà une chaîne, on échappe.
$html .= '<span class="bpcab-posts__date"> ' . esc_html( get_the_date() ) . '</span>';
}
$html .= '</li>';
}
wp_reset_postdata();
$html .= '</ul>';
$html .= '</div>';
// Cache court : suffisant pour éviter 100 requêtes/minute sur une page populaire.
set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );
return $html;
}
add_shortcode( 'bpcab_posts', 'bpcab_shortcode_posts' );
Test :
[bpcab_posts categorie="actus" limit="5" afficher_date="1"][bpcab_posts limit="3"](toutes catégories)
Code complet
Copiez-collez ce fichier tel quel dans wp-content/plugins/bpcab-shortcodes/bpcab-shortcodes.php, créez le CSS dans assets/shortcodes.css, puis activez le plugin.
<?php
/**
* Plugin Name: BPCAB Shortcodes
* Description: Une collection de shortcodes pédagogiques (WordPress 6.9.4+, PHP 8.1+).
* Version: 1.0.0
* Author: Votre Nom
* Requires at least: 6.9
* Requires PHP: 8.1
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Sécurité : empêche l'accès direct au fichier.
}
/**
* Shortcode : [bpcab_annee]
*/
function bpcab_shortcode_annee(): string {
return esc_html( gmdate( 'Y' ) );
}
add_shortcode( 'bpcab_annee', 'bpcab_shortcode_annee' );
/**
* Shortcode : [bpcab_promo titre="Offre" texte="..." lien="https://..." bouton="J'en profite"]
*/
function bpcab_shortcode_promo( $atts = array(), $content = null, $tag = '' ): string {
$atts = shortcode_atts(
array(
'titre' => 'À ne pas manquer',
'texte' => '',
'lien' => '',
'bouton' => 'En savoir plus',
),
(array) $atts,
(string) $tag
);
$titre = sanitize_text_field( $atts['titre'] );
$texte = sanitize_textarea_field( $atts['texte'] );
$lien = esc_url_raw( $atts['lien'] );
$bouton = sanitize_text_field( $atts['bouton'] );
$html = '<div class="bpcab-promo" role="note">';
$html .= '<strong class="bpcab-promo__titre">' . esc_html( $titre ) . '</strong>';
if ( $texte !== '' ) {
$html .= '<p class="bpcab-promo__texte">' . esc_html( $texte ) . '</p>';
}
if ( $lien !== '' ) {
$html .= '<p class="bpcab-promo__cta">';
$html .= '<a class="bpcab-promo__bouton" href="' . esc_url( $lien ) . '">' . esc_html( $bouton ) . '</a>';
$html .= '</p>';
}
$html .= '</div>';
return $html;
}
add_shortcode( 'bpcab_promo', 'bpcab_shortcode_promo' );
/**
* Shortcode : [bpcab_posts categorie="actus" limit="5" afficher_date="1"]
*/
function bpcab_shortcode_posts( $atts = array(), $content = null, $tag = '' ): string {
$atts = shortcode_atts(
array(
'categorie' => '',
'limit' => 5,
'afficher_date' => 0,
),
(array) $atts,
(string) $tag
);
$categorie = sanitize_title( $atts['categorie'] );
$limit = absint( $atts['limit'] );
$limit = $limit > 0 ? min( $limit, 20 ) : 5;
$show_date = (int) $atts['afficher_date'] === 1;
$cache_key = 'bpcab_posts_' . md5( wp_json_encode( array( $categorie, $limit, $show_date ) ) );
$cached = get_transient( $cache_key );
if ( is_string( $cached ) && $cached !== '' ) {
return $cached;
}
$args = array(
'post_type' => 'post',
'post_status' => 'publish',
'posts_per_page' => $limit,
'no_found_rows' => true,
'ignore_sticky_posts' => true,
);
if ( $categorie !== '' ) {
$args['category_name'] = $categorie;
}
$q = new WP_Query( $args );
if ( ! $q->have_posts() ) {
$html = '<div class="bpcab-posts"><p>' . esc_html__( 'Aucun article trouvé.', 'bpcab-shortcodes' ) . '</p></div>';
set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );
return $html;
}
$html = '<div class="bpcab-posts">';
$html .= '<ul class="bpcab-posts__liste">';
while ( $q->have_posts() ) {
$q->the_post();
$html .= '<li class="bpcab-posts__item">';
$html .= '<a class="bpcab-posts__lien" href="' . esc_url( get_permalink() ) . '">' . esc_html( get_the_title() ) . '</a>';
if ( $show_date ) {
$html .= '<span class="bpcab-posts__date"> ' . esc_html( get_the_date() ) . '</span>';
}
$html .= '</li>';
}
wp_reset_postdata();
$html .= '</ul>';
$html .= '</div>';
set_transient( $cache_key, $html, 5 * MINUTE_IN_SECONDS );
return $html;
}
add_shortcode( 'bpcab_posts', 'bpcab_shortcode_posts' );
/**
* Déclare les assets (CSS/JS) du plugin.
*/
function bpcab_shortcodes_register_assets(): void {
$ver = '1.0.0';
wp_register_style(
'bpcab-shortcodes',
plugins_url( 'assets/shortcodes.css', __FILE__ ),
array(),
$ver
);
}
add_action( 'wp_enqueue_scripts', 'bpcab_shortcodes_register_assets' );
/**
* Charge le CSS uniquement si au moins un shortcode est détecté.
*/
function bpcab_maybe_enqueue_assets(): void {
if ( is_admin() ) {
return;
}
$post = get_post();
if ( ! $post instanceof WP_Post ) {
return;
}
$needs_css = false;
// Détection basique dans le contenu.
if ( has_shortcode( $post->post_content, 'bpcab_promo' )
|| has_shortcode( $post->post_content, 'bpcab_annee' )
|| has_shortcode( $post->post_content, 'bpcab_posts' )
) {
$needs_css = true;
}
if ( $needs_css ) {
wp_enqueue_style( 'bpcab-shortcodes' );
}
}
add_action( 'wp', 'bpcab_maybe_enqueue_assets' );
/**
* Maintenance : purge simple des transients du shortcode posts quand un article est mis à jour.
* (Approche pragmatique : on supprime "large", sans chercher à recalculer toutes les clés.)
*/
function bpcab_purge_posts_shortcode_cache_on_save( $post_id ): void {
if ( wp_is_post_revision( $post_id ) ) {
return;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Purge large : on supprime les transients qui commencent par bpcab_posts_
// WordPress ne fournit pas une API native pour supprimer par préfixe.
// On fait une requête SQL sécurisée via $wpdb.
global $wpdb;
$like = $wpdb->esc_like( '_transient_bpcab_posts_' ) . '%';
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
$like,
str_replace( '_transient_', '_transient_timeout_', $like )
)
);
}
add_action( 'save_post', 'bpcab_purge_posts_shortcode_cache_on_save' );
Explication du code
Shortcode : c’est quoi techniquement ?
Un shortcode est une balise reconnue par WordPress, transformée en HTML au moment de l’affichage. Vous l’enregistrez avec add_shortcode(), qui associe un nom (ex. bpcab_promo) à une fonction PHP.
Actions, filtres : la différence (simple)
Un hook est un “point d’accroche” dans WordPress. Il en existe deux types :
- Action : vous exécutez du code à un moment donné (ex.
add_action('wp_enqueue_scripts', ...)). Doc : Actions. - Filtre : vous recevez une valeur, vous la modifiez, vous la retournez. Doc : Filters.
Pourquoi shortcode_atts() change la donne
shortcode_atts() évite les “Undefined index” et vous garantit des valeurs par défaut. Dans mon expérience, c’est la différence entre un shortcode “qui marche sur votre page de test” et un shortcode qui survit aux usages réels (copier-coller incomplet, attribut manquant, etc.).
Sanitization vs escaping
- Sanitization (entrée) : vous nettoyez ce que l’utilisateur fournit. Ex.
sanitize_text_field(),absint(),esc_url_raw(). - Escaping (sortie) : vous rendez votre HTML sûr. Ex.
esc_html()pour du texte,esc_url()pour une URL dans un attribut.
Référence : Security in WordPress (APIs).
Pourquoi WP_Query (et pas query_posts)
query_posts() modifie la requête principale et crée des effets de bord (pagination cassée, SEO, performance). WP_Query isole la requête et se réinitialise avec wp_reset_postdata().
Pourquoi un cache Transient
Sur une page très consultée, un shortcode “derniers articles” peut exécuter une requête SQL à chaque vue. Le cache Transient (Transients API) stocke le HTML rendu pendant quelques minutes. C’est simple, et souvent suffisant.
Variantes et cas d’usage
Variante 1 — Shortcode enveloppant (avec contenu) : [bpcab_note]…[/bpcab_note]
Vous voulez entourer un texte saisi dans l’éditeur. Ici, le contenu est dans $content. Attention : si vous autorisez du HTML, vous devez filtrer.
<?php
// Shortcode : [bpcab_note]Mon texte[/bpcab_note]
function bpcab_shortcode_note( $atts = array(), $content = null ): string {
$content = $content ?? '';
// Autorise un HTML "type contenu" (liens, emphasis, etc.) et supprime le dangereux.
$safe_html = wp_kses_post( $content );
return '<div class="bpcab-note">' . $safe_html . '</div>';
}
add_shortcode( 'bpcab_note', 'bpcab_shortcode_note' );
Variante 2 — Autoriser des shortcodes imbriqués (avec prudence)
Vous pouvez vouloir que le contenu de votre shortcode exécute d’autres shortcodes. Ça se fait avec do_shortcode(), mais c’est une source classique de lenteur si vous l’appliquez partout.
<?php
function bpcab_shortcode_note_nested( $atts = array(), $content = null ): string {
$content = $content ?? '';
// 1) Exécute les shortcodes internes
$content = do_shortcode( $content );
// 2) Puis filtre le HTML final
$content = wp_kses_post( $content );
return '<div class="bpcab-note">' . $content . '</div>';
}
// Exemple : enregistrez-le sous un autre nom pour comparer.
add_shortcode( 'bpcab_note_nested', 'bpcab_shortcode_note_nested' );
Variante 3 — Shortcode “dynamique selon l’utilisateur” (permissions)
Cas concret : afficher un lien “Éditer cet article” uniquement aux utilisateurs qui ont le droit. Ici, vous utilisez les capacités (capabilities) WordPress.
<?php
// Shortcode : [bpcab_edit_link]
function bpcab_shortcode_edit_link(): string {
if ( ! is_singular() ) {
return '';
}
$post_id = get_queried_object_id();
if ( ! $post_id ) {
return '';
}
// Vérifie la permission d'édition.
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return '';
}
$url = get_edit_post_link( $post_id );
if ( ! $url ) {
return '';
}
return '<a class="bpcab-edit-link" href="' . esc_url( $url ) . '">' . esc_html__( 'Modifier cet article', 'bpcab-shortcodes' ) . '</a>';
}
add_shortcode( 'bpcab_edit_link', 'bpcab_shortcode_edit_link' );
Compatibilité Divi 5 / Elementor / Avada
Les shortcodes restent très utilisés dans les builders, mais il y a un détail qui surprend : la détection “le shortcode est présent dans le contenu” n’est pas toujours fiable, car certains builders stockent la mise en page dans des données sérialisées ou des champs meta.
Divi 5
- Vous pouvez insérer vos shortcodes via un module texte / code selon votre setup.
- Si votre CSS ne se charge pas (car
has_shortcode()ne “voit” pas le shortcode), la solution simple est de charger le style globalement, ou d’ajouter une option “forcer le chargement”.
Approche pragmatique que j’utilise souvent sur Divi : charger la feuille CSS sur tout le site si elle est légère.
<?php
// Variante : si vous êtes sur Divi/Elementor et que la détection échoue,
// remplacez bpcab_maybe_enqueue_assets() par un enqueue global.
function bpcab_enqueue_assets_globally(): void {
if ( is_admin() ) {
return;
}
wp_enqueue_style( 'bpcab-shortcodes' );
}
// add_action( 'wp_enqueue_scripts', 'bpcab_enqueue_assets_globally', 20 );
Elementor
- Utilisez le widget “Shortcode”.
- Elementor peut mettre en cache le rendu ; si vous modifiez le PHP, purgez le cache Elementor et votre cache serveur/CDN.
Avada (Fusion Builder)
- Utilisez l’élément “Shortcode”.
- Si vous avez un système de performance/caching Avada activé, pensez à vider ses caches après modification.
Vérifications après mise en place
- Dans l’admin WordPress : Extensions → le plugin est activé, sans message d’erreur.
- Dans une page de test :
[bpcab_annee]affiche l’année. [bpcab_promo ...]affiche un encart, et le lien est cliquable.[bpcab_posts ...]affiche une liste, et les titres sont corrects.- Dans le code source de la page (view source) : la feuille
shortcodes.cssest chargée quand nécessaire (ou globalement si vous avez choisi la variante).
Tableau de diagnostic rapide
| Symptôme | Cause probable | Vérification | Solution |
|---|---|---|---|
| Le shortcode s’affiche tel quel : [bpcab_annee] | Le plugin n’est pas actif ou le code n’est pas chargé | Extensions → plugin activé ? | Activer le plugin, vérifier le bon fichier et le bon dossier |
| Page blanche / erreur 500 | Erreur PHP (parenthèse/point-virgule manquant) | Activer WP_DEBUG sur staging, consulter debug.log | Corriger la syntaxe, revenir via FTP si l’admin est inaccessible |
| Le CSS ne s’applique pas dans un builder | has_shortcode() ne détecte pas le contenu du builder |
Voir si shortcodes.css est chargé |
Charger le CSS globalement, ou implémenter une détection via meta builder |
| La liste d’articles ne se met pas à jour | Cache transient + cache plugin/CDN | Désactiver cache temporairement, attendre 5 min | Purger caches, réduire TTL, vérifier purge sur save_post |
Si ça ne marche pas
1) Vérifier l’emplacement du code
- Si vous avez mis le code dans functions.php du thème parent : vous risquez de le perdre à la mise à jour. Déplacez-le dans un plugin.
- Si vous avez créé le plugin : vérifiez le chemin exact
wp-content/plugins/bpcab-shortcodes/bpcab-shortcodes.php.
2) Activer les logs correctement
Sur une copie de test (staging), activez le debug WordPress selon la doc officielle : Debugging WordPress.
3) Identifier les erreurs réalistes
- Erreur “Parse error: syntax error” : souvent une accolade manquante ou un
;oublié. - Erreur “Call to undefined function” : vous avez collé du code dans un contexte où WordPress n’est pas chargé (mauvais fichier), ou vous utilisez une fonction d’un ancien tutoriel.
- Le shortcode marche sur une page mais pas ailleurs : cache, ou builder qui ne stocke pas le contenu dans
post_content.
4) Purger les caches
- Cache de plugin (LiteSpeed Cache, WP Rocket, etc.)
- Cache serveur (Varnish) et CDN
- Cache builder (Elementor, Avada performance)
- Cache navigateur (testez en navigation privée)
5) Régénérer les permaliens (si besoin)
Ce n’est pas directement lié aux shortcodes, mais j’ai vu des sites où get_permalink() renvoie des URLs inattendues après migration. Allez dans Réglages → Permaliens et cliquez “Enregistrer”.
Pièges et erreurs courantes
| Erreur | Cause | Solution |
|---|---|---|
| Coller le code dans le mauvais fichier | Ajout dans un thème parent ou un fichier non chargé | Utiliser un plugin custom ou mu-plugin, vérifier l’activation |
Oublier un ; ou une accolade } |
Erreur de syntaxe PHP | Relire ligne par ligne, activer les logs, utiliser un éditeur avec coloration |
| Confusion actions vs filtres | Vous essayez de “retourner” quelque chose dans une action | Pour charger CSS/JS : action. Pour modifier une valeur : filtre |
| Utiliser un hook inadapté pour le CSS | Enqueue trop tôt/trop tard | Déclarer via wp_enqueue_scripts, déclencher via wp ou global |
| Shortcode non interprété dans un builder | Widget/module incorrect ou contenu non traité | Utiliser le widget “Shortcode” (Elementor), module adapté (Divi/Avada) |
| CSS/JS non chargé | Mauvais plugins_url() ou fichier manquant |
Vérifier le chemin assets/shortcodes.css et les droits fichiers |
| Conflit avec un plugin de cache | HTML mis en cache, transients non purgés | Purger caches, réduire TTL, purge sur save_post |
| Tester directement en production | Pas de staging, pas de rollback | Tester sur staging, sauvegarde, déployer ensuite |
| Code d’un ancien tuto incompatible | Exemples obsolètes, APIs changées, PHP trop ancien | Cibler WP 6.9.4+ et PHP 8.1+, vérifier la doc officielle |
Conseils sécurité, performance et maintenance
Sécurité
- Échappez toujours la sortie :
esc_html(),esc_url(), etc. Référence : Escaping. - Sanitisez les attributs :
absint(),sanitize_text_field(),sanitize_title(). - Si vous créez un shortcode qui modifie des données (rare, mais possible via formulaire), utilisez des nonces et des vérifications de capacités. Doc : Nonces.
Performance
- Évitez
do_shortcode()sur de gros contenus si vous pouvez faire autrement. - Pour des listes d’articles, utilisez
no_found_rowset limitezposts_per_page. - Ajoutez un cache (transient) si le shortcode est sur une page très visitée. Sur des sites média, c’est souvent la différence entre “OK” et “CPU à 100%”.
Maintenance
- Préfixez toujours vos shortcodes et fonctions (ici
bpcab_) pour éviter les collisions. - Versionnez votre plugin (même en interne) et gardez un changelog simple.
- Si vous distribuez le plugin : respectez les standards de code. Référence : WordPress Coding Standards.
Ressources
- Doc officielle Shortcodes : Shortcodes (Plugin Developer Handbook)
- Référence
add_shortcode(): add_shortcode() - Référence
shortcode_atts(): shortcode_atts() - WP_Query : WP_Query
- Transients API : Transients
- Debug WordPress : Debugging
- Nonces : Nonces
- PHP (référence) : PHP Manual
- Code source WordPress (référence) : wordpress-develop sur GitHub
FAQ
Pourquoi mon shortcode s’affiche en texte au lieu du résultat ?
Soit il n’est pas enregistré (plugin inactif, code non chargé), soit vous l’insérez dans un champ qui n’exécute pas les shortcodes. Testez dans le contenu d’un article standard, puis dans votre builder via le widget/module “Shortcode”.
Puis-je mettre le code dans functions.php ?
Oui, mais uniquement dans un thème enfant. Sinon vous perdrez le code à la mise à jour. Pour un site de blog “long terme”, le plugin custom est plus sûr.
Est-ce que les shortcodes sont “dépassés” avec Gutenberg ?
Ils sont moins centraux qu’avant, mais restent pratiques pour des contenus dynamiques et pour les builders. Si vous avez besoin d’édition visuelle et d’options UI, un bloc personnalisé est souvent mieux.
Comment passer du HTML dans un attribut de shortcode ?
Évitez si possible. Si vous devez le faire, filtrez strictement avec wp_kses() ou wp_kses_post() selon le besoin, et documentez clairement ce qui est autorisé. Sinon vous ouvrez une porte XSS.
Pourquoi mon CSS ne se charge pas sur certaines pages (Elementor/Divi/Avada) ?
Parce que votre contenu peut ne pas être stocké dans post_content, donc has_shortcode() ne détecte rien. Solution simple : charger le CSS globalement si léger, ou implémenter une détection spécifique au builder (plus avancé).
Mon shortcode “derniers articles” ralentit le site : que faire ?
Ajoutez un cache (transient), limitez posts_per_page, activez no_found_rows, et évitez les requêtes inutiles. Sur un site à fort trafic, mettez aussi une stratégie de purge (comme le hook save_post fourni).
Comment tester proprement sans casser mon site ?
Travaillez sur une copie staging, activez les logs, testez 3 scénarios : attributs manquants, attributs invalides, et page builder. Puis déployez en production avec une sauvegarde et une purge cache.
Est-ce que je peux créer plusieurs fichiers pour organiser mes shortcodes ?
Oui. Dans un plugin, vous pouvez faire require_once de fichiers séparés (ex. shortcodes/promo.php). Gardez un point d’entrée unique qui charge tout.
Comment éviter les conflits de noms ?
Préfixez tout : shortcode, fonctions, handles CSS/JS. Exemple : bpcab_promo plutôt que promo. C’est une cause fréquente de bugs sur des sites avec beaucoup de plugins.
Peut-on utiliser un shortcode dans le titre d’un article ?
Par défaut, non : WordPress n’exécute pas les shortcodes partout. Vous pouvez techniquement filtrer certains champs, mais je le déconseille sur un site de blog débutant : vous risquez des effets de bord SEO et des surprises côté admin.