Passer spip en xhtml valide (suite)

Mise à jour du filtre posté par stef : « Passer spip en xhtml valide ».

Ceci est une ARCHIVE, peut-être périmée. Vérifiez bien les compatibilités !

Créer du contenu xhtml 1.0 valide ? C’est possible avec très peu de travail. Tenez, deux filtres en plus, par exemple... (utilisés et validés en production avec un spip 1.5.1)

Créer du contenu xhtml 1.0 valide ? C’est possible avec très peu de travail. Tenez, deux filtres en plus, par exemple... Ces filtres ne règlent pas tous les problèmes, mais ils valident déjà le plus gros : le contenu complet du site. J’utilise ces filtres en production sur un spip 1.5.2 et toutes mes pages sont validées par le W3C, comme vous pouvez le voir en validant ma page d’accueil ou une page intérieure quelconque complète, avec des images.

Note des admins : SPIP à fait beaucoup de progrès depuis la version 1.5.1. Mais cet article reste très pertinent pour vous permettre de conprendre par exemple le fonctionnement des filtres, ou comment rectifier les derniers élements non valides.

XHTML ? Qu’est-ce que c’est ?

Le xhtml est une façon d’aborder le html et qui a vocation à le supplanter à moyenne échéance. Il est défini par le W3C comme « une reformulation de HTML 4 en XML 1.0 ». Sa principale différence avec html réside dans la nécessité de fermer tous les tags ouverts, y compris ceux qu’en html classique on utilise sans tag de fin (par exemple les <img> et autres <br>). Veuillez vous référer à Openweb notamment, si les normes du W3C vous sont imbuvables.

Attention, je ne vais vous fournir ici que de quoi modifier le contenu généré par spip. C’est à vous qu’il incombe par ailleurs de faire en sorte que le reste du site (notamment toute la structure) soit en xhtml, en n’imbriquant pas les balises n’importe comment, en femant systématiquement les balises ouvertes, et en n’utilisant pas n’importe quels attributs. La route est longue ;-)

Quels problèmes constate-t-on dans spip ?

Les problèmes majeurs rencontrés dans les pages générées par spip sont les suivants :

  • Mauvaise imbrication des tables, des intertitres (<h3>) et des listes [1] : ces éléments sont encadrés de <p class="spip></p>, ce n’est pas conforme.
  • <img> et <br> mal fermés
  • hspace et vspace sonrt des attributs d’images non valides, ainsi qu’align
  • Mise en forme : le gras généré par {{texte gras}} en spip-code est un <b>texte gras</b>, ce qui est un formatage visuel non-sémantique, auquel on préférera <strong>texte très appuyé</strong>... De même {texte italique} génère <i>texte italique</i> dans spip, auquel on préférera <em>texte appuyé</em>.
  • Pour les petits éléments de contenu (Descriptif, Notes, Forums) il arrive que les paragraphes soient absents, ou partiellement générés.

1. Changeons les intertitres

Tout d’abord nous devons redéclarer des intertitres, et nous affranchir ainsi des imbrications de titres dans les <p></p>. Vous l’aurez remarqué, par défaut spip 1.5.1 génère des paragraphes vides aux alentours des intertitres.

$GLOBALS['debut_intertitre'] = "\n<h3>";
$GLOBALS['fin_intertitre'] = "</h3>\n";

2. Filtrons notre contenu riche

Ce filtre, en plusieurs passages, corrige tous les points mentionnés ci-dessus. Il « désimbrique » les tags qui ne doivent pas être subordonnés à des <p></p>, il change les attributs align en style float, supprime les attributs hspace et vspace, etc.

