Depuis peu j'ai mis en place un petit système qui permet de faire varier le style du thème utilisé ici en fonction de la saison actuelle ou au libre choix de l'utilisateur. Pour obtenir ceci je suis parti du thème de base (FallSeason), et j'ai choisi de faire varier uniquement les images utilisées pour l'entête, les fonds de menu et les puces. Voyons comment implémenter un tel fonctionnement[1].
Préparation des styles
Première étape, identification des images et création des variations saisonnières. Dans le répertoire du thème nous avons un répertoire images qui contient les images originales. Dans ce répertoire nous allons créer autant de répertoires que de saison avec les noms suivants : autumn, spring, summer et winter. Dans le premier nous allons y placer les images spécifiques de la saison (entête, fonds de menu, …) déjà présentes dans ce thème — je rappelle que le thème actuel a pour objet l'automne, puis dans les autres y créer à partir d'images nouvelles ou en modifiant les images originales[2] tout en s'assurant qu'elles portent le même nom que dans le premier répertoire. Voilà à terme ce que nous devons avoir :
/themes/fallseason/images/autumn/ : - header.jpg - menu.jpg - currentmenu.jpg - puce.jpg /themes/fallseason/images/spring/ : - header.jpg - menu.jpg - currentmenu.jpg - puce.jpg /themes/fallseason/images/summer/ : - header.jpg - menu.jpg - currentmenu.jpg - puce.jpg /themes/fallseason/images/winter/ : - header.jpg - menu.jpg - currentmenu.jpg - puce.jpg
Ensuite il faut identifier dans le thème le ou les styles faisant appel à une des images en question et les extraires pour en faire quatre petits fichiers de style complémentaire, un par saison, soit autumn.css, spring.css, summer.css et winter.css. Ces quatre fichiers seront créés dans le répertoire principal du thème. Exemple pour l'entête. Dans le fichier style.css nous avions ceci :
#headerpic
{
position: relative;
height: 149px;
background: #fff url(images/header.jpg) repeat-x bottom left;
margin-bottom: 2px;
}
Nous allons supprimer la ligne background:…left; pour la placer dans le fichier autumn.css. Voilà ce qu'il reste dans le fichier style.css :
#headerpic
{
position: relative;
height: 149px;
margin-bottom: 2px;
}
Et voilà ce que nous avons maintenant dans le fichier autumn.css :
#headerpic
{
background: #fff url(images/autumn/header.jpg) repeat-x bottom left;
}
Cette opération est à faire pour tous les styles utilisant une des images placées dans les répertoires des saisons. Une fois terminé, il suffit de dupliquer le fichier autumn.css pour créer les fichiers spring.css, summer.css et winter.css en prenant soin au passage de modifier le nom du répertoire où se trouvent les images (voir l'exemple mis en emphase dans l'exemple ci-dessus).
Sélection du style désiré
Ensuite, il va falloir indiquer dans le fichier template.php qu'une feuille de style additionnelle doit être utilisée (celle de la saison en cours). Pour cela, dans la section <head>, juste après l'appel de la feuille de style standard, nous allons rajouter ceci :
<link rel="stylesheet" type="text/css" href="<?php dcInfo('theme'); ?>/<?php echo dcGetSeason(); ?>.css" media="screen" />
La fonction dcGetSeason(), dont vous avez remarqué la présence dans la ligne précédente, va se charger de déterminer la saison courante en fonction de la date du jour ou de fournir la saison explicitement choisie par l'utilisateur.
Le principe retenu ici est de proposer à l'utilisateur les choix suivants :
- utiliser une saison précise et conserver ce choix pendant 3 mois dans un cookie,
- laisser le serveur déterminer la saison actuelle et l'utiliser, choix enregistré comme tel dans un cookie pendant un an,
- idem que précédent à la nuance près que l'utilisateur se trouve sur l'autre hémisphère (les saisons sont inversées).
Pour déterminer le choix de l'utilisateur nous allons utiliser un paramètre passé via l'URL. Ce paramètre, nommé style pourra avoir une des valeurs suivantes :
- autumn
- winter
- spring
- summer
- default
- antipodes
Les quatre premières permettent de forcer la saison désirée, les cinquièmes et sixièmes permettent de laisser au serveur le soin de la déterminer en fonction de la date courante, la dernière provoquant l'inversion de la saison retenue (hiver pour été, …).
La fonction qui fait (quasiment) tout
Cette fonction est créée dans le fichier prepend.php du thème (à créer s'il n'existe pas). Voilà son code :
# Gestion du style
function dcGetSeason($record = false)
{
$styles = array('autumn','winter','spring','summer','default','antipodes');
$dates = array(320, 621, 923, 1221);
$today = getdate();
$serial = $today['mon'] * 100 + $today['mday'];
if (($serial >= $dates[0]) && ($serial < $dates[1])) { $season = 'spring'; $index = 2; }
elseif (($serial >= $dates[1]) && ($serial < $dates[2])) { $season = 'summer'; $index = 3; }
elseif (($serial >= $dates[2]) && ($serial < $dates[3])) { $season = 'autumn'; $index = 0; }
else { $season = 'winter'; $index = 1; }
if (isset($_GET['style']) && in_array($_GET['style'], $styles, true))
{
if ($record) {
if ($_GET['style'] == 'default') { $period = 365; }
elseif ($_GET['style'] == 'antipodes') { $period = 365; }
else { $period = 92; }
setcookie('style', $_GET['style'], time() + ($period * 24 * 3600));
if (dc_http_cache == 1) files::touch(DC_UPDATE_FILE);
header('Location: '.(!empty($_SERVER['HTTP_REFERER']) && strpos($_SERVER['HTTP_REFERER'],$_SERVER['HTTP_HOST']) !== false ? $_SERVER['HTTP_REFERER'] : dc_blog_url));
exit;
}
if ($_GET['style'] == 'antipodes') $season = $styles[($index + 2) % 4];
elseif ($_GET['style'] != 'default') $season = $_GET['style'];
}
elseif (isset($_COOKIE['style']) && in_array($_COOKIE['style'], $styles, true))
{
if ($_COOKIE['style'] == 'antipodes') $season = $styles[($index + 2) % 4];
elseif ($_COOKIE['style'] != 'default') $season = $_COOKIE['style'];
}
return $season;
}
Que fait cette fonction ?
Elle détermine tout d'abord la saison actuelle en fonction de la date du jour[3]. Puis si un paramètre style=… est présent dans l'URL, l'extrait — et l'enregistre dans un cookie nommé style si l'argument $record de la fonction est positionné à true.
Dans le cas contraire, pas de style positionné dans l'URL, elle récupèrera le choix enregistré par l'utilisateur et en déterminera la saison correspondante. Si aucun cookie n'existe ou que celui-ci est arrivé à expiration, elle retournera la saison calculée au préalable.
Toujours dans le fichier prepend.php, à la suite de cette fonction nous rajoutons la ligne suivante :
dcGetSeason(true);
Ce qui permet d'enregistrer le choix effectué dans un cookie avant l'affichage de la page et de forcer le retour à la page d'accueil en ayant indiqué au passage que le cache est obsolète[4]. Prenez soin de placer cette ligne en dehors de toute fonction pour qu'elle soit appelée explicitement dès le début[5].
Voilà terminés les modifications et ajouts à faire dans le thème.
Donner le choix au visiteur
Dernière chose à faire préciser à l'utilisateur les différents choix qu'il a avec à chaque fois l'URL correspondante. Exemple pour un blog ayant comme URL http://www.domain.tld/ :
http://www.domain.tld/index.php?style=autumnpour l'automnehttp://www.domain.tld/index.php?style=winterpour l'hiverhttp://www.domain.tld/index.php?style=springpour le printempshttp://www.domain.tld/index.php?style=summerpour l'étéhttp://www.domain.tld/index.php?style=defaultpour la saison courantehttp://www.domain.tld/index.php?style=antipodespour la saison inverse
Ces URL peuvent être indiquées dans un billet, dans une liste de la sidebar, là où vous voudrez.
Conclusion
Vous voilà doté d'un changement de style saisonnier automatique et positionnable à volonté par l'utilisateur. Vous pouvez bien sûr utiliser d'autres critères pour le changement, qu'il soit basé sur le temps (nuit/jour, mensuel, …) ou pas (catégorie d'appartenance du dernier billet, …). Les possibilités n'ont de limite que votre imagination.
Je précise que je n'ai rien inventé du tout, simplement repris des codes existants à droite et à gauche, en particulier pour la gestion et l'enregistrement du cookie qui vient en droite ligne des plugins switcher de thème disponibles pour Dotclear 1 et 2.
Notes
[1] Ce système est différent des plugins switcher de thème disponibles pour Dotclear 1 et 2 dans la mesure ou il n'est question ici que de faire varier uniquement quelques aspects de certains styles.
[2] Par exemple en faisant varier la teinte d'une image sans toucher à la saturation et à la luminosité, ce qui permet de changer uniquement la couleur dominante.
[3] J'ai choisi, par soucis de simplification, d'utiliser la même date pour chaque saison, quelque soit l'année en cours. D'après ce que j'ai pu récupérer comme informations à ce sujet, les dates retenues — 20 mars, 21 juin, 23 septembre et 21 décembre — sont celles qui reviendront le plus fréquemment dans les dix ans qui viennent.
[4] Dans le cas contraire l'utilisateur devrait attendre une mise à jour du contenu de la page pour voir son choix effectivement pris en compte.
[5] Les instructions présentes dans ce fichier (prepend.php) et non incluses dans une fonction sont exécutées avant l'affichage de la page. Si vous voulez en savoir un peu plus sur le déroulement des opérations, consultez ce billet.

9 réactions
1 De Jean-Michel - 13/11/2007, 09:38
Bonjour Franck. Pour le moment je ne l'ai lu qu'en diagonale et ça m'a l'air déjà très bien. Reste plus qu'à le tester sous peu en local chez moi pour faire de jolis thèmes ;-)
2 De mirovinben - 13/11/2007, 15:54
Très intéressant... Et j'ai fait tilt sur le fichier prepend.php... C'est-y quoi ce truc ? M'a l'air intéressant. Mécanisme intégré à DC2 ? Vais fouiller dans la doc...
Une fois de plus merci pour tes efforts pédagogiques et merci de stimuler mes neurones...
3 De Franck - 13/11/2007, 16:44
mirovinben, jettes un œil dans la note n°5 en fin de billet et cliques sur le lien proposé ;-)
Par contre, ce
prepend.phpest spécifique à Dotclear 1. L'intégration ne se fera pas de la même manière pour Dotclear 2 !4 De mirovinben - 14/11/2007, 06:28
Merdum !... je croyais que tu utilisais DC2... Surtout après ta série didactique sur les templates. Mais c'est vrai que le fait de pouvoir poster un commentaire sans passer par la case "prévisualiser" aurait dû me mettre la puce à l'oreille.
<HS>
Bon, je retourne à mon widget Otherblog : je voudrais lui ajouter un template pour pouvoir l'utiliser en dehors de la sidebar. C'est pas gagné car je suis ignare en PHP (perdu dans les fonctions à utiliser pour faire ce que je souhaite) et ne comprend pas encore le mécanisme et la syntaxe à utiliser pour passer des variables au template. Je dois sans doute prendre le pb à l'envers et vais regarder à nouveau tes billets et voir comment les pro font en examinant le code de leurs plougs installés chez moi.
</HS>
5 De Franck - 14/11/2007, 10:48
Oui j'utilise DC1, mais ce que j'explique doit pouvoir s'appliquer sans trop de difficultés à DC2. Je ferai un petit billet à ce sujet dès que je pourrai.
Pas du tout hors sujet : il y a beaucoup à apprendre à observer et comprendre le code des plugins développés par les copains. J'abuse de ça depuis longtemps ;-)
6 De Sacha - 16/11/2007, 22:52
Bonjour Franck,
Je connais plus ou moins bien le fonctionnement de Dotclear 2, par contre je n'ai jamais touché à du Dotclear 1. Je me demandais quelle était la meilleure façon de s'y prendre pour régler définitivement les problèmes de cache, qui peuvent avoir lieu si le visiteur change de thème, par exemple.
Que fait le code suivant ?
if (dc_http_cache == 1) files::touch(DC_UPDATE_FILE);Si je devine bien, il dit à Dotclear que le contenu a été mis à jour et que tous les navigateurs qui ont mis quelque chose dans le cache doivent recharger la page.
Or il n'y a en réalité qu'un seul utilisateur qui a besoin de recharger les pages, celui qui vient de changer le style du blog.
J'ai alors pensé à enregistrer la date de cette mise à jour dans un cookie (qui pourrait être réutilisé dans d'autres plugins), puis laisser Dotclear 2 comparer cette date avec la date de la version en cache du navigateur (exemple).
Au bout du compte, cela me permet donc de ne pas faire recharger les pages aux visiteurs qui n'en ont pas besoin.
Qu'en penses-tu ? C'est faisable sous Dotclear 1 ?
7 De Franck - 18/11/2007, 11:42
Sasha tu as bien deviné pour l'objet de la ligne de code. Elle a pour effet de forcer le rechargement (cache obsolète), et tu as parfaitement raison pour l'usage particulier de cette modification (changement de style) qui ne concerne qu'un seul utilisateur à un instant donné.
Je vais jeter un œil sur ta solution qui me parait intéressante et c'est certainement adaptable à Dotclear 1. Il suffirait en effet de gérer deux cookies au lieu d'un, un pour le choix, un pour la date, à moins qu'on ne puisse carrément récupérer la date du cookie ?
À suivre …
8 De Sacha - 01/12/2007, 20:56
Bonjour Franck Paul,
Il me semble qu'il n'est pas possible de récupérer la date de création d'un cookie (même si le navigateur garde pour lui la date d'expiration). On peut tout de même utiliser un seul cookie en utilisant la fonction
serialize()de PHP, par exemple.Mais, comme je me suis aperçu qu'un certain nombre d'autres plugins pouvaient se partager la même information (date de mise à jour de l'interface par l'utilisateur), il m'a paru plus intéressant de créer un cookie commun pour stocker cette information.
9 De Franck - 01/12/2007, 21:24
Bonne manière d'affiner l'usage du cache en effet (j'ai été jeter un œil au fil sur le forum).