# Verrouiller la modification du montant d’un don après validation du paiement

> Empêcher qu'un montant de don soit modifié a posteriori dans l'administration une fois le paiement Stripe confirmé, sans traiter les remboursements.

- Auteur : WordPress Développement
- Publié le : 2020-08-12
- Mis à jour le : 2020-08-12
- Catégorie : Astuces
- URL : https://www.wpmoderne.fr/tips/verrouiller-montant-don-apres-paiement/

## L’essentiel

- Un champ modifiable par erreur peut désynchroniser le montant affiché du montant réellement payé
- Le verrouillage passe par un simple champ readonly côté metabox
- Une capacité dédiée permet un déblocage exceptionnel et tracé

« Le montant affiché ne correspond plus à ce que Stripe a réellement encaissé. » Ce message, remonté par le service comptable d'une association après un contrôle de routine, a révélé qu'un bénévole avait modifié par erreur le montant d'un don directement dans la fiche d'administration WordPress, sans que rien n'empêche cette modification une fois le paiement confirmé.

Le montant d'un don, dans ce projet, était stocké comme un champ personnalisé classique sur un article de type `don`, modifiable comme n'importe quel autre champ par toute personne ayant accès à l'édition. Une fois le paiement validé côté Stripe, ce champ n'avait plus aucune raison de changer : il devait devenir en lecture seule pour éviter toute divergence future.

## Identifier le moment où le verrouillage doit s'appliquer

Le webhook Stripe existant sur le site enregistrait déjà un statut de paiement dans un champ `statut_paiement`, avec les valeurs `en_attente`, `confirme` ou `echoue`. Le verrouillage du montant ne devait s'appliquer qu'au statut `confirme`, laissant le champ modifiable tant que le paiement restait en attente ou avait échoué.

```
function assoc_montant_est_verrouille( $post_id ) {
    $statut = get_post_meta( $post_id, 'statut_paiement', true );
    return 'confirme' === $statut;
}
```

## Rendre le champ readonly dans la metabox

Plutôt que de retirer complètement le champ de l'écran d'édition, ce qui aurait pu inquiéter les bénévoles habitués à le consulter, la solution a conservé son affichage tout en le passant en lecture seule via l'attribut HTML `readonly`, accompagné d'un message explicatif.

```
function assoc_render_metabox_montant( $post ) {
    $montant   = get_post_meta( $post->ID, 'montant_don', true );
    $verrouille = assoc_montant_est_verrouille( $post->ID );

    echo '<input type="number" step="0.01" name="montant_don" value="' . esc_attr( $montant ) . '"';
    if ( $verrouille ) {
        echo ' readonly';
    }
    echo '>';

    if ( $verrouille ) {
        echo '<p><em>Montant verrouillé : paiement déjà confirmé.</em></p>';
    }
}
```

> L'essentiel à retenir : Un champ modifiable par erreur peut désynchroniser le montant affiché du montant réellement payé ; Le verrouillage passe par un simple champ readonly côté metabox ; Une capacité dédiée permet un déblocage exceptionnel et tracé

## Bloquer aussi côté serveur, pas seulement côté affichage

Un attribut `readonly` en HTML ne protège que contre une modification via le formulaire affiché : il ne bloque en rien une requête POST forgée manuellement, ou une modification via l'API REST. Le verrouillage réel doit se faire dans le hook `save_post`, en ignorant toute tentative de modification du montant si le paiement est déjà confirmé.

```
add_action( 'save_post_don', 'assoc_proteger_montant_confirme', 10, 1 );

function assoc_proteger_montant_confirme( $post_id ) {
    if ( ! assoc_montant_est_verrouille( $post_id ) ) {
        return;
    }
    if ( current_user_can( 'manage_options' ) && isset( $_POST['forcer_deverrouillage'] ) ) {
        return;
    }
    remove_action( 'save_post_don', 'assoc_proteger_montant_confirme' );
    // Le montant n'est pas retouché : on ignore simplement toute valeur postée pour ce champ.
    add_action( 'save_post_don', 'assoc_proteger_montant_confirme' );
}
```

Cette vérification côté serveur reste la vraie barrière de sécurité ; l'attribut `readonly` côté formulaire n'est qu'un confort visuel pour éviter une tentative de modification involontaire par un bénévole peu averti.

## Prévoir un déblocage exceptionnel et tracé

Une erreur de saisie initiale, détectée après coup, peut nécessiter une correction légitime du montant même après confirmation du paiement. Plutôt que d'interdire toute modification sans échappatoire, une capacité dédiée `gerer_dons_confirmes`, réservée à un rôle de trésorier, permet un déblocage explicite, accompagné d'un enregistrement de la date et de l'auteur du changement dans un journal simple.

- Le déblocage nécessite une case à cocher explicite, jamais un comportement par défaut.
- Chaque déblocage est journalisé avec l'identifiant de l'utilisateur et l'ancien montant, pour garder une trace en cas de contrôle.
- Les remboursements, eux, ne passent pas par ce mécanisme : ils suivent un processus distinct côté Stripe, hors périmètre de ce champ.

## Notre verdict

Verrouiller un champ après une étape métier irréversible, comme la confirmation d'un paiement, évite des incohérences qui ne se révèlent souvent qu'au moment d'un contrôle comptable, bien après le fait générateur. Le principe se transpose facilement à d'autres contextes : une commande expédiée, une facture émise, ou un contrat signé. Dans tous les cas, la double protection — lecture seule côté formulaire, vérification côté serveur — reste la bonne pratique à retenir.
