Environnement
-
Version de WP-Discourse : 2.5.7
-
Version de Discourse : 3.5.0.beta5-dev
-
Version de WordPress : 6.9
-
Hébergement : WP Engine (multisite WordPress)
-
Instance Discourse : Auto-hébergée / Hébergement Discourse (forum.avweb.com)
Résumé
Les articles publiés depuis WordPress créent des sujets sur Discourse avec succès, mais discourse_permalink est stocké comme une chaîne vide dans les métadonnées de l’article. Cela provoque l’échec silencieux de toutes les synchronisations de commentaires ultérieures, car sync_comments() dans discourse-comment.php s’arrête prématurément lorsque le permalien est vide. L’ID du sujet Discourse et le drapeau de synchronisation webhook sont écrits correctement — seul le permalien est manquant.
Nous avons identifié 174 articles affectés sur un seul site de notre réseau multisite. Le problème semble avoir commencé vers la mi-décembre 2025.
Étapes pour reproduire
-
Publier un article WordPress configuré pour créer un sujet Discourse
-
Le sujet est créé avec succès sur Discourse
-
discourse_topic_idest enregistré dans les métadonnées de l’article ✓ -
wpdc_sync_post_commentsest défini sur1(le webhook se déclenche correctement) ✓ -
discourse_permalinkest enregistré comme une chaîne vide ✗ -
discourse_comments_rawn’est jamais écrit (la synchronisation ne se termine jamais)
Comportement attendu
discourse_permalink devrait contenir l’URL complète du sujet Discourse (par exemple, The China Chickens Come Home - AVweb - News Discussion - AVweb.com Discussion) après la création réussie du sujet.
Comportement actuel
discourse_permalink existe en tant que clé de métadonnée mais sa valeur est vide. Chaque appel subséquent à sync_comments() atteint cette garde à la ligne 209 de lib/discourse-comment.php et retourne prématurément :
if ( ! $discourse_permalink ) {
return 0;
}
Comme la synchronisation ne se termine jamais, discourse_last_sync n’est jamais écrit, de sorte que le plugin tente à nouveau à chaque chargement de page — et échoue à chaque fois.
Diagnostic
Nous avons retracé le problème via le chemin de code suivant :
-
DiscourseCommentFormatter::format()appelledo_action('wpdc_sync_discourse_comments')qui déclencheDiscourseComment::sync_comments() -
sync_comments()vérifiediscourse_permalink— le trouve vide, retourne 0 -
format()vérifie ensuitediscourse_comments_rawdans les métadonnées de l’article — le trouve manquant, retournebad_response_html() -
Les commentaires ne s’affichent jamais pour l’article affecté
Le flux de création de sujet écrit discourse_topic_id mais ne parvient pas à persister le permalien. Nous avons pu reconstruire les permaliens corrects en interrogeant l’API Discourse à l’adresse /t/{topic_id}.json et en les réécrivant dans les métadonnées de l’article, ce qui a résolu la synchronisation pour les 174 articles.
Solution de contournement
Nous avons écrit un script de réparation WP-CLI qui :
-
Trouve les articles où
wpdc_sync_post_comments = 1maisdiscourse_comments_rawest manquant -
Récupère le slug du sujet depuis
/t/{topic_id}.json -
Reconstruit et enregistre le permalien
-
Récupère et enregistre les commentaires depuis
/t/{slug}/{topic_id}/wordpress.json
Nous exécutons ceci sur une tâche cron planifiée à titre de mesure temporaire.
Problèmes supplémentaires trouvés lors de l’enquête
1. Verrouillage MySQL global provoquant des échecs de synchronisation silencieux
Fichier : lib/discourse-comment.php, ligne 176
$got_lock = $wpdb->get_row( "SELECT GET_LOCK( 'discourse_lock', 0 ) got_it" );
sync_comments() utilise un seul verrou MySQL global (discourse_lock) partagé entre tous les articles de l’installation entière. Le délai d’attente est de 0 (non bloquant), donc si un article est en cours de synchronisation, tous les autres articles sautent silencieusement leur synchronisation — pas de journalisation, pas de nouvelle tentative.
Sur un site à fort trafic publiant plusieurs articles par jour, cela crée une condition de concurrence où les articles perdent constamment le verrou et ne se synchronisent jamais. Combiné à la période de synchronisation de 10 minutes, un article peut rester bloqué de façon permanente s’il perd le verrou lors de ses premières tentatives et que le problème de permalien vide empêche les synchronisations futures.
Correction suggérée : Utiliser un verrou par article :
$got_lock = $wpdb->get_row( "SELECT GET_LOCK( 'discourse_lock_{$post_id}', 0 ) got_it" );
Avec la libération correspondante :
$wpdb->get_results( "SELECT RELEASE_LOCK( 'discourse_lock_{$post_id}' )" );
2. Double échappement de discourse_comments_raw
Fichier : lib/discourse-comment.php, ligne 222
update_post_meta( $post_id, 'discourse_comments_raw', esc_sql( $raw_body ) );
update_post_meta() utilise $wpdb->prepare() en interne, donc l’encapsulation de la valeur dans esc_sql() provoque un double échappement. Sur plusieurs cycles de synchronisation, les guillemets dans le corps JSON accumulent des caractères d’échappement (\\" → \\\\\\" → \\\\\\\\\\\\\\"), jusqu’à ce que le JSON devienne impossible à analyser.
Correction suggérée :
update_post_meta( $post_id, 'discourse_comments_raw', $raw_body );
Impact
Ces problèmes s’additionnent : le permalien vide empêche la synchronisation initiale, le verrou global empêche la récupération, et le double échappement peut corrompre les données des articles qui parviennent à se synchroniser. Sur notre installation, 174 articles (environ 2 mois de contenu) ont été affectés avant que nous n’identifiions la cause première.