function nb_spip2xhtml($str) {
    if($str!="") {
        // suppresion des hspace, vspace
        $str = preg_replace( "/(h|v)space='.'|border=0/i" , "" , $str);
        
        // img xhtml <img> -> <img />
        $str = preg_replace( "/<img([^>]*)>/i" , "<img \\1 />" , $str);
        
        // align -> style float
        $str = preg_replace( "/align='([a-z]*)'/i" , "style=\"float:\\1;\"" , $str);
        
        // h3 imbrique dans un p
        $str = preg_replace( "/<p class=\"spip\"> <h3>/i" , "<h3>" , $str);
        $str = preg_replace( "/<\/h3>( )*<\/p>/i" , "</h3>" , $str);
        
        // tableaux imbriques dans p
        $str = preg_replace( "/<p class=\"spip\"><table class=\"spip\">/i" , "<table>" , $str);
        $str = preg_replace( "/<\/table>( )*<\/p>/i" , "</table>" , $str);
        
        // ol ou ul imbrique dans p
        $str = preg_replace( "/<p class=\"spip\"><(o|u)l class=\"spip\">/i" , "<\\1l class=\"spip\">" , $str);
        $str = preg_replace( "/<\/(o|u)l>( )*<\/p>/i" , "</\\1l>" , $str);
        
        // <br> -> <br />
        $str = preg_replace( "/<br>/i" , "<br />" , $str);
        
        // <b> -> <strong> et <i> -> <em>
        $str = preg_replace( "/(<b class=\"spip\">|<b>)/i" , "<strong>" , $str);
        $str = preg_replace( "/(<i class=\"spip\">|<i>)/i" , "<em>" , $str);
        $str = preg_replace( "/<\/b>/i" , "</strong>" , $str);
        $str = preg_replace( "/<\/i>/i" , "</em>" , $str);
        
    }
    
    // renvoyer la chaine corrigee
    return $str;
}

2.1 Filtrons les formulaires

Cette partie permet de rendre compatible xhtml 1.0 les formulaires #RECHERCHE et #FORUM.

// FORMULAIRE
// passage des balises en minucule
$str = ereg_replace("<FORM", "<form", "$str");
$str = ereg_replace("<INPUT", "<input", "$str");
$str = ereg_replace("<TEXTAREA", "<textarea", "$str");
$str = ereg_replace("</TEXTAREA>", "</textarea>", "$str");
$str = preg_replace("/(<.*?)(TYPE=\')(.*?)(\')(.*?>)/", "\\1type=\"\\3\"\\5", "$str");
$str = ereg_replace("VALUE=", "value=", "$str");
// Pour le formulaire FORUM création des attributs id
$str = preg_replace("/(<.*?)(NAME=')(.*?)(')(.*?>)/", "\\1id=\"\\3\" name=\"\\3\"\\5", "$str");		
// On remplace name par id dans la balise form
$str = preg_replace("/(<form.*?)(name=)(.*?>)/", "\\1id=\\3", "$str");
// on ferme les balises input
$str = preg_replace("/(<input.*?)(>)/", "\\1 />", "$str");
// On supprime l'attribut WRAP des zones de texte qui n'est pas valide xhtml
$str = preg_replace("/(<textarea.*?)( wrap=hard| wrap=soft| wrap=off)(.*?>)/", "\\1\\3", "$str");

NB : Pour placer les deux attributs « id » et « name » dans la balise <form>, il faut remplacer la ligne :

$str = preg_replace("/(<form.*?)(name=)(.*?>)/", "\\1id=\\3", "$str");

par

$str = preg_replace("/(<form.*?)(name=')(.*?)(')(.*?>)/", "\\1id=\"\\3\" name=\"\\3\"\\5", "$str");

3. modifions tous les contenus « légers »

Les notes, forums, et autres chapeaux ne sont pas forcément bien « habillés ». Pour y remédier un filtre tout bête vérifie la présence de début et de fin de paragraphe. [2]

function nb_checkparas($str) {
    $str = trim($str);
    if($str!="") {
        if(substr($str, 0, 2)!="<p") {
            $str = "<p>" . $str;
        }
        if(substr($str, strlen($str)-4, 4)!="</p>") {
            $str .= "</p>";
        }
    }
    return $str;
}

Conjonction des filtres (petite piqûre de rappel)

