Custom Drupal Templates by Path
I've had this issue crop up before, but never had a pressing need to solve it, or much time to search around to find the solution. Drupal has a great system of template naming where it allows you to use multiple different names for a template file (tpl.php) that will be used for a page depending on it's path.
Drupal Template Suggestions
Drupal's standard template naming works like the following example according to this information.
For example, if you were to visit example.com/node/1/edit, PHPtemplate would look for the following templates, in descending order:
page-node-edit.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
That's all fine and good, and works as expected. However, while working on iShrink.org yesterday, I needed something a little different than I usually do. Each of the main pages on that site require a completely different template, and as the site nears completion, several of the core pages will probably completely change layout. This poses the need that all of those pages have their own page.tpl.php template file.
Using the built in Drupal template suggestions, for the about page at iShrink.org/about, I could use the template page-node-1.tpl.php. As well as using page-node-2.tpl.php for the page at iShrink.org/services.
What's wrong here?
Well for starters, it might not be "too" hard to keep up with this if you are only modifying the page template for one or two pages, but imagine if this went to node30, and you had to remember that node 22 was pageX, etc. It would get quite confusing very fast. So a better alternative would be to have Drupal search for a file that was named page-about.tpl.php or page-services.tpl.php based on the two pages I listed above.
I found a snippet of code that could be added to template.php in your theme in order to accomplish this here. It almost works perfectly, but that'll come further down. The first snippet here is original, and has side effects if you use it as is.
function phptemplate_preprocess_page(&$vars) {
if (module_exists('path')) {
$alias = drupal_get_path_alias(str_replace('/edit','',$_GET['q']));
if ($alias != $_GET['q']) {
$suggestions = array();
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$suggestions[] = $template_filename;
}
}
$vars['template_files'] = $suggestions;
}
}
After first finding this after an hour or more of searching, I was extremely excited, as this would work great for other sites I've done as well. So I threw this function in my template.php file for the template in question, and whoosh, the first template I tested worked like a charm. However there was an issue that presented itself almost immediately.
I tested out the new code on a new blank page, the iShrink subscriptions page. It worked great, but once I went back to the home page, or any other page that used the standard template naming convention, those were all broken now. So what was happening is that this new function was completely overwritting the core name suggestion functions that occur in /includes/theme.inc.
The solution for perfect template naming
So now that we know what's happening, we can correct this by modifying this function before we implement it in our template.php file. What we need to happen to make this "perfect" is to have the function first use a template based on the path alias, and if it doesn't find one, use one from the standard Drupal naming system.
This is going to look backward in the following function, as it calls the standard Drupal scheme first, and THEN the alias checks, but the reason for this is that later in /includes/theme.inc, it will reverse the array that is created here. So the last item to be in the array will become the first, so in the end, if our alias path template is found, it will be presented to Drupal first when searching for the appropriate template.
So to finish it up, paste the following code into your template.php file assuming you are using a standard PHPtemplate theme of course.
function phptemplate_preprocess_page(&$vars) {
// first, proceed with a modifed version of the standard
// Drupal template suggestion calls
$i = 0;
$suggestions = array();
$suggestion = 'page';
while ($arg = arg($i++)) {
$suggestions[] = $suggestion .'-'. $arg;
if (!is_numeric($arg)) {
$suggestion .= '-'. $arg;
}
}
if (drupal_is_front_page()) {
$suggestions[] = 'page-front';
}
// next, check for templates that use the path alias
if (module_exists('path')) {
$alias = drupal_get_path_alias(str_replace('/edit','',$_GET['q']));
if ($alias != $_GET['q']) {
$template_filename = 'page';
foreach (explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$suggestions[] = $template_filename;
}
}
$vars['template_files'] = $suggestions;
} // end path alias template check
if ($suggestions) {
$vars['template_files'] = $suggestions;
}
}
Conclusion
So what this is going to do now is use the following order to look for templates when calling a page. (it will only operate the alias search if the path module is enabled)
page-about.tpl.php
page-node-edit.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
Hopefully this turns out useful for others, as I've looked far and wide, and finally found this solution. There may be some minor issues I haven't ran across yet with this code, and if there are, please add them as a comment so I can correct them. I may attempt later to add this in as a simple module so it can be quickly added to any template across a new site that I work on.
General Categories
My Latest Tweets
- Please wait while my tweets are loading, or if there's an issue, just go to my twitter page.
Protected iShrink Links
Also, as a note, sorry the links to iShrink.org are currently password protected. I wanted them linked for future reference, but for now, it's still under heavy development, and not ready for any public viewing.
page-node-edit.tpl.php as top option
So I've played with this some today, and as it is, I think it works fine, and gives the template suggestion order like listed.
page-about.tpl.php
page-node-edit.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
My problem later became that the page-node-edit.tpl.php needed to be the final option, NOT the custom templates... Reason for this being that in the iShrink project, the edit pages need to take up the FULL width of the layout, as it is a very narrow layout to begin with.
So, I've created a module that changes the order of how the templates are being rendered to the following
On
http://iShrink.org/node/1/edit (about page edit)
page-node-edit.tpl.php
page-about.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
On http://iShrink.org/about/
page-about.tpl.php
page-node-1.tpl.php
page-node.tpl.php
page.tpl.php
I may consider releasing this later, but for now, it's on my back burner for personal use.
really useful for me thank
really useful for me thank you very much
Post new comment