Reusing Common Elements in Theme Template Files

Most developers are familiar with the phrase D.R.Y – Don't Repeat Yourself. It's sensible: if there are lots of different instances of the same bit of code used throughout your site, there's that many places that need to be visited in case something contained within that code needs to be updated. This is why PHP has functions like include().

Concrete CMS has similar functions – but it doesn't use PHP's include. Why? For one, Concrete has a relatively complex way of determining where files are located. Say you want to include a header menu in a particular theme. If this theme is packaged up, the system will need to know to look inside that special package directory. But, if the owner of a site copies that file into a root directory, then Concrete needs to look there first, instead of in the package. include() doesn't do enough.

So, how do you use something like include() in Concrete? You use the inc() method, which is found in the \Concrete\Core\View\View class. The instance of the current view is injected into your theme automatically, in this variable:

$view

Right now, our Urbanic theme has one page template – Full – so it's not crucially important that we start to separate certain bits of code into reusable elements. But once we get half a dozen page templates it's not a good idea to have the same exact header and footer code on each of those templates. So let's separate the part of the page that's the same on every page template into a reusable PHP element.

First, create an elements directory in the theme directory.

mkdir themes/urbanic/elements

Create a file named header.php and a file named footer.php in this directory.

Then, copy all HTML from the start of the tag to the start of the Main area. Move this HTML in header.php. Replace this HTML with

$view->inc('elements/header.php');

For the footer.php, copy all HTML from the DIV with the class templatemo-footer down to the closing tag. Replace this HTML with

$view->inc('elements/footer.php');

Files included by inc() are in the same scope as the original template files, meaning that $view->inc() will work from within includes as well as within the template files themselves. Loader::element() also works.

Now, when you create additional page templates, the same header.php and footer.php will be shared across all templates.

Since inc() is a method on an object, variables in the local scope of your page template won't be passed into the inc() method. If you need to pass a variable into the file included by $view->inc(), you can do so like this

$tab = 'tweets';
// I want to pass $tab into my header.
$view->inc('elements/header.php', array('activeTab' => $tab));

In the example above, $activeTab will have the value of $tab (tweets) in my header.php. Use this technique to build scalable, maintainable Concrete themes (without repeating yourself!)