Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.
15:23

Apply the DRY Principle to Build Websites With ExpressionEngine 2


ExpressionEngine 2 is a wonderful CMS and arguably the most designer-friendly one out there, used by many well-known names like A List Apart, Andy Clarke and Veerle Pieters. Ironically, however, its default configuration is poorly suited for use in a professional web development workflow, which usually involves multiple sites, servers, and developers.

This tutorial will show you how to customize ExpressionEngine 2 so you can hit the ground running with a rock solid yet flexible starting point that can easily be deployed to multiple environments in minutes.


Overview

I’m not a programmer. However, the programming mantra don’t repeat yourself, or the DRY principle for those acronym lovers among us, has really begun to resonate within me as I get more involved both with web development and running my own business. In fact, DRY is good advice for living out your life in general. Repeating yourself costs more time up front, and potentially a lot more down the road if you have to go back and make the same change in multiple places.

Plus it’s a hindrance for personal growth because if you’re doing something you’ve already done, you’re not learning something new. What’s better is to identify those places where you do repeat yourself and come up with a system to standardize that task or piece of data.


A Little History

When I first started working with ExpressionEngine a year and a half ago, it was a one-off project and I was a novice designer. Needless to say, the DRY mentality was the furthest thing from my mind. I was happily humming along, mucking with settings as the situation dictated, not documenting anything and having a blast with custom fields and template groups, those things that make EE a designer’s dream come true. It was sort of like my first date with the software. In the end, I liked EE so much that I decided to get exclusive and “marry” it as my CMS of choice for all future projects.

After about the third or fourth site, however, I began to see flaws in our relationship (as is liable to happen when you really get familiar with something) and got frustrated doing menial, repetitive tasks related to deploying and managing EE. This was especially apparent with some ongoing projects which required twice or thrice weekly updates from development to staging to live servers. It got to the point that I was spending nearly as much time managing deployments as I was actually coding.


The Solution

Not content to lose money and slave away at boring drudgery, I sought to tidy up the mess.

What follows is the fruit of my and others’ labor, a guide to applying the DRY principle to developing and deploying sites with EE.

It walks you through how I’ve tweaked and customized ExpressionEngine 2’s flabby, nonsensical default configuration into a lean, efficient workhorse that takes nearly all the repetition out of working with EE. Specifically, these modifications will:

  • Provide a starting point with all the commonly used addons installed and settings turned on so you’re not running the installation wizard and starting from scratch every time.
  • Integrate EE with a version control system of your choice for rapid deployment to multiple web servers or developers’ workstations and easy management of code. My experience is with SVN but all the principles apply to Git as well.
  • Centralize all settings and configs to facilitate easy migration from one server to another, so launching and pushing updates is a cinch rather than a headache.

This has been a rather large endeavour and I couldn’t have done it alone. A big thanks go out to the following people, who helped me whether they knew it or not:


Step 1: Download and Installation

For your sanity’s sake get a fresh copy of the latest build of EE 2 before you do any of this. Download and install as normal, preferably on a local server, as you’ll be making lots of changes to the files. Leave out the Agile Records templates when you are prompted.


Step 2: Pouring Out the Config Soup

If you’ve ever had to migrate ExpressionEngine from one server to another, you know that this task is no easy feat; in fact, it’s a complete nightmare if you’re unprepared. A lot of this stems from the fact that ExpressionEngine stores config variables and server paths all over creation, to the point that it’s difficult to track them all down and adjust them when you move servers.

Deployment requires updating the URL and path information in literally about a dozen places. It’s clumsy, time-consuming, and error prone.”

Kenn Christ’s quote on your right is right on. Fortunately, there’s another way. Rather than editing all those variables in a dozen places in the control panel and probably forgetting some, you can consolidate them in one place—the config file. By default, ExpressionEngine stores config information that you will need to worry about in two files. These are:

  • system/expressionengine/config/config.php
  • system/expressionengine/config/database.php

Ditching database.php

As you might imagine, database.php stores the MySQL database connection information. I suppose EllisLab takes the position that it’s easier to find the DB information if it’s in it’s own aptly named file, but I’m going to argue the opposite. This is DRY, damn it! I’d rather open one file and edit my settings from one place, not two, so I did away with database.php altogether. Well, not quite, but I did take all the database settings from it and move them to config.php with a little PHP.

<?php

if ( ! defined('EXT')){
exit('Invalid file request');
}

/* THIS FILE WILL NEED PERMISSIONS SET TO 400 OR SIMILAR SO EE DOESN'T OVERWRITE IT. */

require 'config.php';
break;

}

?>

You’ll never need to open database.php again.

