Structure de test
La structure de test adoptée pour ce tutoriel est celle du schéma de Polyhiérarchie.
Les cercles tout en bas du schéma sont les articles. XS et YS sont les secteurs.
Une base de donnée exemple est jointe à l’article (dump SPIP 3, sans auteurs, avec juste les rubriques et les articles). Voilà la structure :
ID | Titre |
---|---|
1 | xs |
2 | d |
3 | b |
6 | ys |
7 | g |
8 | d’ |
10 | g’ |
11 | f’ |
ID | Titre |
---|---|
1 | f |
2 | a |
3 | c |
4 | e |
5 | h |
Ce qui donne le schéma suivant :
Les exemples que nous donnerons se baseront sur la recherche des chemins de l’article 5.
Principe général
Nous allons remonter les différentes hiérarchies depuis l’article jusqu’à la racine. Nous stockerons ces hiérarchies dans un tableau #ARRAY. Chaque entrée du tableau correspondant à un chemin possible, sous la forme rxryrx
, où x, y, z sont les numéros de rubriques.
Puis nous bouclerons sur ce tableau, pour pouvoir gérer l’affichage des chemins. Chaque entrée sous la forme rxryrx
sera transformée en tableau sur lequel nous bouclerons à l’envers (pour avoir une hiérarchie depuis le haut vers le bas, et non du bas vers le haut). Cela nous permettra d’afficher les chemins.
Nous utiliserons donc les outils les plus avancés du langage de squelette de SPIP :
- #ARRAY
,#SET
,#GET
pour gérer le tableau.
- La boucle (POUR)
- Les boucles imbriquées pour pouvoir remonter entièrement la hiérarchie.
Je précise que cette contribution a été testée sous SPIP 3. Pour SPIP 2.1, il vous faudra installer le plugin BONUX.
Initialisation du tableau des chemins
Nous allons initialiser un tableau vide, où nous stockerons les différents chemins. Tout notre code devra être situé à l’intérieur d’une boucle ARTICLE
.
Toujours à l’intérieur de cette boucle, nous allons initialiser une variable niveau
qui nous permettra d’analyser à quelle niveau de hiérarchie nous sommes. Plus nous remonterons dans la hiérarchie, plus le niveau sera élevé. Nous partons du niveau 0.
<BOUCLE_article(ARTICLES){critères}>
#SET{chemins,#ARRAY}
#SET{niveau,0}
</BOUCLE_article>
Remplissage du tableau, au premier niveau
Insérons maintenant dans cette boucle, après #SET{niveau,0}
le code pour remplir le tableau pour le premier niveau de hiérarchie (comme toujours, en partant du bas) :
<BOUCLE_article(ARTICLES){critères}>
#SET{chemins,#ARRAY}
#SET{niveau,0}
<BOUCLE_parents(RUBRIQUES){parents}{par titre}>
#SET{n0,r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n0},
#GET{n0},
}
}}
</BOUCLE_parents>
</BOUCLE_article>
Explications :
- nous stockons temporairement dans la variable n0
la valeur du chemin courant. En effet, nous en aurons besoin pour construire les chemins « au dessus » de cette rubrique.
- nous ajoutons dans le tableau, pour chaque rubriques « mère », une entrée dont la clef est rXXX
et la valeur rXXX
, où XXX représente le numéro de rubrique.
Pourquoi me direz vous dupliquer ainsi l’information ? Parce que si la rubrique courante a elle même des ancêtres, alors nous n’aurons pas un chemin complet. Par conséquence, il faudra effacer le « demi-chemin ». Nous en parlons plus loins. Chaque chose en son temps.
Pour le moment, notre tableau chemins
se compose ainsi :
Clef | Valeur |
---|---|
r7 | r7 |
r10 | r10 |
Remonter la hiérarchie
Dans notre boucle _parents
nous allons appeler une boucle _grands_parents
, qui s’appellera de manière récursive, afin de remonter toute la hiérarchie.
Avant de rentrer dans cette boucle, nous allons augmenter la variable niveau
de 1, et la rediminuer en sortant. Ainsi, nous saurons systématiquement à quelle niveau nous nous trouvons dans l’aborescence.
<BOUCLE_article(ARTICLES){critères}>
#SET{chemins,#ARRAY}
#SET{niveau,0}
<BOUCLE_parents(RUBRIQUES){parents}{par titre}>
#SET{n0,r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n0},
#GET{n0}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_grands_parents(RUBRIQUES){parents}{par titre}>
#SET{n#GET{niveau},#GET{n#GET{niveau}|moins{1}}r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}},
#GET{n#GET{niveau}}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_ancetres(Boucle_grands_parents) />
#SET{niveau,#GET{niveau}|moins{1}}
</BOUCLE_grands_parents>
#SET{niveau,#GET{niveau}|moins{1}}
</BOUCLE_parents>
Pour chaque niveau, noté x
, nous allons créer une variable nx
: c’est le #SET{n#GET{niveau},
.
Cette variable reprendre la valeur de la variable nx-1
, en ajoutant à la fin r#ID_RUBRIQUE
: c’est le #GET{n#GET{niveau}|moins{1}}r#ID_RUBRIQUE
.
Nous ajoutons ensuite la valeur de la variable nx
comme couple entrée/valeur dans le tableau des chemins.
Enfin, nous remontons tout en haut de la hiérarchie par récursion, en appelant la boucle ancetres
: voyez la documentation sur les boucles récursives.
Deux remarques pour prévenir les questions :
- Nous ne pouvons pas mettre le changement de la variable
niveau
dans la partie optionelle des boucles, car cette partie est interprétée après le contenu de la boucle. - On pourrait se dire qu’il serait possible de commencer au niveau de la boucle
grand_parents
et se passer deparents
. Nous avons testé et obtenu des erreurs de récursions à l’infini, empêchant l’affichage de la page.
Notre tableau à maintenant le contenu suivant :
r7 | r7 |
r7r2 | r7r2 |
r7r2r1 | r7r2r1 |
r10 | r10 |
r10r8 | r10r8 |
r10r8r6 | r10r8r6 |
Filtrer les chemins incomplets
Les chemins r7
,r7r2
,r10
, r10r8
ne sont pas complets : ils ne remontent pas jusqu’à la racine. Il nous faut donc les filtrer.
Pour ce faire, nous allons effacer la valeur de la clef correspondante, en mettant le code suivant dans la partie optionelle de nos boucles parents
et grand_parents
:
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}|moins{1}},
''
}
}}
Cela donc donc :
<BOUCLE_article(ARTICLES){critères}>
#SET{chemins,#ARRAY}
#SET{niveau,0}
<BOUCLE_parents(RUBRIQUES){parents}{par titre}>
#SET{n0,r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n0},
#GET{n0}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_grands_parents(RUBRIQUES){parents}{par titre}>
#SET{n#GET{niveau},#GET{n#GET{niveau}|moins{1}}r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}},
#GET{n#GET{niveau}}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_ancetres(Boucle_grands_parents) />
#SET{niveau,#GET{niveau}|moins{1}}
}}
</BOUCLE_grands_parents>
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}|moins{1}},
''
}
}}
</B_grands_parents>
#SET{niveau,#GET{niveau}|moins{1}}
</BOUCLE_parents>
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}|moins{1}},
''
}
}}
</B_parents>
</BOUCLE_article>
Et on a le tableau des chemins suivant :
Clef | Valeur |
---|---|
r7 | |
r7r2 | |
r7r2r1 | r7r2r1 |
r10 | |
r7r2r8 | |
r7r2r8r6 | r7r2r8r6 |
Afficher tout les chemins
L’essentiel est fait : il ne nous reste plus qu’à boucler sur le tableau des chemins, en excluant ceux dont la valeur est vide :
<B_chemins>
<ul>
<BOUCLE_chemins(POUR){tableau #GET{chemins}}{valeur!=''}>
<li>#VALEUR</li>
</BOUCLE_chemins>
</ul>
</B_chemins>
Cela produit :
<ul>
<li>r7r2r1</li>
<li>r10</li>
<li>r7r2r8r6</li>
</ul>
Chaque li
correspond à un chemin. Il nous faut donc l’afficher.
Pour ce faire, nous allons :
- exploser la chaînes rxryrz
pour obtenir un tableau, en utilisant r
comme séparateur.
- boucler sur ce tableau, en insérant une symbole de séparation entre chaque entrée, en évitant les entrées vides (liées au fait que nous n’avons pas de r
à la fin de nos chemin) et en inversant l’ordre (pour avoir une hiérarchie allant de haut en bas et non de bas en haut)
- dans la boucle, récupérer le titre la rubrique avec la balise #INFO_TITRE
, et son URL avec #URL_RUBRIQUE{x}
.
Ce qui donne :
<B_chemins>
<ul>
<BOUCLE_chemins(POUR){tableau #GET{chemins}}{valeur!=''}>
<B_chemin>
<li>
<a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a> >
<BOUCLE_chemin(POUR){tableau #VALEUR|explode{r}}{inverse}{valeur!=''}{" > "}>
<a href="#URL_RUBRIQUE{#VALEUR}">#INFO_TITRE{rubrique,#VALEUR}</a>
</BOUCLE_chemin>
> #TITRE [(#REM)<!-- correspond au titre de l'article-->]
</li>
</B_chemin>
</BOUCLE_chemins>
</ul>
</B_chemins>
Et en HTML produit :
<ul>
<li>
<a href="http://poly.dev">Mon site SPIP</a> >
<a href="-rubrique1-.html">xs</a>
>
<a href="-rubrique2-.html">d</a>
>
<a href="-rubrique7-.html">g</a>
> h
</li>
<li>
<a href="http://poly.dev">Mon site SPIP</a> >
<a href="-rubrique6-.html">ys</a>
>
<a href="-rubrique8-.html">d’</a>
>
<a href="-rubrique10-.html">g’</a>
> h
</li>
</ul>
Mettre en exergue le chemin principal
Il serait pratique que le chemin principal s’affiche en premier, avec une classe spéciale. Pour ce faire, nous allons utiliser une boucle HIERARCHIE
classique, qui affichera le chemin avant, et stockera dans une variable cheminp
ce chemin, afin de pouvoir l’exclure des chemins sur lesquelles on boucle.
Le remplissage de cette variable et l’affichage du chemin se fait donc ainsi :
<B_cheminp>
<div class='cheminp'>
<a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a> >
<BOUCLE_cheminp(HIERARCHIE){id_article}{" > "}>
<a href="#URL_RUBRIQUE}">#TITRE</a>[(#SET{cheminp,[r(#ID_RUBRIQUE)][(#GET{cheminp})]})]
</BOUCLE_cheminp>
> #TITRE [(#REM)<!-- correspond au titre de l'article-->]
</div>
</B_cheminp>
Nous allons donc exclure de la boucle chemins
le chemin dont la valeur est égale à #GET{cheminp}
.
Ce qui donne :
<B_chemins>
<ul>
<BOUCLE_chemins(POUR){tableau #GET{chemins}}{valeur!=''}{valeur!=#GET{cheminp}}>
<B_chemin>
<li>
<a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a> >
<BOUCLE_chemin(POUR){tableau #VALEUR|explode{r}}{inverse}{valeur!=''}{" > "}>
<a href="#URL_RUBRIQUE{#VALEUR}">#INFO_TITRE{rubrique,#VALEUR}</a>
</BOUCLE_chemin>
> #TITRE [(#REM)<!-- correspond au titre de l'article-->]
</li>
</B_chemin>
</BOUCLE_chemins>
</ul>
</B_chemins>
Au final
Nous avons donc au final un ensemble de boucles qui s’écrivent ainsi :
<BOUCLE_article(ARTICLES){critères}>
#SET{chemins,#ARRAY}
#SET{niveau,0}
<BOUCLE_parents(RUBRIQUES){parents}{par titre}>
#SET{n0,r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n0},
#GET{n0}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_grands_parents(RUBRIQUES){parents}{par titre}>
#SET{n#GET{niveau},#GET{n#GET{niveau}|moins{1}}r#ID_RUBRIQUE}
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}},
#GET{n#GET{niveau}}
}
}}
#SET{niveau,#GET{niveau}|plus{1}}
<BOUCLE_ancetres(Boucle_grands_parents) />
#SET{niveau,#GET{niveau}|moins{1}}
</BOUCLE_grands_parents>
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}|moins{1}},
''
}
}}
</B_grands_parents>
#SET{niveau,#GET{niveau}|moins{1}}
</BOUCLE_parents>
#SET{chemins,#GET{chemins}|array_merge{#ARRAY{
#GET{n#GET{niveau}|moins{1}},
''
}
}}
</B_parents>
#SET{cheminp,''}
<B_cheminp>
<div class='cheminp'>
<a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a> >
<BOUCLE_cheminp(HIERARCHIE){id_article}{" > "}>
<a href="#URL_RUBRIQUE}">#TITRE</a>[(#SET{cheminp,[r(#ID_RUBRIQUE)][(#GET{cheminp})]})]
</BOUCLE_cheminp>
> #TITRE [(#REM)<!-- correspond au titre de l'article-->]
</div>
</B_cheminp>
<B_chemins>
<ul>
<BOUCLE_chemins(POUR){tableau #GET{chemins}}{valeur!=''}{valeur!=#GET{cheminp}}>
<B_chemin>
<li>
<a href="#URL_SITE_SPIP">#NOM_SITE_SPIP</a> >
<BOUCLE_chemin(POUR){tableau #VALEUR|explode{r}}{inverse}{valeur!=''}{" > "}>
<a href="#URL_RUBRIQUE{#VALEUR}">#INFO_TITRE{rubrique,#VALEUR}</a>
</BOUCLE_chemin>
> #TITRE [(#REM)<!-- correspond au titre de l'article-->]
</li>
</B_chemin>
</BOUCLE_chemins>
</ul>
</B_chemins>
</BOUCLE_article>
Ce qui donne en HTML
<div class='cheminp'>
<a href="http://poly.dev">Mon site SPIP</a> >
<a href="-rubrique6-.html}">ys</a>
>
<a href="-rubrique8-.html}">d’</a>
>
<a href="-rubrique10-.html}">g’</a>
> h
</div>
<ul>
<li>
<a href="http://poly.dev">Mon site SPIP</a> >
<a href="-rubrique1-.html">xs</a>
>
<a href="-rubrique2-.html">d</a>
>
<a href="-rubrique7-.html">g</a>
> h
</li>
</ul>
Le reste n’est plus qu’affaire de maîtrise du CSS / HTML.
Discussions par date d’activité
3 discussions
Salut,
Concrètement où doit-on inscrire ces codes ?
Question de débutant, mais cela serait sympa de répondre de manière pédagogique.
Merci,
Nico
Salut,
concrètement il faut le mettre dans le squelettes correspondant à la page où tu veux que cela apparaissent. Pour le coup je ne peux que te conseiller de lire la documentation de base de SPIP sur la notion de squelettes et de boucles. Tu peux aussi regarder http://programmer.spip.net/-Introduction,2- (et suivante)
Sinon si c’est pour résoudre ponctuellement un problème, tu m’indique ton site et je te donne plus en détail le mode de fonctionnement.
Salut,
Merci Maïeul pour cette réponse et ta proposition.
Après avoir pensé qu’indiquer aux articles / polyhiérarchie suffisait pour mettre un article / rubrique en 2 endroits différents, je pensais qu’inclure un seul « squelette »/« code » aurait suffit.
Du coup la manip me semble trop compliquée pour mes modestes capacités.
Je te remercie pour ta proposition d’ aide, mais j’ai du activer une 20aine d’articles / rubriques avec l’option polyhiérarhie et cela va être fastidieux de les retrouver parmis les 2000 articles du site.
Au plaisir,
Nico
Répondre à ce message
Hello Maïeul
Merci pour cette contrib qui fonctionne très bien... Juste un truc, quand même, mais je ne sais pas si ça a un rapport. Dans la boucle « pour » nommée chemin (au singulier),
#URL_RUBRIQUE{#VALEUR}
me rajoute « &connect=pour » à la fin de l’url : spip.php ?page=rubrique&id_rubrique=1076&connect=pourCe qui est bizarre aussi c’est que le site est paramétré en url de type page, la balise
#URL_RUBRIQUE{#VALEUR}
devrait donc générer spip.php ?rubrique1076...Tu vois d’où ça pourrait venir ?
SPIP 2.1.19 à jour de svn. Les plugins aussi. J’ai également le plugin « itérateur » installé
aucune idée ...
Pour info, c’est un bug dans la boucle pour de bonux. Qui ne sera pas corrigé en spip 2.1 :
http://core.spip.org/issues/2868#change-8180
Répondre à ce message
cet article semble passionnant.....
mais la lecture de tous ces #### est....... censored !
personne n’ecrirait un balise genre #EVAL
qui permettrait d’ecrire (entre accolades)
#EVAL{ niveau = niveau + 1 ; }
une seule balise prefixant une ligne instruction claire....
( les get ou set seraient choisis par l’analyseur interne)
merci
faites le :-) moi en tout cas je n’ai pas le temps
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 :
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.
Suivre les commentaires : |