Skip to main content
Retour aux billets
Sept. 2026 à aujourd'hui9 min de lecture

Des pointages tapés au bord du terrain, sur le site avant le début de la partie suivante

Montreal United offre du mentorat et du sport organisé aux jeunes de Montréal, dont deux tournois de basketball annuels. J'ai repris leur site WordPress bilingue en septembre 2026 et je leur ai bâti une deuxième chose qu'ils avaient demandée : une façon de gérer un tournoi depuis un téléphone, au gymnase. Les divisions, les poules, les parties générées et les pointages s'entrent sur le téléphone, et la page publique les reprend d'elle-même, en anglais et en français. La partie que j'ai la plus soignée est celle qui refuse, parce que la personne qui s'en sert est debout à la table des marqueurs avec une partie qui se termine derrière elle.

WordPressDiviWPMLPWABilingualClient workLong-term

Montreal United est un organisme sans but lucratif qui offre du mentorat et du sport organisé aux jeunes de Montréal. Deux tournois de basketball ancrent leur année : le Lindsay A. Burnett Invitational et No Politics, Just Ball. J'ai repris le site web en septembre 2026 et je l'exploite depuis. C'est WordPress sur Divi avec WPML, ce qui veut dire que chaque page existe deux fois, une fois en anglais et une fois en français, et que les deux doivent rester synchronisées sinon le côté français pourrit en silence.

La page d'accueil de Montreal United : un ballon de basketball en noir et blanc traversant un panier, la marque-mot, et la phrase sur le mentorat et le développement offerts aux jeunes de Montréal par le sport organisé.
Le site en ligne. Un organisme sans but lucratif géré par des bénévoles, deux tournois annuels, et chaque page en anglais et en français.

La moitié qui n'est pas le site web

La consigne qui comptait ne portait pas du tout sur le site. Pendant un tournoi, les pointages existent sur papier à la table des marqueurs et nulle part ailleurs, jusqu'à ce que quelqu'un rentre à la maison et les saisisse. Les parents dans le gymnase rafraîchissent une page qui n'a pas changé depuis jeudi. Ce que l'organisme voulait, c'était pouvoir mettre à jour les équipes et les pointages depuis un téléphone, sur le plancher, et que le site s'occupe du reste. La seconde moitié de ce mandat est donc un outil : une extension WordPress avec ses propres tables et un espace REST réservé aux administrateurs, jumelée à une application web progressive qui s'installe à partir d'un lien. Pas de magasin d'applications, pas de file d'attente de révision, pas d'étape de compilation de leur côté. On ouvre un lien, on l'ajoute à l'écran d'accueil, et ça se comporte comme une application.

L'application de tournoi sur un téléphone : la bannière du L.A.B Invitational, une carte du tournoi 2026 marquée comme étant sur le site avec ses dates et ses huit divisions, et un formulaire pour créer un nouveau tournoi.
Le premier écran de l'application. Chaque carte de tournoi dit clairement si elle est sur le site ou non, parce que c'est la seule chose de cet écran qui a des conséquences en dehors du téléphone.

Un tournoi est un brouillon jusqu'à ce que quelqu'un en décide autrement

La personne qui s'en sert est debout à la table des marqueurs, avec une partie qui se termine derrière elle et un parent qui pose une question. Ce contexte a décidé l'essentiel de la conception. Chaque tournoi commence comme un brouillon, et le site public n'affiche jamais que les tournois publiés, donc rien de ce qu'on fait dans l'application n'atteint le site public avant d'avoir appuyé sur un bouton qui le dit. Il y a un tournoi d'essai en une touche qui se remplit de parties d'exemple à la date du jour, et il porte sur chaque écran une bannière disant qu'il n'est pas sur le site et qu'on peut tout essayer. Publier et retirer sont deux boutons explicites distincts derrière une confirmation, et la confirmation avertit quand un autre tournoi est déjà en ligne ou quand le nom ressemble à un essai. Effacer tous les pointages est annulable. Renommer une équipe est annulable.

