Un expert-comptable indépendant, qui accompagne une vingtaine de PME locales, avait un besoin précis : que chaque client dépose ses relevés bancaires et factures directement depuis son espace WordPress, sans passer par des pièces jointes e-mail dispersées, tout en étant certain qu’un client ne puisse jamais accéder, même par erreur d’URL, aux documents d’un autre client.
La solution retenue n’a pas nécessité un extranet complexe avec système de comptes tiers : WordPress fournit déjà, via son système de rôles et de capacités personnalisées, tout ce qu’il faut pour construire cette isolation, à condition de ne pas se contenter du système de rôles par défaut.
Le piège du dossier uploads standard
La première tentation, la plus rapide à développer, consiste à utiliser le système de médias natif de WordPress : chaque client dépose son fichier via un champ d’upload standard, qui atterrit dans wp-content/uploads/. Ce dossier, servi directement par le serveur web sans passer par PHP, rend chaque fichier accessible par son URL directe à quiconque la devine ou la trouve indexée, indépendamment de toute vérification de connexion ou de rôle.
Pour des documents comptables, cette exposition est inacceptable, même si l’URL contient un nom de fichier peu prévisible : un identifiant devinable ou une fuite accidentelle de lien suffirait à exposer les relevés bancaires d’un client à toute personne extérieure.
Une capacité personnalisée par espace client

La structure retenue attribue à chaque compte client un rôle dédié, porteur d’une capacité personnalisée qui encode l’identifiant du cabinet virtuel auquel il appartient, via une métadonnée utilisateur plutôt qu’un rôle distinct par client, ce qui resterait ingérable à vingt-quatre clients et plus.
add_action( 'init', function () {
$role = get_role( 'client_cabinet' );
if ( $role && ! $role->has_cap( 'deposer_justificatif' ) ) {
$role->add_cap( 'deposer_justificatif' );
}
} );
function cabinet_utilisateur_peut_acceder_dossier( int $user_id, int $dossier_id ): bool {
if ( ! user_can( $user_id, 'deposer_justificatif' ) ) {
return false;
}
$dossier_proprietaire = get_post_meta( $dossier_id, 'client_id', true );
return (int) $dossier_proprietaire === $user_id;
}
Chaque document déposé est enregistré comme un article d’un type de contenu personnalisé justificatif, avec une métadonnée client_id qui porte l’identifiant du client propriétaire. La capacité deposer_justificatif autorise le dépôt, mais l’accès à un document précis passe systématiquement par une vérification supplémentaire de propriété, indépendante du rôle.
Servir les fichiers hors du dossier public
Les fichiers eux-mêmes ne sont jamais stockés dans le dossier uploads standard, mais dans un répertoire séparé, en dehors de la racine web accessible directement, ou protégé par une règle de serveur qui bloque l’accès direct. Le téléchargement passe systématiquement par un script PHP qui vérifie la propriété avant de servir le fichier :
add_action( 'template_redirect', function () {
if ( ! isset( $_GET['telecharger_justificatif'] ) ) {
return;
}
$dossier_id = absint( $_GET['telecharger_justificatif'] );
$user_id = get_current_user_id();
if ( ! cabinet_utilisateur_peut_acceder_dossier( $user_id, $dossier_id ) ) {
wp_die( 'Accès refusé.', 403 );
}
$chemin = get_post_meta( $dossier_id, 'chemin_fichier', true );
if ( ! $chemin || ! file_exists( $chemin ) ) {
wp_die( 'Document introuvable.', 404 );
}
header( 'Content-Type: application/pdf' );
header( 'Content-Disposition: attachment; filename="justificatif.pdf"' );
readfile( $chemin );
exit;
} );
Ce script ne fait confiance à aucune information transmise par le navigateur pour établir l’accès : il revérifie systématiquement, à chaque téléchargement, la relation entre l’utilisateur connecté et le document demandé, indépendamment de ce qu’affichait l’écran précédent.
Points de vigilance retenus
- Ne jamais faire confiance à l’affichage de l’interface pour la sécurité : un lien masqué dans le CSS reste accessible directement par son URL.
- Vérifier la propriété du document à chaque téléchargement, pas seulement lors de la génération de la liste des documents visibles.
- Interdire l’indexation du dossier de stockage par le serveur web, en complément de la vérification applicative.
Le principe que j’applique sur tout espace de dépôt de documents sensibles : la vérification d’accès doit se refaire au moment précis du téléchargement, jamais seulement au moment où le lien a été affiché à l’écran.
En résumé
Une capacité personnalisée combinée à une vérification de propriété au moment du téléchargement suffit à construire un espace de dépôt cloisonné entre clients, sans extranet dédié ni système de comptes tiers. La comptabilité elle-même, tenue par le cabinet dans son propre logiciel métier, reste en dehors du périmètre de cette extension.