jereme claussen

Concrete5 and magical theme switching

In a recent project I was confronted with a technology challenge in Concrete that had "fun" and "pain" written all over it.  The task was to produce a website that has multiple themes; one generic, one we'll call "rockets" and one we'll call "torpedoes".  Upon entering the site, a user could chose to view information about rockets, torpedoes, or they could view  a small handful of generic pages.  The trick was this... Once they viewed either rockets or torpedoes, all of the generic pages should from that point assume the theme of either rockets or torpedoes?

Confusing?  Kind of...  The motivation was, once the user chooses a vertical, their experience should remain consistent across all pages unless they switch verticals.


I got my trusty friend MIRV involved as nobody outside of Concrete knows the core like he does.  He quickly pointed out that we could easily set the theme on the fly using site_theme_paths and the setTheme() function off the view object.

That part was simple:

$v = View::getInstance();
$v->setTheme("torpedoes");

The next trick was to come up with a way to indicate which theme should be used.  It was pretty simple to employ a cookie here.  This only added one line of code:

$useTheme = $_COOKIE['useTheme'];
$v = View::getInstance();
$v->setTheme($useTheme);

There was an immediate problem.  We could no longer access login or the dashboard as it was using a theme based on the cookie.  This process had naturally hijacked the whole theme functionality of Concrete5.

The next riddle was to come up with a way to determine what pages actually qualify for theme switching.  Our first pass was to investigate the REQUEST_URI environment variable and select it based off of that.  This had two major drawbacks.  The first is that if pages weren't carefully added to the site, they might fall out of our path-based rules and fall back to the wrong theme.  The second was that this was heavily dependent on pretty url's.  Anybody with a good amount of Concrete5 experience knows that through editing pages, you often fall out of pretty URL's back to form GET driven URL's.

After repeatedly smashing my head against a wall, I started to investigate how I could determine what theme the requested page uses by default.  If I could determine that it was the generic theme, then I'd know that I need to switch this theme out when our cookie is set.  With only two possible URL configurations, this wasn't too hard.

if( preg_match("/cID=(\d+)/", $_SERVER['REQUEST_URI'], $matches) ) {
  $cID = $matches[1];
  $page = Page::getByID($cID);
} else {
  $page_path = preg_replace(array("#" . DIR_REL . "#", "#/$#"), '', $_SERVER['REQUEST_URI']);
  if( $page_path == '/' ) {
    $page = Page::getByID(1);
  } else {
    $page = Page::getByPath($page_path);
  }
}
$theme_handle = $page->getCollectionThemeObject()->getThemeHandle();

Though there's probably a prettier way to grab the Page object with pretty url's, this was the most consistent method I arrived at, and now we had our theme handle stored in a variable for inspection!

The last part of the site_theme_paths puzzle was to act on this theme handle like so:

if($theme_handle == "generic" && !preg_match("/login/", $_SERVER['REQUEST_URI'])) {
  $v->setTheme($useTheme);
}

You'll notice that I had to do an extra check to see if we are at the login page.  I'm not sure why the login page meets the requirement of having the generic theme.  It's not because of the name "generic" as in my application my theme wasn't named "generic".  Rather than dig deep to figure this out, I just filtered it out with a regex match.

All stitched together, my site_theme_paths.php file looked like:

/* Look for a theme to use based on the useTheme cookie */
$useTheme = $_COOKIE['useTheme'];

if (!is_null($useTheme)) {
  if( preg_match("/cID=(\d+)/", $_SERVER['REQUEST_URI'], $matches) ) {
    $cID = $matches[1];
    $page = Page::getByID($cID);
  } else {
    $page_path = preg_replace(array("#" . DIR_REL . "#", "#/$#"), '', $_SERVER['REQUEST_URI']);
    if( $page_path == '/' ) {
      $page = Page::getByID(1);
    } else {
      $page = Page::getByPath($page_path);
    }
  }
 
  $theme_handle = $page->getCollectionThemeObject()->getThemeHandle();
  if(preg_match("/phillips_generic/", $theme_handle) && !preg_match("/login/", $_SERVER['REQUEST_URI'])) {
    $v->setTheme($useTheme);
  }
}

 

The next step was to come up with a very basic javascript library to set this cookie.  I could have gotten much fancier than this, but I had MIRV create a simple function that I could run from anywhere to set the cookie.

function setTheme(themeName) {
    var expires = 60 * 5; //5 minutes
    if (themeName != "" && themeName != null) {
    document.cookie = "useTheme="+ themeName +
     ";expires=" + expires +
    ";path=/";
    }
}

Then, in my torpedo and rocket themes, I had this bit of javascript:

$(document).ready(function() {
  setTheme('rocket');
});

The end result?  If you hit any rocket or torpedo page, the cookie gets set.  From then on, any generic pages you visit will assume the proper theme.  If you switch sides, no problem, the cookie updates and you get the new theme.

In the end, we were able to prove the concept and see that it wasn't what the client wanted after all, but I thought I'd give it a home on the Internet so that others might find it.





Please add a comment