Saisie d'un pointage sur le téléphone : deux noms d'équipes avec 61 et 58 dans de grandes cases, des boutons d'état pour prévu, en direct, final et forfait avec final sélectionné, et le jour, l'heure, le terrain et une note facultative en dessous.
La saisie du pointage. De grandes cibles, un état plutôt qu'une case à cocher, et la bannière d'essai toujours visible en haut, pour qu'on ne se demande jamais si c'est pour de vrai.

Se tromper de pointage est normal, donc corriger devait coûter aussi peu que saisir. Rouvrir une partie terminée affiche une note qui reconnaît l'erreur et permet de changer l'un ou l'autre des chiffres, et la carte enregistrée se met à jour immédiatement avec le gagnant en gras. La barre d'annulation est en haut de l'écran plutôt que dans un menu, parce que le moment où on en a besoin est celui où on a le moins envie de la chercher.

La liste des parties du jour après l'enregistrement : la partie terminée affiche 61 à 58 avec l'équipe gagnante en gras, une commande d'annulation en haut de l'écran, et les parties restantes en dessous, toujours en attente de pointage.
Enregistré. La partie terminée devient un résultat avec le gagnant en gras, et l'annulation reste à une touche en haut de l'écran aussi longtemps qu'elle est utile.

Les divisions, les poules, et les parties entre les deux

Un tournoi ici, c'est huit divisions par âge et par genre, chacune avec ses équipes, et l'édition 2026 a compté quatre-vingt-huit parties. L'application bâtit cette structure au lieu de demander à quelqu'un de la saisir : on ajoute les équipes à une division, on les répartit en poules par classement ou à la main, et on génère le tournoi à la ronde. Les classements sortent avec les bris d'égalité appliqués, et les parties croisées qui suivent résolvent leurs rangs à partir des résultats de poule au lieu de devoir être ressaisies. Regénérer est sans danger, parce que c'est un bouton distinct qui dit ce qu'il s'apprête à remplacer.

Une division ouverte sur le téléphone : six équipes portant chacune une lettre de poule et un rang, des commandes pour créer une poule ou répartir en poules par rang, et une section des parties en dessous avec une action de regénération.
Une division avec ses équipes, ses lettres de poule et ses rangs. Répartir en poules et générer l'horaire, c'est deux touches, et les deux sont réversibles.

Le moment qui justifie tout

Voici tout l'intérêt du projet en une phrase : un pointage tapé à la table des marqueurs est sur le site public avant le début de la partie suivante, et personne n'a rien fait pour que ça arrive. La page publique du tournoi se rafraîchit d'elle-même, donc le parent debout dans le gymnase avec un téléphone, et le grand-parent qui suit depuis une autre ville, voient le même chiffre dans la minute. Pas d'exportation, pas de téléversement, pas de bénévole devant un portable ce soir-là.

L'horaire public du tournoi dans un navigateur de bureau, montrant une partie terminée indiquant Wolves 55 à 52 Drop Off dans la liste du jeudi, arrivée depuis le téléphone sans qu'une personne recharge la page.
Le même pointage, sur la page publique, arrivé tout seul. Cette image vient d'une captation où le pointage a été entré sur un téléphone et où l'ordinateur l'a repris sans que personne y touche.

Les deux langues, sinon ça ne sort pas

Nous sommes à Montréal, l'organisme sert des familles dans les deux langues, et une page française en retard sur l'anglaise est pire qu'une absence de page française, parce qu'elle a l'air entretenue sans l'être. Les vues de tournoi sont donc bilingues à la source : le même horaire, les mêmes divisions, poules et classements s'affichent sur /tournament/ et /fr/tournoi/, avec les noms de divisions repris des termes français de l'organisme plutôt que devinés par une machine. La suite de validation vérifie que les dates de tournoi apparaissent sur les pages d'accueil, de contact et de tournoi dans les deux langues, pour qu'une modification qui ne met à jour que l'anglais échoue avant d'atteindre qui que ce soit.

La même page de tournoi en français sur /fr/tournoi/, avec l'horaire groupé sous jeudi 14 mai et vendredi 15 mai, et les filtres de division et de gymnase traduits.
Le côté français du même tournoi, rendu à partir des mêmes données. Les jours, les filtres et les noms de divisions sont traduits ; les pointages sont exactement les mêmes lignes.

La moitié ingrate : de 2,5 secondes à environ 150 millisecondes

