Un studio de design partenaire d’une agence me demande régulièrement la même chose : pouvoir importer ses logos vectoriels directement dans la médiathèque, sans repasser par un export PNG à chaque révision. WordPress refuse le SVG par défaut, et c’est un choix assumé : un fichier SVG est en réalité un document XML, capable d’embarquer du JavaScript exécutable dans le navigateur. L’autoriser sans précaution revient à ouvrir une porte au cross-site scripting.
La bonne pratique combine deux étapes bien distinctes : autoriser techniquement le type MIME avec upload_mimes, puis nettoyer réellement le contenu du fichier avec une bibliothèque de sanitization dédiée. La première étape sans la seconde ne protège absolument rien.
Autoriser le type MIME avec upload_mimes
Le filtre upload_mimes reçoit un tableau associant des extensions à des types MIME. Ajouter le SVG suffit pour que WordPress accepte le fichier au moment de l’upload, sans en vérifier le contenu.
function studio_autoriser_svg( $mimes ) {
$mimes['svg'] = 'image/svg+xml';
return $mimes;
}
add_filter( 'upload_mimes', 'studio_autoriser_svg' );
À ce stade, n’importe quel fichier .svg passe, y compris un fichier contenant une balise <script> ou un attribut onload. C’est précisément la raison pour laquelle WordPress refuse ce format par défaut : la vérification native basée sur wp_check_filetype() ne fait qu’inspecter l’extension et le type MIME déclaré, pas la structure interne du fichier.
Nettoyer réellement le fichier avec une sanitization
Le hook wp_handle_upload_prefilter permet d’intercepter le fichier avant son enregistrement définitif, et donc d’y appliquer un nettoyage. La bibliothèque PHP enshrined/svg-sanitize est une référence largement utilisée dans l’écosystème WordPress pour cet usage précis : elle retire les balises et attributs dangereux tout en conservant le rendu visuel.

function studio_nettoyer_svg_uploade( $file ) {
if ( 'image/svg+xml' !== $file['type'] ) {
return $file;
}
$contenu = file_get_contents( $file['tmp_name'] );
$nettoyeur = new enshrined\svgSanitize\Sanitizer();
$contenu_propre = $nettoyeur->sanitize( $contenu );
if ( false === $contenu_propre ) {
$file['error'] = 'Le fichier SVG n\'a pas pu être nettoyé.';
return $file;
}
file_put_contents( $file['tmp_name'], $contenu_propre );
return $file;
}
add_filter( 'wp_handle_upload_prefilter', 'studio_nettoyer_svg_uploade' );
Cette bibliothèque se déclare via Composer (composer require enshrined/svg-sanitize) et se charge à travers l’autoloader du thème ou de l’extension maison. Sans gestionnaire de dépendances, une version packagée en fichier unique existe aussi, mais Composer reste préférable pour suivre les mises à jour de sécurité.
Restreindre l’upload par rôle
Même nettoyé, il reste prudent de restreindre l’upload de SVG aux rôles de confiance — administrateurs et éditeurs — plutôt que de l’ouvrir à tous les contributeurs d’un site à plusieurs mains.
function studio_autoriser_svg( $mimes ) {
if ( ! current_user_can( 'manage_options' ) ) {
return $mimes;
}
$mimes['svg'] = 'image/svg+xml';
return $mimes;
}
add_filter( 'upload_mimes', 'studio_autoriser_svg' );
Générer une miniature correcte dans la médiathèque
Sans traitement supplémentaire, un fichier SVG s’affiche comme une icône générique grise dans la grille de la médiathèque, ce qui complique la sélection visuelle. Un filtre sur wp_prepare_attachment_for_js permet d’utiliser le fichier SVG lui-même comme miniature, puisque le format s’affiche nativement dans un navigateur.
function studio_miniature_svg( $reponse, $attachment ) {
if ( 'image/svg+xml' === $attachment->post_mime_type ) {
$url = wp_get_attachment_url( $attachment->ID );
$reponse['sizes']['thumbnail'] = array(
'url' => $url,
'width' => 150,
'height' => 150,
);
}
return $reponse;
}
add_filter( 'wp_prepare_attachment_for_js', 'studio_miniature_svg', 10, 2 );
Je n’ai jamais rencontré de client qui refuse cette contrainte une fois expliquée : personne ne veut être responsable d’une faille XSS exploitée via le logo qu’il vient d’importer lui-même.
En résumé
Autoriser le SVG sans le nettoyer n’est pas une demi-mesure : c’est une absence totale de protection, puisque upload_mimes ne fait qu’ouvrir la porte sans jamais inspecter le contenu. La sanitization via une bibliothèque dédiée, couplée à une restriction par rôle, transforme cette ouverture en fonctionnalité réellement sûre.