MODX Community

Any tips to re-theme a website based on date?

Has anyone tried to re-theme a website based on recurring dates? For example, automatically changing the look of a website for Christmas, Thanksgiving, 4th of July, or whenever?

Any tips you could share on making it work in a user friendly way?

1 Like

I’ve never done it but off the top of my head I would say write a snippet that checks the date and spits out different CSS files based on that. E.g.,
<link href="[[cssDateCheck]]">

1 Like

I believe contexts would work for this, using the date checker, but contexts are a little hard to set up and might not be so useful when trying to make say 4 different layouts based on date.

One potential wrinkle, I would think normally the period of time to display the seasonal layout would be more than one day

I think the really difficult part would be doing the designs. There are lots of ways to do this, but here’s one off the top of my head:

I wrote a blog post with a snippet that detects the four seasons, though I can’t find it. Here’s one I wrote that detects holidays. You could modify it to add a date range around each one, and use that to set a System Setting (you’d create) to the name of the season or a default for non-holidays. Then you could name each theme after the season, and use a System Setting tag to make the theme active.

A cron job could run the snippet each night around midnight.

It might be possible to do this by just using a different CSS file for each season. Then it would be dead easy to use the System Setting tag in the Template where you load the CSS file.

1 Like

I feel like contexts and cron jobs are way more complicated than is necessary. Pure CSS is the way to go unless the themes are so different they require significant markup changes. You could easily do the logic in a snippet like this:

$xmasStart = new DateTime('12/1 00:00:00');
$xmasEnd = new DateTime('1/1 23:59:59');
$now = new DateTime();
if($now >= $xmasStart && $now < $xmasEnd) {
    echo '<link rel="stylesheet" href="xmas_theme.css">';
}

Then your markup:

<link rel="stylesheet" href="base.css">
[[!addTheme]]

You can easily expand from here. You could also use TVs or system settings to provide options to change the date ranges or add additional holidays and themes without the need to modify the code.

3 Likes

A much better answer than the one I wrote at 3 a.m. :wink:

2 Likes

Wow that’s an elegant solution, very nice! And you didn’t start the Xmas theme until December, bravo!

1 Like

Thank you!

To my mind, Christmas does not start until after Thanksgiving lol

1 Like

I’m having trouble imagining how to get that to work with a TV?

1 Like

If you just want to be able to adjust the dates you can create a couple Date TVs for it and then use that output in your snippet in place of the date strings, though you’ll have to do a little formatting if you want to avoid specifying a year and have it recurr. If you do it this way and want to have it apply to the whole site, rather than just a particular page, you’ll have to check a specific page’s TVs in your template with something like getResourceField or pdoTools’ fast fields. In this case I would use the site’s home page as the repository for the TVs.

For more robust management, e.g. adding/removing themes and assigning start/end dates and CSS files to them, you’ll need MIGX.

1 Like

TBH, I think you’re better off without the TVs. You can modify the snippet I linked to to get the dates of the holidays for the current year, figure out your start and end days, and just return the name of the holiday if it applies at the moment.

Then the code would look like this and you’d never have to edit it:

<link rel="stylesheet" href="base.css">
[[!isHoliday]]
/* isHoliday snippet */
$output = '';
$holiday = getHoliday();  // call function to get the current holiday if any

if ($holiday) {
    switch $holiday {
         case 'Christmas':
             $output = '<link rel="stylesheet" href="xmas_theme.css">';
             break;

         case 'Easter':
             $output = '<link rel="stylesheet" href="easter_theme.css">';
             break;

         /* Etc. */
    }
}

return $output;
1 Like

Another way, in your template you can put a class on the body that changes each month, and then you can keep all your themes in the same css file, namespaced by month.

<body class="[[!+nowdate:default=`now`:strtotime:date=`%b`]]">

You have less control over when the theme changes as it is tied to the current month. But very simple.

3 Likes

I just skimmed the code there but it looks like all the holidays are hard-coded and Christmas isn’t one of them. If I’ve understood it correctly, one would need to be willing to accept those defaults to use that snippet without modifying any code. Neither would it provide a way for users to choose which holidays to “decorate” for and when they’d like to do so. Assuming one actually wants their users to be able choose such a thing. I wouldn’t go to the trouble of providing those kinds of options just for myself. :stuck_out_tongue:

1 Like

That’s why I said this in my post:

It wasn’t meant to be a solution, just some help in getting the date of the more difficult holidays. Since Christmas is always 12/25 it wouldn’t be too hard to add.

One solution would be to use that code to create an array something like this:

$output = '';
$holidays = array(
    'Christmas' = array(
         'begin' => strtotime($thanksgiving .  '+ 4days' ,
         'end' => strtotime('12/29/' . $year)
    ),
    'NewYears' = array(
        'begin' => strtotime('12/30/' . $year),
        'end' => strtotime('01/02' . $year+1),
     ),
     /* etc. */
);

foreach($holidays as $holiday => $endpoints) {
    if (time() > $endpoints['begin'] && time() < $endPoints['end']) {
        $output = '<link rel="stylesheet" href="' . $holiday . '_theme.css">';
    }
}

return $output;

You’d have to make sure the ranges don’t overlap and would probably want to add a time to the dates.

If you want to let users control which they see, you could create a form with checkboxes and store the result as a comma-separated list in a User Setting called user_holidays, then do this:

$holidaysToShow = explode(',', $modx->getOption('user_holidays');

Then surround the $ouput = line like this:

if (in_array($holiday, $holidaysToShow)) {
       $output = '<link rel="stylesheet" href="' . $holiday . '_theme.css">';
}
1 Like

I just did this for Black Friday and Cyber Monday. Assuming for the holidays, Black Friday, Cyber Monday the charges are mostly colors and in most cases just a few CSS declarations are needed.

I did not add a new css file but just a class value to the html tag and a higher order declaration against it.

<html class="[[!siteTheme]]" .... >

snippet “siteTheme” with similar switch statement like you see in above posts with the return value of the classname

<html class="theme_blackfri"...>

CSS example

body { /* normal every day color */
background: #fff;
}

html.theme_blackfri body{
background: #000;
}

etc etc

3 Likes

Nice solution! :slight_smile:

1 Like