1

I'm trying to customize the page template for a specific node of a specific content type. This is what I have: Content type: Custom Page Node ID: 2

First, I need to customize all 'Custom Page' content nodes so I created a custom page template for them: page--custom-page.tpl.php

Then, I also need to customize a specific 'Custom Page' node so I created a custom page template for it too: page--node--2.tpl.php

But when I visit the node 2 page it is using the Custom Page (page--custom-page.tpl.php) template and not the page template I created specifically for that node.

How can I make the custom page template for that node work?

6
  • You've cleared cache, yes?
    – Shai
    Commented Nov 11, 2014 at 3:15
  • Also, you wrote, "How can I have this custom node template work?" You aren't trying to create a node template (affect the layout of the content of the node) are you? The recipe you are following in your question is to create a page template to be applied only when a particular node is displaying.
    – Shai
    Commented Nov 11, 2014 at 3:18
  • And yes, I cleared the cache :/
    – barrakuda
    Commented Nov 11, 2014 at 3:25
  • What happens if you remove page--custom-page.tpl.php. Will it work for node/2 in that case?
    – Shai
    Commented Nov 11, 2014 at 3:29
  • Yes, when I remove page--custom-page.tpl.php, page--node--2.tpl.php works on node 2
    – barrakuda
    Commented Nov 11, 2014 at 3:33

3 Answers 3

2

Templates are chosen based on the other that they are in the $variables['theme_hook_suggestions'] array.

So if you have a list:

page.tpl.php
page--node.tpl.php
page--node--1.tpl.php
page--node--edit.tpl.php

Then it will look from the bottom up and use the first template it finds.

From Drupal 7 Template (Theme Hook) Suggestions:

When the page is actually rendered, the last suggestion is checked. If it exists, that suggestion is used. Otherwise the next suggestion up is checked, and so on. Of course, if none of the overriding suggestions exist, page.tpl.php is the final suggestion. This also explains why page--front.tpl.php, if it exists, overrides any other suggestion for the front page: it is always the last suggestion for the page designated as the front page.

Because you have custom code (I'm assuming your code here) that adds a tempalte suggestion to the end of that like this:

$variables['theme_hook_suggestions'][] = 'page__custom_page';

Then that suggestion is added to the end of the list, so will override all previous ones if it is present.

If you want to have different template precedence then you have to make the hook suggestions array use that order.

There are a number of ways you can do this and it depends what you want to achieve as to how you want to do it.

If you want your template to be last in the template precedence (first in the array) then you can do this:

array_unshift($variables['theme_hook_suggestions'], 'page__custom_page');

Other than that you can also use other PHP array manipulation functions to insert your suggestion in the middle of the array, or you could add your suggestion to the end, then add other suggestions after it again (it doesn't matter if a suggestion is in the array multiple times, the first time it is checked it will be used).

0

So, this is how I accomplished what I needed.

The template that I'm using is calling the theme_preprocess_page hook in the templates.php file to allow custom page templates per content type:

function myTheme_preprocess_page(&$variables) {
  if (!empty($variables['node'])) {
    $variables['theme_hook_suggestions'][] = 'page__' . $variables['node']->type;
  }
}

So if I have a content type with the machine name of custom_page, I can place a template named page--custom-page.tpl.php in the myTheme/templates directory to target those content types.

Then, to target a specific node (which in may case is node 15) I added the following code to the function:

if(arg(1) == 15) {
  $variables['theme_hook_suggestions'][] = 'page__myCustomNode';
}

And created a page template named: page--myCustomNode.tpl.php and placed it in myTheme/templates directory.

This allowed me to have a custom page template for all custom-page content types, and a custom page template specifically for node 15, of the same content type.

The complete function looks like this:

function myTheme_preprocess_page(&$variables) {
  if (!empty($variables['node'])) {
    $variables['theme_hook_suggestions'][] = 'page__' . $variables['node']->type;
  }
  if(arg(1) == 15) {
    $variables['theme_hook_suggestions'][] = 'page__myCustomNode';
  }
}

I hope this helps someone needing to do the same!

If there is a better way of accomplishing this, please post it here! Thanks!!!

2
  • For obvious reason, I don't like hardcoded nid's. I'd add an extra field ( on/off checkbox ) in the Content Type(s), allowing you to 'flag' the node as having to use the custom page template. I'd then intercept it, and add the suggestion if the value of the checkbox is 1. This way, several nodes can use the template, without having to update or even use hardcoded nid's.
    – Vodde
    Commented Nov 11, 2014 at 11:27
  • I would also personally not hard code the node ID. If I wanted the user to have control of the template I would use Vodde's suggestion, otherwise I would use the existing node ID suggestion by putting the suggestions in the correct order. I have also updated my answer with a fix to some of the information (about the default page template overriding your if you put it first) and added a new code example.
    – rooby
    Commented Nov 11, 2014 at 15:05
0

I realize this is quite an old question, but recently I found myself having to do this enough times that I wrote a module that provides the ability to specify custom page.tpl.php and node.tpl.php files for individual nodes.

The code within the module uses the techniques already mentioned here, so it just makes the process a bit less complicated. You still have to create the template files yourself, but no template.php file modifications are necessary:

https://www.drupal.org/project/cts

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.