Skip to content

Automating CSS Changes with ExpressionEngine

Color picker plus preview 01 full

With a bit of SCSS, ExpressionEngine and a color picker field type, we gave our client the ability to update CSS throughout the site.

Our client has a fairly normal request: give each of our departments a unique color palette, while keeping the design integrity in-tact - AND - if we add new departments in the future, we want to be able to add those, with their custom colors too. We explored a couple of options, including writing some CSS overrides inline and building a custom CSS snippet they could edit for each department. These options forced the client to manage a lot of code, and gave the potential for significant breakage in their design if they did it wrong.

What if we gave the client a few color picker fields to customize the palette, and the system rebuilt the CSS after the record was saved? That would be slick, safe, and immensely helpful to our client who only wants to make a few tweaks and not learn a whole new set of rules for how to manage CSS on their site.

What did we add:

  • Use the pages module to generate pages of the site
  • Add a color picker field type to the channel used by the page
  • Create a custom module to update the CSS from a SCSS definition file (this module includes an SCSS php compiler from when the Channel Entry Submission End hook is called.
  • Load the custom CSS in the page template

Pages Module

You could use Structure, Native Layouts or the classic Templates approach, but whatever path you choose, you'll need to store the custom color data in a channel entry and listen for the field to be updated in order to regenerate the custom CSS.

Color Picker

There are a few out there that will work fine. We went with Color Picker Plus to have the flexibility to define a custom palette for the customer if they ever wanted that. At the time of this writing, it's only $14.50, if that's too rich for your bones, take a look at the Noah Kuhn's free Color Picker field type. In the end, you need to end up with a hex value in the field content.

Custom module to update the CSS from the SCSS definition file.

This is where the magic happens. Build a simple extension to listen for the "Channel Entry Submission End" developer hook. When the right entry is being saved, load the color from the entry, load the SCSS file, compile it using the library with the CSS destination... and clear your cache because the work is done. We included a couple of ExpressionEngine fields in the SCSS file, which are swapped out in the extension prior to compilation. If there is no color set in the channel entry, we fall back to the corporate colors.

Extension Code (listening for the "entry_submission_end" hook)

public function entry_submission_end($entry_id, $meta, $data) {
    $entry_type_field = 'field_id_'.$this->settings['page_type_field'];
    if ($meta['channel_id'] == $this->settings['pages_channel']) {
        require_once dirname(dirname(__FILE__)) . '/graybox_ui/libraries/scss/';
        // get a list of all departments
        $departments_query = $this->EE->db
            ->where('exp_channel_titles.entry_id = exp_channel_data.entry_id')
            ->where('exp_channel_titles.channel_id', $this->settings['pages_channel'])
        // primary color: field_id_28
        // secondary color: field_id_29
        $primary_color_field = 'field_id_'.$this->settings['department_color_primary_field'];
        $secondary_color_field = 'field_id_'.$this->settings['department_color_secondary_field'];
        // load the template
        $path_to_sass = $this->EE->config->item('sass_path');
        $sass_template = file_get_contents($path_to_sass.'custom/_color-swap.scss') or die("Unable to open SASS template");;
        foreach ($department_query->result() AS $department_row) {
        $department_name = $department_row->url_title;
        $department_primary_color = $department_row->$primary_color_field;
        $department_secondary_color = $department_row->$secondary_color_field;
        if ($department_primary_color == '') {
            $department_primary_color = '5DA5CF';
        $department_sass_template = $sass_template;
        $department_sass_template = str_ireplace('{{primary_color}}', '#'.$department_primary_color, $department_sass_template);
        $department_sass_template = str_ireplace('{{secondary_color}}', '#'.$department_secondary_color, $department_sass_template);
        $filename = $this->EE->config->item('departments_css_folder').'style-'.$department_name.'.css';
        $department_scss = new scssc();
        $department_css_content = $department_scss->compile($department_sass_template);
        $dept_style_file = fopen($filename, "w") or die("Unable to write CSS files");
        fwrite($dept_style_file, $department_css_content);

In the SCSS file, we have a few variables:

/* Two-Tone Color Set
$primary:  {{primary_color}};
$secondary:  {{secondary_color}};
$lighter:  lighten($primary, 15%);
$lightest: lighten($primary, 55%);
$darker:   darken($primary, 15%);

Update your paths, and you're all set to go! The client can update the CSS with whatever field content you select in your channel entry, giving them the freedom and the safety of not being able to easily break their design.

Happy Coding Friends!

Blog & Events

Featured Work