Posted by Mark A. on
Found your story while investigating ways to build a multilingual Concrete5 site. Still not sure how but that makes me feel better ;-)
Leave a Reply



(Your email will not be publicly displayed.)

Please type the letters and numbers shown in the image.Captcha Code



Order Accutane no Prescription Buy Tablets Clomid Take Lasix Cheap Buying Baclofen no Prescription Purchase no Prescription Strattera Take Prednisone Without Prescription Cheapest Tetracycline Pills Take Doxycycline Cheap Purchase Propranolol cod Purchase Online Without Prescription Nolvadex Buy Metformin pills Purchase generic Furosemide Buy Acomplia pills Take Bactrim Pills Purchase Fluoxetine meds Without Prescription Purchase Antabuse generic Take Hydrochlorothiazide Next Day delivery Buying Without Prescription Erythromycin Pills Purchase Lithium Carbonate Purchase Abilify meds Without Prescription Cheapest Order Cymbalta Purchase Online Without Prescription Clavamox Take Cipro Pills Purchase Cytotec Without a Prescription Buying Levaquin no Prescription Buy Tablets Revia When to Take Ventolin Generic Order Benicar When to Take Aricept Purchase Clonidine Without a Prescription Purchase Stromectol free delivery Purchase generic Rimonabant Buy alternative Diflucan Pills Buying Proscar Buy Without a Prescription Ampicillin Order Seroquel Next Day Delivery Purchase no Prescription Alli Buying Inderal legally Purchase Elavil no Prescription Buy Yasmin medication Purchase no Prescription Proventil Order Maxalt Medication Take no Prescription Actonel Buy generic Accutane Take Clomid Without Prescription Purchase Cheap Lasix Buying Baclofen legally Order Cheap Strattera Buying Prednisone legally Buy Tetracycline Overnight delivery Buy Doxycycline from Canada Buy Cheap Propranolol Order no Prescription Nolvadex Purchase Cheap Metformin Take Furosemide Without Prescription Purchase Acomplia alternative Order Bactrim no Prescription Purchase Fluoxetine no Prescription Buying Antabuse Purchase Hydrochlorothiazide generic Purchase Erythromycin alternative When to Take Lithium Carbonate Buying Abilify on line Buy no Prescription Cymbalta Buy Tablets Clavamox Online Buy Cipro no Prescription Buying Cytotec legally Buying Levaquin no Prescription Order no Prescription Revia Order Ventolin Medication Order Benicar Next Day Delivery Order Online Without a Prescription Aricept Buying Clonidine Take Stromectol Pills Buy Without a Prescription Rimonabant Purchase Cheap Diflucan Buy no Prescription Proscar Generic Order Ampicillin Online Buying Seroquel Buying Alli no Prescription Take Inderal Pills Purchase Elavil alternative Buy no Prescription Yasmin Alternative Buying Proventil Generic Order Maxalt Purchase Actonel Without a Prescription Take no Prescription Accutane Buy Clomid cod Buy Lasix from Canada Buy Cheapest Baclofen Pills Purchase Strattera Generic Order Prednisone Buy Tetracycline Tablets Buying Pills Doxycycline Buy Cheap Propranolol Buying Nolvadex Purchase Metformin free delivery Purchase Cheap Furosemide Buy Tablets Acomplia Online Online Buy Bactrim Without a Prescription Purchase Fluoxetine meds Without Prescription Buy Without a Prescription Antabuse Buy generic Hydrochlorothiazide Buy no Prescription Erythromycin Purchase Cheap Lithium Carbonate Buy Tablets Abilify Online Order Cymbalta Next Day Delivery When to Take Clavamox Online Order Cipro Without Prescription Buy Cheapest Cytotec Order Levaquin Pills Buy Without a Prescription Revia Buy Tablets Ventolin Online Generic Order Benicar Buying Without Prescription Aricept Take Clonidine Next Day delivery Buy Stromectol Tablets Buy Rimonabant next day delivery Buying Without Prescription Diflucan Purchase Proscar free delivery Cheapest Ampicillin Pills Purchase Seroquel no Prescription Buy Pills Alli Online Purchase Inderal generic Online Buy Elavil Without a Prescription Purchase no Prescription Yasmin Purchase Cheap Proventil Purchase no Prescription Maxalt Order Online Without a Prescription Actonel purchasing Accutane Pharmacy Without Prescription Buying Pills Clomid Purchase Cheap Lasix Purchase Baclofen meds Without Prescription Buy Strattera no Prescription Buy Cheap Prednisone Buy Tetracycline Online Purchase Doxycycline alternative Buying Propranolol no Prescription Tablets Buy Nolvadex Buy Without a Prescription Metformin Buy Furosemide cod Buy Acomplia next day delivery Buy Cheapest Bactrim Purchase generic Fluoxetine Buy Pills Antabuse Online Buy Tablets Hydrochlorothiazide Online Buy Erythromycin Overnight delivery Generic Order Lithium Carbonate Buying Abilify Pharmacy Without Prescription Buy Cheap Cymbalta Purchase Clavamox generic Cheapest Order Cipro Buy Cytotec Overnight delivery Buy no Prescription Levaquin