More Power to ExpressionEngine URLs

When playing “contract engineer”, you sometimes have to jump in and work with a less than ideal codebase. This was the case on a recent project I helped out on; the codebase is an install of ExpressionEngine 2 (EE2), a publishing system (CMS) developed by the fine people at EllisLab, favored by web designers all over the place. While I personally find it too limiting for my tastes (I suspect this is due to my doing less design based work these days), I can understand why people choose to work with it – highly sensible defaults with a pleasing overall control panel design that you can sell to customers. We can all agree that not reinventing the wheel is a good thing.

That said, I would be lying if I didn’t note that there are a few things about EE2 that bug me. I’ll write about them each in-depth in their own articles; the focus of this one is on the somewhat limiting URL structure that EE2 enforces on you, as well as how to get around this and obtain a much higher degree of flexibility while still re-using your same EE2 essentials (templates, session handling, etc).

The Scenario to Fix

The way that EE2 handles URL routing is pretty simple, and works for a large majority of use cases. The short and sweet of it is this:

http://example.com/index.php/template_group/template/

That url will render a template named “template” that resides inside “template_group”, taking care of appropriate contextual data and such. Let’s imagine, though, that for SEO-related purposes you want a little more dynamism in that url – the “template_group” should act as more of a controller, where it can be re-used based on a given data set. What to do about this…

Wait! EE2 is CodeIgniter!

This is where things get interesting. EE2 is actually built on top of CodeIgniter, an open source PHP framework maintained by EllisLab. It’s similar to Ruby on Rails in many regards.

That said, if you’re new to web development and reading this, please go learn to use a real framework. Learning PHP (and associated frameworks) first will only set you up for hardships later.

Now, since we have a framework, we have to ask ourselves… why doesn’t EE2’s setup look like a CodeIgniter setup? Well, EE2 swaps some functionality into the CI build it runs on, so things are a bit different. This is done (presumably) to maintain some level of backwards compatibility with older ExpressionEngine installations.

Exposing the Underlying Components

The first thing we need to address is the fact that the CodeIgniter router functions are being overridden. If you open up the main index.php file used by EE2 and go to line 94-ish, you’ll find something like the following:

You’re gonna want to just comment those lines out. What’s basically going on there is that this is saying “hey, let’s just have every request go through this controller and function”, but we really don’t want this. By commenting these out, the full routing capabilities of CodeIgniter return to us.

One thing to note here is that if our desired route isn’t found, ExpressionEngine will still continue to work absolutely fine. This is due to a line in the config/routes.php file:

The default controller, if no route is found matching the one we’ve specified, is the EE controller, so nothing will break.

Controllers and Re-using Assets

So now that we’ve got a sane controller-based setup rolling, there’s one more problem to tackle: layouts and/or views. Presumably all your view code is built to use the EE2 templating engine; it’d be insane to have to keep a separate set of view files around that are non-EE2 compatible, so let’s see if we can’t re-use this stuff.

A basic controller example is below:

Now, viewing “/example/12345″ in your browser should bring up a page that simply prints “12345″. The noteworthy pieces of this happen inside the construct method; there’s a few pieces that we need to establish in there so we have a reference to the EE2 components.

Now, to use our template structures once more, we need to add in a little magic…

This render method should be added to the controller example above; it accepts three parameters – a template group, a template name, and an optional multi-dimensional array to use as a context for template rendering (i.e, your own tags). If the last argument confuses you, it’s probably best to read the EE2 third_party documentation on parsing variables, as it’s actually just using that API. There’s really less black magic here than it looks like.

With that done, our final controller looks something like this…

Awesome! Now what?

Please go use a more reasonable programming language that enforces better practices. While you’re at it, check out one of the best web frameworks around, conveniently written in said reasonable programming language.

Of course, if you’re stuck using PHP, then make the most of it I suppose. If this article was useful to you, I’d love to hear so!

Tags: , , ,

7 Responses to “More Power to ExpressionEngine URLs”

  1. I’m not a programmer so don’t know quite what your trying to accomplish…It’s true that EE’s standard URL parsing is templateGroup/template/something, but, you can use dynamic=”off” and put anything you want in the URL segments to tell your tags what to render. For anything other than a blog or straight content site I never use the standard EE method.

  2. @PXLated: I think you mean dynamic=”no”, no? Think it used to be “off” but got swapped.

    At any rate, that’s not really what this is meant to accomplish. I can’t really detail the project I was working on as it’s not directly mine, so professional courtesy of course dictates keeping it under wraps, but I’ll note that this was a case where there was a rather large data model that we still wanted to allow people to edit via EE2’s interface, but the model itself wasn’t conducive to the way EE2 handles URLs in general.

  3. when i was searching yahoo just for this issue, I feel that its no answer for me , but thanks god , your article save me from this!2

  4. Great stuff! I had almost given up getting CI and EE to work side by side. So this is exactly what i needed.
    Also, you convinced me to give django/python a go. Most useful blogpost in a long time. Thank you so much!

  5. Is there a way to make global variables work in these templates? Things like {site_name}, {site_url}, etc etc?

  6. Disregard previous comment…

    For anybody trying to do this, I ran into a few bugs in the code. Here’s the controller I eventually got working:

    This also will render global variables.

    core->_initialize_core();
    $this->EE = $this->core->EE;

    /* This is required to initialize template rendering */
    require APPPATH.'libraries/Template'.EXT;
    }

    private function _render($template_group, $template, $opts = array()) {
    /* Create a new EE Template Instance */
    $this->EE->TMPL = new EE_Template();

    /* Run through the initial parsing phase, set output type */
    $this->EE->TMPL->fetch_and_parse($template_group, $template, FALSE);
    $this->EE->output->out_type = $this->EE->TMPL->template_type;

    /* Return source. If we were given opts to do template replacement, parse them in */
    if(count($opts) > 0) {
    $this->EE->output->set_output(
    $this->EE->TMPL->parse_variables(
    $this->EE->TMPL->parse_globals($this->EE->TMPL->final_template),
    array($opts)
    )
    );
    } else {
    $this->EE->output->set_output($this->EE->TMPL->final_template);
    }
    }

    function test($ext) {
    return $this->_render('test', 'testing', array(
    'var' => 'yes',
    ));
    }
    }

    /* End of file */

  7. Hey Dennis – thanks for the code, that’s awesome!

Leave a Reply