Consolidating config.php

So now we have our database settings in config.php, plus a bunch of other stuff that you’ve probably edited in the control panel but had no idea it could hang out here as well, like template preferences, themes preferences, CP URL etc. Great, so we’re all done and we can deploy from our version control repository to any server we please with the tap-tap-tap of an SSH command.

Wrong. Here’s our problem; when EE moves from one server to another, things like the database connection settings need to change to reflect the new server environment. If we want to use EE with a version control system (and trust me, we do), then every time we deploy a working copy to a new server, we would need to download a copy of the config.php, edit the settings so they’re correct for that server, FTP it back up to the server, and make sure to tell our version control to ignore it when we issue a commit or update.

Best case scenario, we’d have a separate, non version-controlled config file for each additional server on which the site resides. For me (and I’m a one-man show) that’s:

  • iMac’s local server
  • Macbook Pro’s local server
  • staging server
  • live server

Add another couple developers if you work at an agency and you’re looking at a lot of these buggers running around. So what happens when you need to change another config variable, like the license number? Do you email yourself and other developers a copy of this file and upload it to all servers one by one? DRY, my friends, DRY. The only logical answer is a single, version controlled config.php file which can accommodate all server environments.

Nonsense, you might say, but thanks to some clever PHP it is indeed possible. As you can see, the PHP case syntax looks for an IP address and serves what I call environmental config variables based on that IP. Now the only things you need to know and change when you deploy to a new server are the IP address and the database connection information, which should be readily available to you.

switch ( $_SERVER['SERVER_ADDR'] ) {

    // local
    case '127.0.0.1' :
	$db['expressionengine']['hostname'] = "localhost";
	$db['expressionengine']['username'] = "root";
	$db['expressionengine']['password'] = "password";
	$db['expressionengine']['database'] = "local-db";
    break;

    // staging
    case '72.10.54.22' :
	$db['expressionengine']['hostname'] = "mysql.exampleserver.com";
	$db['expressionengine']['username'] = "admin";
	$db['expressionengine']['password'] = "password";
	$db['expressionengine']['database'] = "staging-db";
    break;

    // live
    case '82.335.65.67' :
	$db['expressionengine']['hostname'] = "mysql.exampleserver.com";
	$db['expressionengine']['username'] = "admin";
	$db['expressionengine']['password'] = "password";
	$db['expressionengine']['database'] = "live-db";
    break;

}

At this point I want to distinguish between what I call environmental variables and universal variables.

  • Environmental variables are different on each server environment.
  • Universal variables are the same no matter which server the site resides on, so they go outside the IP switch/case syntax.

These are things like the server paths and URLs to the themes folder, template folder, CAPTCHAs, the license number, basically anything besides the aforementioned database information and IP address (these are all commented in the included file for reference).

Did you hear me say that server paths and URLs stay the same no matter what server you’re on? Yes you did. As long as your site’s folder structure remains the same in every instance (and if you’re on version control it obviously will), PHP variables detect the root server path and URL and fill them in for you. Why EE doesn’t do this to begin with baffles me, but I digress. No more forgetting to change the server path to your themes folder when you migrate servers and spending an hour figuring out why you have a blank screen instead of a CP. Anyone excited yet?

/*
|--------------------------------------------------------------------------
| ExpressionEngine Config Items
|--------------------------------------------------------------------------
*/

$config['app_version'] = "211";
$config['license_number'] = "0000-0000-0000-0000";
$config['debug'] = "1";
$config['install_lock'] = "";
$config['system_folder'] = "admin";
$config['doc_url'] = "http://expressionengine.com/user_guide/";
$config['is_system_on'] = "y";
$config['cookie_prefix'] = "";
$config['site_name'] = "Flourish Interactive Codebase";
$config['allow_extensions'] = "y";

/* General
-------------------------------------------------------------------*/
$config['site_index'] = "";
$config['site_url'] = "http://".$_SERVER['HTTP_HOST'];
$config['server_path'] = $_SERVER['DOCUMENT_ROOT'];
$config['cp_url'] = $config['site_url']."/".$config['system_folder'];

/* Universal database connection settings
-------------------------------------------------------------------*/
$active_group = 'expressionengine';
$active_record = TRUE;
$db['expressionengine']['dbdriver'] = "mysql";
$db['expressionengine']['dbprefix'] = "exp_";
$db['expressionengine']['pconnect'] = FALSE;
$db['expressionengine']['swap_pre'] = "exp_";
$db['expressionengine']['db_debug'] = FALSE;
$db['expressionengine']['cache_on'] = FALSE;
$db['expressionengine']['autoinit'] = FALSE;
$db['expressionengine']['char_set'] = "utf8";
$db['expressionengine']['dbcollat'] = "utf8_general_ci";
$db['expressionengine']['cachedir'] = $config['server_path'].$config['system_folder']."/expressionengine/cache/db_cache/";

