On parle souvent des nouvelles Web APIs comme si elles étaient réservées aux grosses applications SaaS… et pourtant, certaines d’entre elles ont un potentiel énorme pour nos workflows WordPress au quotidien. L’API File System Access en fait partie : elle permet de lire et d’écrire des fichiers locaux directement depuis le navigateur, sans passer par le serveur. Dans cet article, on va voir comment l’intégrer concrètement dans un bloc Gutenberg custom — et surtout dans quels cas ça vaut vraiment le coup (et quand éviter de s’en servir).
L’API File System Access : ce que c’est et pourquoi ça change tout
Avant d’aller plus loin, on doit poser les bases. L’API File System Access (parfois encore appelée Native File System API dans les anciennes docs) est une Web API moderne qui permet à une application web d’interagir directement avec le système de fichiers local de l’utilisateur. Lire, écrire, créer, supprimer des fichiers… le tout sans passer par un serveur. C’est un changement de paradigme assez radical pour le web.
Principe de fonctionnement et support navigateur
Le principe est simple : au lieu d’obliger l’utilisateur à uploader un fichier vers un serveur distant pour le traiter, puis le re-télécharger, on travaille directement avec les fichiers locaux dans le navigateur. L’application web accède au système de fichiers en temps réel — un peu comme le ferait une application native.
Côté support navigateur, la situation est la suivante (et elle évolue vite) :
- Chrome et Edge : support complet depuis 2021-2022, c’est la combinaison la plus fiable aujourd’hui
- Safari : support partiel via l’Origin Private File System (OPFS), mais les méthodes de sélection de fichiers du système arrivent progressivement
- Firefox : pas encore de support des méthodes
showOpenFilePicker()& co sur le système de fichiers natif, l’OPFS est supporté en revanche
Donc oui, il faut composer avec ces disparités. Mais pour un outil orienté développeurs (et la grande majorité utilise Chrome ou Edge), c’est tout à fait viable en production.
Permissions, sécurité et modèle de confiance
C’est probablement la partie la plus importante. Et c’est aussi ce qui distingue vraiment cette API des anciennes approches.
Avec input[type=file] ou la FileReader API, on pouvait lire un fichier — mais de façon ponctuelle, sans persistance, et sans accès en écriture. L’utilisateur choisissait un fichier, le navigateur lisait son contenu, terminé.
Avec l’API File System Access, le modèle est radicalement différent :
- L’application demande l’accès via un dialogue natif du système d’exploitation (le vrai explorateur de fichiers, pas une interface web)
- L’utilisateur choisit explicitement le fichier ou le dossier à exposer
- Le navigateur mémorise cette permission pour la session (et potentiellement au-delà, si l’utilisateur l’accepte)
Aucun accès silencieux n’est possible. L’utilisateur garde le contrôle total. C’est ce modèle de confiance explicite qui rend cette API acceptable d’un point de vue sécurité, même pour des opérations d’écriture.
Ce que cette API apporte concrètement aux développeurs web
Trois méthodes sont au cœur de l’API :
window.showOpenFilePicker(): ouvre un dialogue pour sélectionner un ou plusieurs fichiers en lecturewindow.showSaveFilePicker(): permet de sauvegarder un fichier directement sur le disque (avec choix de l’emplacement)window.showDirectoryPicker(): donne accès à un dossier entier, avec la possibilité de lister, lire et écrire tous les fichiers qu’il contient
Pour un développeur qui travaille dans Gutenberg, ça ouvre des possibilités très concrètes : éditer un fichier CSS local, synchroniser des templates, gérer des assets sans quitter l’interface. Et pourtant, cette API reste étonnamment peu documentée dans la sphère WordPress francophone. On parle beaucoup de l’API REST, des blocs FSE, des hooks… mais quasiment pas de ça. C’est dommage, parce que le potentiel pour les outils de développement côté éditeur est vraiment là.
Intégrer l’API File System Access dans un bloc Gutenberg custom
On arrive au cœur du sujet. Maintenant qu’on a compris ce qu’est l’API File System Access et pourquoi elle est intéressante dans un contexte WordPress, passons aux choses sérieuses : créer un bloc Gutenberg personnalisé qui l’exploite vraiment. Je vais détailler chaque étape, avec des extraits de code commentés pour que vous puissiez adapter ça à votre propre cas d’usage.
Créer le bloc React avec la gestion des permissions fichier
Tout commence par un registerBlockType classique. Rien de magique ici — on pose les bases d’un bloc Gutenberg standard, avec ses attributs et son composant Edit. C’est dans ce composant qu’on va brancher nos appels à l’API.
import { registerBlockType } from '@wordpress/blocks';
import { Button, TextareaControl, Notice } from '@wordpress/components';
import { useState } from '@wordpress/element';
registerBlockType('mon-plugin/file-editor', {
title: 'Éditeur de fichier local',
icon: 'media-text',
category: 'widgets',
attributes: {
fileContent: { type: 'string', default: '' },
fileName: { type: 'string', default: '' },
},
edit: EditComponent,
save: () => null, // Bloc dynamique, rendu côté serveur ou inutile en front
});
Un point important : on déclare save à null (ou un composant vide). Ce bloc n’a pas vocation à être rendu côté front-end WordPress — c’est un outil réservé à l’éditeur admin. On y reviendra.
Pour la gestion des permissions, l’API File System Access fonctionne uniquement sur action utilisateur directe (un clic, par exemple). Pas question d’appeler showOpenFilePicker() au chargement du composant — le navigateur le refusera silencieusement. Donc on attache toujours ces appels à un handler de bouton.
Lire et afficher un fichier local dans l’éditeur
La lecture d’un fichier se fait en trois étapes : ouvrir le dialogue natif via showOpenFilePicker(), récupérer le FileSystemFileHandle, puis lire le contenu avec .getFile() et .text(). En pratique, ça donne ça :
function EditComponent({ attributes, setAttributes }) {
const { fileContent, fileName } = attributes;
const [fileHandle, setFileHandle] = useState(null);
const [error, setError] = useState(null);
const handleOpenFile = async () => {
try {
// Ouvre le dialogue de sélection de fichier natif
const [handle] = await window.showOpenFilePicker({
types: [{ description: 'Fichiers texte', accept: { 'text/*': ['.txt', '.md', '.js', '.php'] } }],
multiple: false,
});
const file = await handle.getFile();
const content = await file.text();
// On stocke le handle en state local (non sérialisable, donc pas dans les attributs)
setFileHandle(handle);
setAttributes({ fileContent: content, fileName: file.name });
setError(null);
} catch (err) {
if (err.name !== 'AbortError') {
setError('Impossible de lire le fichier : ' + err.message);
}
// Si AbortError : l'utilisateur a juste fermé le dialogue, on ne fait rien
}
};
return (
<div>
<Button variant="primary" onClick={handleOpenFile}>
Ouvrir un fichier local
</Button>
{fileName && <p>Fichier ouvert : <strong>{fileName}</strong></p>}
<TextareaControl
label="Contenu du fichier"
value={fileContent}
onChange={(val) => setAttributes({ fileContent: val })}
rows={15}
/>
</div>
);
}
Notez qu’on stocke le fileHandle dans un useState local et non dans les attributs du bloc. C’est intentionnel : les handles ne sont pas sérialisables en JSON, donc ils disparaissent au rechargement de la page. C’est une limitation à bien avoir en tête.
Écrire et sauvegarder des modifications directement sur le disque
C’est là que ça devient vraiment intéressant. On peut soit utiliser createWritable() sur un handle existant (si l’utilisateur a déjà ouvert le fichier), soit appeler showSaveFilePicker() pour choisir une destination. Dans les deux cas, il faut demander la permission readwrite explicitement.
const handleSaveFile = async () => {
try {
let targetHandle = fileHandle;
// Si pas de handle en mémoire, on ouvre un dialogue "Enregistrer sous"
if (!targetHandle) {
targetHandle = await window.showSaveFilePicker({
suggestedName: fileName || 'nouveau-fichier.txt',
types: [{ description: 'Fichier texte', accept: { 'text/plain': ['.txt'] } }],
});
}
// Vérification de la permission en écriture
const permission = await targetHandle.requestPermission({ mode: 'readwrite' });
if (permission !== 'granted') {
setError('Permission d\'écriture refusée.');
return;
}
// Création du stream d'écriture et sauvegarde
const writable = await targetHandle.createWritable();
await writable.write(fileContent);
await writable.close();
setError(null);
// Petit feedback utilisateur (vous pouvez utiliser un Notice Gutenberg ici)
alert('Fichier sauvegardé avec succès !');
} catch (err) {
if (err.name !== 'AbortError') {
setError('Erreur lors de la sauvegarde : ' + err.message);
}
}
};
La méthode createWritable() écrase le fichier existant par défaut. Si vous voulez ajouter du contenu à la suite, passez { keepExistingData: true } en option — mais dans notre cas d’éditeur, on veut bien réécrire l’intégralité du fichier.
Gestion des erreurs, fallbacks et compatibilité
Soyons réalistes : cette API ne fonctionne pas partout. Firefox ne la supporte toujours pas à l’heure où j’écris ces lignes, et Safari reste à la traîne. Donc avant tout, une feature detection s’impose :
const isFileSystemAccessSupported = 'showOpenFilePicker' in window;
On peut conditionner l’affichage du bouton principal à cette vérification, et proposer un fallback propre pour les navigateurs non compatibles :
// Fallback : téléchargement classique via Blob
const handleDownloadFallback = () => {
const blob = new Blob([fileContent], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName || 'fichier.txt';
a.click();
URL.revokeObjectURL(url);
};
Pour la lecture sans File System Access, un simple <input type="file"> déclenché programmatiquement fait très bien l’affaire. Ce n’est pas aussi élégant, mais ça couvre les cas où le navigateur ne suit pas.
Côté erreurs, les cas à gérer sont principalement trois :
AbortError: l’utilisateur a fermé le dialogue sans choisir de fichier. On ignore silencieusement.NotAllowedError: permission refusée. On affiche un message clair et on propose le fallback.- Erreurs inattendues : réseau, fichier verrouillé, etc. On log et on informe l’utilisateur.
Et pour finir, un rappel fondamental : ce bloc ne fonctionnera jamais côté front-end WordPress. L’API File System Access n’existe que dans le contexte navigateur, et le save() du bloc ne devrait rien rendre de significatif côté public. C’est un outil de développement et de productivité, pensé pour l’interface d’administration. Pas une fonctionnalité à exposer à vos visiteurs.
Cas d’usage réels et limites à connaître
Bon, maintenant qu’on a vu comment intégrer l’API File System Access dans un bloc Gutenberg, parlons de ce qu’on peut vraiment en faire au quotidien. Parce que la technique, c’est bien — mais savoir quand et pourquoi l’utiliser, c’est encore mieux.
Édition de fichiers de configuration sans quitter le navigateur
C’est probablement le cas d’usage qui m’a le plus convaincu. Quand on développe un thème, on jongle en permanence entre l’éditeur WordPress, son terminal et son éditeur de code. Avec l’API File System Access, on peut construire un bloc ou un panel dédié dans Gutenberg pour éditer directement theme.json, ou même des fichiers de traduction .po/.pot, sans sortir du navigateur.
Le gain de temps est réel : on charge le fichier, on modifie la valeur qui nous intéresse, on écrit. Aucun aller-retour serveur, aucun FTP. C’est du local pur.
Prototype d’un éditeur de block.json intégré
Voilà un projet qui tient vraiment la route pour un plugin de développement : un éditeur de block.json directement dans l’interface Gutenberg. On sélectionne le fichier via showOpenFilePicker(), on affiche les champs dans un formulaire React (nom du bloc, attributs, supports…), et on écrit le résultat avec createWritable(). C’est exactement le genre d’outil qui n’existe pas encore dans l’écosystème, et qui serait pourtant très utile.
Import/export de contenu structuré vers des Custom Post Types
Autre cas concret : l’import de données depuis des fichiers JSON ou CSV locaux vers des Custom Post Types. Au lieu de passer par une interface d’import classique avec upload côté serveur, on lit directement le fichier en local, on parse son contenu, et on l’envoie via l’API REST de WordPress. L’export fonctionne aussi très bien dans l’autre sens — générer un CSV depuis une requête wp.data et le proposer au téléchargement via createWritable().
C’est particulièrement utile pour des migrations ou des synchronisations ponctuelles dans un contexte de développement.
Outils de debug et génération de code dans l’éditeur
On peut aussi imaginer des outils de debug plus élaborés : un bloc qui inspecte un fichier de log local, ou un générateur de code qui produit des fichiers PHP ou JS à la volée depuis l’interface Gutenberg. Ça reste un usage de niche, mais pour un workflow de développement, c’est franchement pratique. Et comme Gutenberg est une SPA React, l’intégration de ce type d’interaction est très naturelle.
Les limites à ne pas ignorer
Maintenant, soyons honnêtes : cette API a ses contraintes, et il vaut mieux les connaître avant de se lancer.
Contexte sécurisé obligatoire. L’API File System Access ne fonctionne que dans un contexte HTTPS — ou localhost pour le développement local. Pas question de l’utiliser sur un environnement HTTP classique.
Permissions non persistantes par défaut. Les autorisations accordées par l’utilisateur sont liées à la session navigateur. Si l’utilisateur ferme l’onglet, les permissions tombent. Il existe une solution via le StorageManager et l’Origin Private File System (OPFS), mais ça demande une implémentation supplémentaire.
Inutilisable dans un iframe sandboxé. Si votre bloc ou votre plugin est chargé dans un contexte iframe avec des restrictions sandbox, l’API sera bloquée. Attention donc aux intégrations tierces qui utilisent ce type d’architecture.
Pas adapté aux utilisateurs finaux non techniques. C’est peut-être la limite la plus importante à garder en tête. Cette API est idéale pour des outils internes, des plugins de développement, des workflows d’agence — mais pas pour un utilisateur lambda qui gère son blog WordPress. Le dialogue de sélection de fichier natif peut déjà dérouter quelqu’un qui n’est pas à l’aise avec son système de fichiers.
L’Origin Private File System : une alternative à explorer
Pour les cas où on a besoin de persistance — stocker des fichiers entre deux sessions sans redemander les permissions — l’OPFS (Origin Private File System) est une piste intéressante. Il s’agit d’un système de fichiers sandboxé, propre à l’origine du site, que le navigateur gère de façon transparente. Pas d’accès au système de fichiers réel de l’utilisateur, mais une vraie persistance côté navigateur. C’est une alternative sérieuse pour certains cas d’usage spécifiques.
Au final, cette API est encore jeune et son support reste limité à Chromium pour l’essentiel. Mais la trajectoire est bonne, et le support progresse. WordPress et Gutenberg, en tant que SPA React, constituent un terrain d’expérimentation idéal. Les possibilités sont là — il suffit de commencer à creuser.