Le site fait tourner trente-cinq extensions, et une requête non mise en cache passait environ 2,5 secondes dans WordPress avant d'envoyer un octet, dont environ 0,8 pour WooCommerce à lui seul. Le réflexe tentant est de commencer à supprimer. Le bon réflexe, pour un organisme bénévole qui dépend de ces extensions pour les inscriptions et les paiements, était de placer une mise en cache des pages devant et de laisser la pile tranquille. J'ai ajouté un préchauffeur qui reconstruit chaque page par lots, enregistre sa progression, revérifie l'ensemble à la fin d'un passage et recommence si quelque chose a effacé des pages en cours de route. Les vingt-quatre pages publiques sont maintenant servies depuis le cache en environ 150 millisecondes.

La page publique du tournoi sur ordinateur : le nom et les dates du tournoi, des onglets pour l'horaire, les divisions et le direct, des filtres par division et par gymnase, un lien d'impression, et l'horaire groupé par jour avec l'heure, la partie, la division et le terrain.
Ce que l'outil produit pour le public : l'horaire par jour, les divisions avec poules et classements, un onglet en direct, des filtres, et une vue d'impression pour ceux qui veulent encore du papier à l'entrée.

Ce qui a été difficile

Trois choses, dont aucune que j'aurais prévue. L'hébergeur refuse tout corps de requête au-delà d'un mégaoctet : Apache répond avant que PHP ne s'exécute, donc le point d'accès média ne peut tout simplement pas recevoir une photo prise directement avec un téléphone, ce qui est exactement ce que le client essaierait en premier. J'ai mesuré la limite, 1024 Ko acceptés et 1100 Ko refusés, puis j'ai écrit un téléversement par morceaux qui reconstitue le fichier à partir de plus petites pièces, vérifie le SHA-256 du résultat contre celui envoyé, et ne l'enregistre qu'ensuite. Deuxièmement, WPML traduit les fichiers joints, donc enregistrer une page française réécrit en silence chaque identifiant de galerie vers un jumeau français pointant sur les mêmes fichiers, ce qui fait échouer toute comparaison naïve de relecture sur chaque page française contenant une galerie. Troisièmement, le constructeur de pages lançait automatiquement la première vidéo d'un onglet, sans sourdine, dès qu'un visiteur ouvrait cet onglet, et comme cliquer sur l'onglet compte comme un geste de l'utilisateur, la politique de lecture automatique du navigateur ne l'arrêtait pas. Celui-là était en ligne et personne ne l'avait signalé.

Ce que j'ai appris

La fonctionnalité dont je suis le plus fier est celle qui ne fait rien. Un tournoi d'essai, un état brouillon, une confirmation qui lit la situation et avertit quand autre chose est déjà en ligne : rien de tout ça n'apparaît dans une liste de fonctionnalités, et c'est tout ça qui fait que quelqu'un s'en servira vraiment pendant un vrai tournoi au lieu d'attendre d'être rentré. La deuxième leçon est plus ancienne et je la réapprends sans cesse. Tout ce que j'ai livré ici est vérifié par un script qui s'exécute contre le site en ligne, maintenant 104 assertions dont un aller-retour effectué avec le compte du client, parce que sur un site bilingue le mode de défaillance n'est jamais une page cassée, c'est une page française qui a cessé de correspondre à l'anglaise il y a quatre semaines.

La suite

  • Les tournois 2027, les premiers où l'outil fera tourner une fin de semaine en direct dès la première partie, au lieu d'être testé contre une saison déjà terminée.
  • Faire relever la limite de requête d'un mégaoctet chez l'hébergeur, pour que le client puisse téléverser une photo directement depuis un téléphone sans que le contournement par morceaux serve de béquille.
  • Une galerie rotative de photos de tournoi sur les pages de tournoi, en attente des photos plutôt que du code.
  • Poursuivre le travail courant dont le site vit vraiment : le contenu, les dates de tournoi, les formulaires d'inscription à chaque cycle, les mises à jour de WordPress et des extensions, les sauvegardes et la surveillance.
Projet associé

Montreal United: bilingual WordPress site for a Montreal youth basketball non-profit, plus a phone tool that puts tournament scores on it live

Voir le projet