/* Member directory paths and urls
-------------------------------------------------------------------*/
$config['avatar_url'] = $config['site_url']."/uploads/system/avatars/";
$config['avatar_path'] = $config['server_path']."/uploads/system/avatars/";
$config['photo_url'] = $config['site_url']."/uploads/system/member_photos/";
$config['photo_path'] = $config['server_path']."/uploads/system/member_photos/";
$config['sig_img_url'] = $config['site_url']."/uploads/system/signature_attachments/";
$config['sig_img_path'] = $config['server_path']."/uploads/system/signature_attachments/";
$config['prv_msg_upload_path'] = $config['server_path']."/uploads/system/pm_attachments/";

/* Misc directory paths and urls
-------------------------------------------------------------------*/
$config['theme_folder_url'] = $config['site_url']."/themes/";
$config['theme_folder_path'] = $config['server_path']."/themes/";

/* Templates Preferences
-------------------------------------------------------------------*/
$config['save_tmpl_files'] = "y";
$config['tmpl_file_basepath'] = $config['server_path']."/templates/";
$config['site_404'] = "404/index";
$config['strict_urls'] = "n";

// END EE config items

Keep in mind that a universal variable can become an environmental variable if you need it to. Let’s say that you want to change your site name automatically based on the server it’s on, so you can tell at a glance if you’re looking at the local, dev or live version of your site. Just delete the variable from the “universal variables” area and copy it into each IP case syntax, assigning it whatever value you want.


Step 3: Cleaning House

Let’s face it; the default install of ExpressionEngine includes a lot of files you don’t need, especially if you’re a professional developer who’s not poking around for the first time.

These include the theme files for the Agile Records example site, smileys, wiki themes, and a lot more. Why fatten your site unnecessarily? Put EE on a diet and delete all this stuff, you can always grab a fresh copy and add it back in the unlikely event you need it for a wiki, forum or other community-based site. Delete only what makes sense for you, but I’ve done about a dozen EE sites and never used any of it.

  • /themes/wiki_themes
  • /themes/site_themes/agile_records
  • /themes/profile_themes/agile_records
  • /images/smileys
  • /images/avatars

Step 4: Create a Standard Top-level Folder Structure and .htaccess File

Like many tasks in web development, there’s no one right way to go about this, but what’s important is that you pick a way and stick to it. Some people like to put their static asset files (images, css, js, swf, etc.) in a /themes/site_themes/examplesite folder. I prefer to put each asset folder on the top level because I’m lazy and don’t like to click through three levels of subfolders to access these files during development, plus I like nice short URLs in my HTML and CSS.

Now that I’ve gotten used to a standard structure, I do not create additional top level files or folders unless absolutely necessary (you’ll see why in a minute). This is what my top level structure looks like.

  • .htaccess – will explain more in a minute
  • system – rename this please
  • css
  • favicon.ico
  • fw – this is short for “framework” e.g. my CSS background images
  • images – non CMS-managed content images
  • index.php
  • js
  • robots.txt
  • templates
  • themes – CP and fieldtype themes
  • uploads – where all CMS-managed docs and images go

Now I get around to talking about .htaccess. It’s a mystery to many developers and frankly it is to me too, but I know enough to use it to remove that unsightly index.php from EE’s otherwise pretty URLs. I use a variant of the exclude method from the ExpressionEngine Wiki. This is in no way guaranteed to work on your web host, but it’s worked for me on MAMP Pro, HostGator and MediaTemple, both (gs) and (dv). The usual caveats apply, e.g. mod_rewrite must be enabled in Apache’s http.conf etc.

If you’re using this method of removing index.php and wish to add a new top level file or folder to your site (and I mean a “real” file or folder, not an EE entry, template or template group), you’ll need to add an exception in .htaccess or else that file/folder will be inaccessible.


Step 5: Install Your Default Add-ons and Configure Them

After developing several EE sites, there are add-ons I am either unwilling or unable to live without. These are the best the EE development community has to offer and they have the honor of being installed in my codebase so that every new site has them from the get-go. They are (and these are all free):

Don’t just install these, configure them. For example, I have set up all my email notification templates for Freeform, created additional custom form fields based on what I usually use for a standard contact form, and I have a template called contact.html which has the front end form code in it, including JavaScript validation and a success message. Even if I need to add a field or two, or move that form code into a different template, it’s a matter of tweaking, not creating from scratch every time. DRY. Minus CSS styling, that form is ready to go out of the box.

