diff -ruN a/Nolan-make-it-real-vo/assets/mir.js b/Nolan-make-it-real-vo/assets/mir.js --- a/Nolan-make-it-real-vo/assets/mir.js 2026-09-25 08:30:36 +++ b/Nolan-make-it-real-vo/assets/mir.js 2026-09-25 11:41:30 @@ -191,12 +191,20 @@ var titre = modaleCreer.querySelector('.ni-mir-etape:not([hidden]) .ni-mir-modale-titre'); if (titre) { titre.setAttribute('tabindex', '-1'); titre.focus(); } } + /* Mots de plus de CFG.max_lettres lettres (seules les lettres comptent : « qu’on » = 4) */ + function motsTropLongs(p) { + var max = CFG.max_lettres || 10; + return mots(p).filter(function (m) { return (m.match(/\p{L}/gu) || []).length > max; }); + } function majCompteur() { var n = mots(saisie.value).length; var trop = n > CFG.max; - compteur.textContent = trop ? fmt(CFG.txt.trop, n - CFG.max) : (n === 1 ? fmt(CFG.txt.compteur_un, 1, CFG.max) : fmt(CFG.txt.compteur, n, CFG.max)); - compteur.classList.toggle('est-trop', trop); - btnComposer.disabled = n < 1 || trop; + var longs = motsTropLongs(saisie.value); + if (trop) { compteur.textContent = fmt(CFG.txt.trop, n - CFG.max); } + else if (longs.length) { compteur.textContent = fmt(CFG.txt.mot_trop_long, '« ' + longs.join(' », « ') + ' »'); } + else { compteur.textContent = n === 1 ? fmt(CFG.txt.compteur_un, 1, CFG.max) : fmt(CFG.txt.compteur, n, CFG.max); } + compteur.classList.toggle('est-trop', trop || longs.length > 0); + btnComposer.disabled = n < 1 || trop || longs.length > 0; } saisie.addEventListener('input', majCompteur); modaleCreer.querySelectorAll('.ni-mir-exemple').forEach(function (b) { diff -ruN a/Nolan-make-it-real-vo/nolan-make-it-real-vo.php b/Nolan-make-it-real-vo/nolan-make-it-real-vo.php --- a/Nolan-make-it-real-vo/nolan-make-it-real-vo.php 2026-09-25 08:30:36 +++ b/Nolan-make-it-real-vo/nolan-make-it-real-vo.php 2026-09-25 11:41:30 @@ -3,7 +3,7 @@ * Plugin Name: Nolan-make-it-real-vo * Plugin URI: https://geraldmorales.eu * Description: Expérience participative : proposez une phrase de neuf mots maximum, votez pour vos préférées, Nolan Izreal crée l'œuvre. - * Version: 1.7.2 + * Version: 1.7.3 * Author: Gérald Morales * Author URI: https://geraldmorales.eu * Text Domain: nolan-make-it-real-vo @@ -111,6 +111,7 @@ define( 'NI_MIR_DOSSIER', plugin_dir_path( __FILE__ ) ); define( 'NI_MIR_URL', plugin_dir_url( __FILE__ ) ); define( 'NI_MIR_MAX_MOTS', 9 ); +define( 'NI_MIR_MAX_LETTRES', 10 ); // lettres par mot (apostrophes, traits d'union et ponctuation non comptés) define( 'NI_MIR_PAR_PAGE', 12 ); require_once __DIR__ . '/nolanizreal-make-it-real-commande.php'; define( 'NI_MIR_FRISE_MIN', 5 ); // à partir de ce nombre de phrases, la galerie devient un ticker défilant @@ -246,7 +247,8 @@ 'fermer' => array( 'fr' => 'Fermer', 'en' => 'Close' ), 'erreur' => array( 'fr' => 'Une erreur est survenue. Réessayez dans un instant.', 'en' => 'Something went wrong. Please try again in a moment.' ), 'erreur_email' => array( 'fr' => 'Adresse e-mail invalide.', 'en' => 'Invalid e-mail address.' ), - 'erreur_phrase' => array( 'fr' => 'Votre phrase doit contenir entre 1 et 9 mots, sans lien.', 'en' => 'Your sentence must be 1 to 9 words, without links.' ), + 'erreur_phrase' => array( 'fr' => 'Votre phrase doit contenir entre 1 et 9 mots de 10 lettres maximum, sans lien.', 'en' => 'Your sentence must be 1 to 9 words of 10 letters at most, without links.' ), + 'mot_trop_long' => array( 'fr' => 'Chaque mot doit faire 10 lettres maximum. Trop long : %s.', 'en' => 'Each word must be 10 letters at most. Too long: %s.' ), 'erreur_prenom' => array( 'fr' => 'Indiquez un prénom ou un pseudo.', 'en' => 'Please enter a first name or nickname.' ), 'erreur_conditions' => array( 'fr' => 'Merci d’accepter les conditions de participation.', 'en' => 'Please accept the participation terms.' ), 'doublon_oeuvre' => array( 'fr' => 'Cette phrase est déjà une œuvre de Nolan Izreal. Proposez-en une autre !', 'en' => 'This sentence is already an artwork by Nolan Izreal. Try another one!' ), @@ -359,9 +361,19 @@ if ( preg_match( '#(https?:|www\.|\.[a-z]{2,4}/|@[a-z0-9_]+\.)#i', $p ) ) { return ''; } $n = count( ni_mir_mots( $p ) ); if ( $n < 1 || $n > NI_MIR_MAX_MOTS ) { return ''; } + if ( ni_mir_mots_trop_longs( $p ) ) { return ''; } return $p; } +/** Mots de plus de NI_MIR_MAX_LETTRES lettres (seules les lettres comptent : « qu’on » = 4). */ +function ni_mir_mots_trop_longs( $phrase ) { + $trop = array(); + foreach ( ni_mir_mots( $phrase ) as $m ) { + if ( preg_match_all( '/\p{L}/u', $m ) > NI_MIR_MAX_LETTRES ) { $trop[] = $m; } + } + return $trop; +} + function ni_mir_nettoyer_composition( $c, $nb_mots ) { $c = is_array( $c ) ? $c : array(); $n = count( ni_mir_palette() ); @@ -601,6 +613,8 @@ function ni_mir_rest_verifier( WP_REST_Request $req ) { $lang = ni_mir_rest_langue( $req ); if ( ! ni_mir_limite( 'verifier_' . ni_mir_ip_hash(), 120, HOUR_IN_SECONDS ) ) { return ni_mir_rest_erreur( 'erreur_limite', $lang, 429 ); } + $longs = ni_mir_mots_trop_longs( sanitize_text_field( wp_unslash( (string) $req->get_param( 'phrase' ) ) ) ); + if ( $longs ) { return rest_ensure_response( array( 'ok' => false, 'message' => sprintf( ni_mir_txt( 'mot_trop_long', $lang ), '« ' . implode( ' », « ', $longs ) . ' »' ) ) ); } $phrase = ni_mir_nettoyer_phrase( $req->get_param( 'phrase' ) ); if ( '' === $phrase ) { return rest_ensure_response( array( 'ok' => false, 'message' => ni_mir_txt( 'erreur_phrase', $lang ) ) ); } $type = ni_mir_doublon( $phrase ); @@ -844,8 +858,8 @@ $t = function ( $k ) use ( $lang ) { return esc_html( ni_mir_txt( $k, $lang ) ); }; $uid = 'ni-mir-' . wp_unique_id(); - $config = array( 'rest' => esc_url_raw( rest_url( 'ni/v1/mir/' ) ), 'langue' => $lang, 'max' => NI_MIR_MAX_MOTS, 'palette' => ni_mir_palette(), 'majuscules' => (int) ni_mir_majuscules(), 'txt' => array() ); - foreach ( array( 'compteur', 'compteur_un', 'trop', 'erreur', 'erreur_email', 'erreur_phrase', 'erreur_prenom', 'erreur_conditions', 'vote_merci', 'vote_deja', 'vote_fait', 'btn_vote', 'votes_sg', 'votes_pl', 'envoi', 'verification', 'btn_composer' ) as $k ) { $config['txt'][ $k ] = ni_mir_txt( $k, $lang ); } + $config = array( 'rest' => esc_url_raw( rest_url( 'ni/v1/mir/' ) ), 'langue' => $lang, 'max' => NI_MIR_MAX_MOTS, 'max_lettres' => NI_MIR_MAX_LETTRES, 'palette' => ni_mir_palette(), 'majuscules' => (int) ni_mir_majuscules(), 'txt' => array() ); + foreach ( array( 'compteur', 'compteur_un', 'trop', 'mot_trop_long', 'erreur', 'erreur_email', 'erreur_phrase', 'erreur_prenom', 'erreur_conditions', 'vote_merci', 'vote_deja', 'vote_fait', 'btn_vote', 'votes_sg', 'votes_pl', 'envoi', 'verification', 'btn_composer' ) as $k ) { $config['txt'][ $k ] = ni_mir_txt( $k, $lang ); } if ( function_exists( 'ni_mir_txt_commande' ) ) { $config['txt']['commande_prep'] = ni_mir_txt_commande( 'prep', $lang ); $config['txt']['commande_erreur'] = ni_mir_txt_commande( 'erreur', $lang ); } $h = '
';