Pour rappel des filtres peuvent être imbriqués, on peut donc tout à fait utiliser [<div class="chapo">(#CHAPO|nb_spip2xhtml|nb_checkparas)</div>].

Mise en place

Sur mon site j’ai passé chaque contenu généré en nb_spip2xhtml, et ajouté pour les notes le nb_checkparas. Rien ne vous empêche, comme je viens de le préciser, de mettre systématiquement les deux filtres.

Mises en garde

Quand vous utilisez des <doc***> spip génère un tableau qu’il fait flotter à l’intérieur même d’un paragraphe. Cette approche « permissive » est tolérée par les navigateurs en HTML, elle est en revanche non valide en XHTML strict. Pour l’instant je n’ai pas de solution simple. Dans mon spip j’ai carrément dû modifier le noyau pour générer un <span> que je fais flotter, mais ce n’est pas satisfaisant, et en tout cas je me garderais de fournir le code ici, il est resté au niveau du hack marginal.

-  Ce filte ne s’applique pas aux formulaires #SIGNATURE, #SITE et #ECRIRE_AUTEUR
-  Pour utiliser ce filtre avec un formulaire #RECHERCHE, il faut préciser la page resultat.
ex : [(#FORMULAIRE_RECHERCHE|recherche.php3|nb_spip2xhtml)]

Et voilà le code complet :-)

/*
 *   +----------------------------------+
 *    Nom du Filtre :    nb_spip2xhtml
 *                       nb_checkparas
 *   +----------------------------------+
 *    Date : jeudi 22 mai 2003
 *    Auteur :  stef      + nospam@notabene.f2o.org
 *              Aurélien
 *   +-------------------------------------+
 *    Fonctions de ces filtres :
 *     Ils rendent conforme à xhtml le contenu généré par spip
 *   +-------------------------------------+ 
 *  
 * Pour toute suggestion, remarque, proposition d'ajout
 * reportez-vous au forum de l'article :
 * http://www.uzine.net/spip_contrib/article.php3?id_article=164
*/

/*
* reformatage des intertitres
* */

$GLOBALS['debut_intertitre'] = "\n<h3>";
$GLOBALS['fin_intertitre'] = "</h3>\n";

/*
* formatage du contenu pour validation xhtml
* */

function nb_spip2xhtml($str) {
    if($str!="") {
        // suppresion des hspace, vspace
        $str = preg_replace( "/(h|v)space='.'|border=0/i" , "" , $str);
        
        // img xhtml <img> -> <img />
        $str = preg_replace( "/<img([^>]*)>/i" , "<img \\1 />" , $str);
        
        // align -> style text-align
        $str = preg_replace( "/align='([a-z]*)'/i" , "style=\"float:\\1;\"" , $str);
        
        // h3 imbrique dans un p
        $str = preg_replace( "/<p class=\"spip\"> <h3>/i" , "<h3>" , $str);
        $str = preg_replace( "/<\/h3>( )*<\/p>/i" , "</h3>" , $str);
        
        // tableaux imbriques dans p
        $str = preg_replace( "/<p class=\"spip\"><table class=\"spip\">/i" , "<table>" , $str);
        $str = preg_replace( "/<\/table>( )*<\/p>/i" , "</table>" , $str);
        
        // ol ou ul imbrique dans p
        $str = preg_replace( "/<p class=\"spip\"><(o|u)l class=\"spip\">/i" , "<\\1l class=\"spip\">" , $str);
        $str = preg_replace( "/<\/(o|u)l>( )*<\/p>/i" , "</\\1l>" , $str);
        
        // <br> -> <br />
        $str = preg_replace( "/<br>/i" , "<br />" , $str);
        
        // <b> -> <strong> et <i> -> <em>
        $str = preg_replace( "/(<b class=\"spip\">|<b>)/i" , "<strong>" , $str);
        $str = preg_replace( "/(<i class=\"spip\">|<i>)/i" , "<em>" , $str);
        $str = preg_replace( "/<\/b>/i" , "</strong>" , $str);
        $str = preg_replace( "/<\/i>/i" , "</em>" , $str);

        // FORMULAIRE
        // passage des balises en minucule
        $str = ereg_replace("<FORM", "<form", "$str");
        $str = ereg_replace("<INPUT", "<input", "$str");
        $str = ereg_replace("<TEXTAREA", "<textarea", "$str");
        $str = ereg_replace("</TEXTAREA>", "</textarea>", "$str");
        $str = preg_replace("/(<.*?)(TYPE=\')(.*?)(\')(.*?>)/", "\\1type=\"\\3\"\\5", "$str");
        $str = ereg_replace("VALUE=", "value=", "$str");
        // Pour le formulaire FORUM création des attributs id
        $str = preg_replace("/(<.*?)(NAME=')(.*?)(')(.*?>)/", "\\1id=\"\\3\" name=\"\\3\"\\5", "$str");		
        // On remplace name par id dans la balise form
        $str = preg_replace("/(<form.*?)(name=)(.*?>)/", "\\1id=\\3", "$str");
        // on ferme les balises input
        $str = preg_replace("/(<input.*?)(>)/", "\\1 />", "$str");
        // On supprime l'attribut WRAP des zones de texte qui n'est pas valide xhtml
        $str = preg_replace("/(<textarea.*?)( wrap=hard| wrap=soft| wrap=off)(.*?>)/", "\\1\\3", "$str");
        
    }
    
    // renvoyer la chaine corrigee
    return $str;
}
// FIN du filtre nb_spip2xhtml

/*
* les notes ont un petit bug :il manque parfois le <p> de debut
* cette fonction y remedie
* fonction utilisee aussi sur mon site pour la bio des auteurs notamment
* */

function nb_checkparas($str) {
    $str = trim($str);
    if($str!="") {
        if(substr($str, 0, 2)!="<p") {
            $str = "<p>" . $str;
        }
        if(substr($str, strlen($str)-4, 4)!="</p>") {
            $str .= "</p>";
        }
    }
    return $str;
}
// FIN du filtre nb_checkparas

Notes

[1Les listes qu’en spip on écrit en -* pour les listes à puces et en -# pour les listes numérotées, soit respectivement en html <ul> et <ol>

[2Vous constaterez que nous commençons par tester si la chaîne n’est pas vide, sans quoi nous générerions un paragraphe conforme, mais vide, ce qui peut poser des problèmes de mise en page : dans le cas d’un [<div class="notes">(#NOTES|nb_checkparas)</div>] par exemple, sans description on génère un pavé de notes non nécessaire, ce qui peut nuire au contenu et à l’apparence de sérieux du site.

-  Pour tester la validité de vos pages : W3C
-  Suite aux différentes contributions et à la remarque neoram, j’ai ajouté un fichier word indiquant en gros ce qu’il reste à faire pour rendre spip en xhtml valide et conforme aux recommendations W3C/WAI/Braillenet

Discussion

2 discussions

  • Christian C

    Bonjour,

    Cette contrib m’intéresse car j’utilise beaucoup de liste (<ul><li> ...) qui dans l’écriture des articles spip, doivent être écrite avec des tirets ...

    Malheureusement, ces tirets sont transformés en balises : <br /><li>, imbriquées dans un <p class="spip" align="center"> et il manque la balise <ul>" !

    N’étant pas un pro en php, quelqu’un pourrait-il m’aider ?

    J’utilise SPIP 1.7.2

    Merci

    Répondre à ce message

  • Cette contrib est-elle toujours d’actualité ?
    Les filtres sont apparamment utilisés dans les squelettes de spip contrib, est-ce normal ?

    @+

    Répondre à ce message

Ajouter un commentaire

Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :

  • Désactiver tous les plugins que vous ne voulez pas tester afin de vous assurer que le bug vient bien du plugin X. Cela vous évitera d’écrire sur le forum d’une contribution qui n’est finalement pas en cause.
  • Cherchez et notez les numéros de version de tout ce qui est en place au moment du test :
    • version de SPIP, en bas de la partie privée
    • version du plugin testé et des éventuels plugins nécessités
    • version de PHP (exec=info en partie privée)
    • version de MySQL / SQLite
  • Si votre problème concerne la partie publique de votre site, donnez une URL où le bug est visible, pour que les gens puissent voir par eux-mêmes.
  • En cas de page blanche, merci d’activer l’affichage des erreurs, et d’indiquer ensuite l’erreur qui apparaît.

Merci d’avance pour les personnes qui vous aideront !

Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.

Qui êtes-vous ?
[Se connecter]

Pour afficher votre trombine avec votre message, enregistrez-la d’abord sur gravatar.com (gratuit et indolore) et n’oubliez pas d’indiquer votre adresse e-mail ici.

Ajoutez votre commentaire ici

Ce champ accepte les raccourcis SPIP {{gras}} {italique} -*liste [texte->url] <quote> <code> et le code HTML <q> <del> <ins>. Pour créer des paragraphes, laissez simplement des lignes vides.

Ajouter un document

Suivre les commentaires : RSS 2.0 | Atom