Be on the lookout for another article by me soon as I discuss these and a couple of commercial add-ons for EE2 in more detail.


Step 6: Set Up Your Client’s Member Group

Giving unlimited access to my client is scary for both them and me.

This is one of those things you likely forget to do until you’re nearly finished with the site, but it doesn’t need to be if it’s in your codebase. The default EE administrator account belongs to the Super Admins member group, which necessarily has access to everything. Giving unlimited access to my client is scary for both them and me, so I create a second member group called Admins. I usually wait until they’ve picked an email address before I actually make their account but that only takes a couple seconds once you have the member group permissions defined.

In this member group I’ve turned off all access to the templates, site and member administration, communication module, and add-ons. All that most clients need to do is create and edit content, and maybe view their Freeform submissions. That’s it. Simplify their life and yours and take away what they don’t need. Again, I’ve had to tweak this before but a starting point is better than starting from scratch.


Step 7: Working With Your Codebase

Congratulations, you should now have a far superior starting point for your next ExpressionEngine project. So that you can add to it and reuse it, create a new project in your version control and commit your customized ExpressionEngine codebase as version number one. Below are examples of some common operations you’ll likely need to do once you’ve got new projects in the pipeline (may vary depending on server setup, or if you’re using Git instead of SVN).

Create a New Project – 10 minutes

  • Clear all caches of your codebase project.
  • Export database and import under new project name using PHPMyAdmin or similar.
  • SVN export a copy of your codebase to the working copy folder of a new SVN project. VERY IMPORTANT: Note that I said export, not checkout.
  • Set the following folders and their contents to permissions 777:
    • /templates
    • /uploads (or whatever your upload folder is named)
    • /system/expressionengine/cache/db_cache
  • Add DB connection info for new DB to config.php. Change the site name, license numbers and any other preferences you need to change.
  • Load up your control panel and change the file upload preferences. These are stored in the database and cannot be put in the config for some asinine reason.
  • Go nuts.

Deploy a Site to a New Server – 10 minutes

  • Clear all caches.
  • Export and import database using PHPMyAdmin or similar.
  • Find IP address and database info and add a new IP case section to config.php.
  • Commit config.php to your repository.
  • Check out your site’s repository to the public_html folder of your new server.
    • If it’s a local server use your SVN client.
    • If it’s a remote server use the SSH command svn checkout http://samplerepository.com/sampleproject/ . The space and dot after the trailing slash checks out the contents of the folder to the current folder, otherwise you’ll get public_html/sampleproject/index.php if you leave out the dot.
  • Set the following folders and their contents to permissions 777:
    • /templates
    • /uploads (or whatever your upload folder is named)
    • /system/expressionengine/cache/db_cache
  • Load up your control panel and change the file upload preferences.

Update a Site to an Existing Server – 1 to 5 minutes

  • Clear all caches (only if you’ve made changes to the database).
  • Export and import database using PHPMyAdmin or similar (only if you’ve made changes to the database).
  • Run an SVN update on your site copy:
    • If it’s a local server use your SVN client.
    • If it’s a remote server use the SSH command svn update. You shouldn’t need to re-enter the URL or password.
  • Load up your control panel and change the file upload preferences (only if you’ve made changes to the database).

Conclusion – Sojourning in the DRY Desert

As you go about your business designing and developing kick-ass ExpressionEngine websites, keep yourself mentally aware of what you’re doing at all times, from a big-picture, functionality perspective. Some pieces of website functionality are nearly identical across sites, they just need some minor markup tweaks and a CSS “skin” to easily transfer from one to another.

In the future, microformats will standardize the markup even more! These are ideal candidates for inclusion in your codebase. One we already discussed is the ubiquitous contact form. Some other potential “standard” functionality (I’ve had multiple clients ask for these things):

  • Blogs and their associated comment forms
  • Address or v cards
  • News release sections
  • XML or “Google” sitemaps
  • Search and search results pages
  • Custom Share This! type code
  • Facebook or Twitter timelines

You could theoretically have channels, categories, custom field groups and templates built out and ready to go (I know I do for a lot of these). Your client is still getting the same amount of value that they would if you hand-built these pieces for their site (arguably more since they’ll be refined and tested more often) and you do less work, meaning you can price yourself more competitively, or if you sell fixed fee, charge the same price and turn more of a profit. Remember to have fun and enjoy developing with ExpressionEngine!

(PRO)
No Soup for you

Don't be the product, buy the product!

close
YES, I want to SOUP ●UP for ...