欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

drupal 自定义模板建议 顺序

shiping1 的头像

Working with template suggestions

Last updated July 17, 2013. Created by LeeHunter on February 18, 2008.
Edited by pcoucke, chrisjlee, heather, rootwork. Log in to edit this page.

Template suggestions are alternate templates based on existing .tpl.php files. These suggestions are used when a specific condition is met and a matching file exists. All layers from core, modules, theme engines and themes can provide the suggestions. You can think of them as naming hints telling the system to pick and choose based on the right circumstances. The idea is simple but it is a powerful feature providing another layer of customization.

Theme Developer module showing template suggestions for the possible "page" templates. The image shows Drupal 6 template suggestions.
devel showing Drupal 6 template suggestions

These naming suggestions are set from preprocess functions. There are plenty already provided by core. If you need to extend it further, add a preprocessor for the theming hook into your template.php file. The examples below add suggestions on the "node" and "page" theming hooks. It can be added to any hook implemented as a template.

Drupal 7

A listing of all the suggestions for Drupal 7 core can be found in Drupal 7 Template Suggestions.

To use the examples below, paste the function definitions into a template.php file in your theme directory, ex: "sites/all/themes/drop/template.php". If a template.php file does not exist in your theme, you may create one. The prefix of "drop" should be the name of your theme.

<?php
// Add a single suggestion for nodes that have the "Promoted to front page" box checked.
function drop_preprocess_node(&$variables) {
if (
$variables['promote']) {
// looks for node--promoted.tpl.php in your theme directory
$variables['theme_hook_suggestion'] = 'node__promoted';
}
}


// Add multiple suggestions for pages based on the logged in user's roles.
function drop_preprocess_page(&$variables) {
global
$user;

if (!empty(
$user->roles)) {
foreach (
$user->roles as $role) {
$filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
$string_clean = preg_replace($filter, '-', drupal_strtolower($role));

// looks for page--[role].tpl.php in your theme directory
// ex: page--administrator.tpl.php

$variables['theme_hook_suggestions'][] = 'page__'. $string_clean;
}
}
}

?>

There are two ways to add these suggestions.

  1. The key of 'theme_hook_suggestion' accepts a single suggestion and it takes precedence. If the condition is met and the file exists, it will be used ignoring all others.
  2. The key of 'theme_hook_suggestions' (plural) can accept an array of suggestions. They are processed in FILO order (first in last out order). Adding to the array should be done with a general condition first, progressively getting more specific so it cascades based on specificity.

A few notes:

  • When adding to 'theme_hook_suggestions', add to the array. Do not reset it since the variables are passed by reference. All the suggestions set before it in core and modules would be lost.
    <?php
    // Do not do this:
    $variables['theme_hook_suggestion'] = array('hook__suggestion');

    // Instead do this:
    $variables['theme_hook_suggestions'][] = 'hook__suggestion';
    ?>
  • Prefix the suggestion with the name of the hook it is associated with, such as "node" or "page". This keeps it clear and the files grouped together. It also minimizes any chance of Drupal registering the template with a different hook.
  • Use two hyphens to separate the hook name from the rest of the suggestion. This is consistent with template naming suggestions in core.
  • Use underscores ("_") instead of hyphens ("-") when adding to the array but use hyphens for your template.
    <?php
    // do this
    $variables['theme_hook_suggestions'][] = 'pagemanager_item__'.$style;
    // instead of this
    $variables['theme_hook_suggestions'][] = 'pagemanager-item__'.$style;
    // to get to pagemanager-item--style1.tpl.php
    ?>

Drupal 6

A listing of all the suggestions for core can be found in Drupal 6 Template Suggestions.

The prefix of "drop" should be the name of your theme.

<?php
function drop_preprocess_page(&$variables) {
global
$user;

// Add a single suggestion based on the throttle module in core.
if (module_invoke('throttle', 'status') && isset($user->roles[1])) {
$variables['template_file'] = 'page-busy';
}


// Add multiple suggestions for pages based on the logged in user's roles.
if (!empty($user->roles)) {
foreach (
$user->roles as $role) {
$filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
$string_clean = preg_replace($filter, '-', drupal_strtolower($role));
$variables['template_files'][] = 'page-'. $string_clean;
}
}

}

?>

Theming a page by arbitrary content types

You could improve above code to have the theme suggestion for all content types in your site.

<?php
function drop_preprocess_page(&$variables) {
if (
$variables['node']->type != "") {
$variables['template_files'][] = "page-node-" . $variables['node']->type;
}
}

?>

Now just make your template in form page-node-your_content_type. If it's missing, the default page template will be used.

There are two ways to add these suggestions.

  1. The key of 'template_file' accepts a single suggestion and it takes precedence. If the condition is met and the file exists, it will be used ignoring all others.
  2. The key of 'template_files' (plural) can accept an array of suggestions. They are processed in FILO order (first in last out order). Adding to the array should be done with a general condition first, progressively getting more specific so it cascades based on specificity.

With the above example, Drupal will attempt to use a file named "page-busy.tpl.php" when the throttling threshold is met for anonymous users (anonymous role id typically set to 1). The others inform Drupal to look for templates based on the roles assigned to the current user, e.g., "page-authenticated-user.tpl.php". If none apply, the base template of "page.tpl.php" is used.

These are simply examples. You can set any context based on any data available to you.

A few notes:

  • When adding to 'template_files', add to the array. Do not reset it since the variables are passed by reference. All the suggestions set before it in core and modules would be lost.
    <?php
    // Do not do this:
    $variables['template_files'] = array('hook-suggestion');

    // Instead do this:
    $variables['template_files'][] = 'hook-suggestion';
    ?>
  • Prefix the suggestion with the name of the hook it is associated with. This keeps it clear and the files grouped together. It also minimizes any chance of Drupal registering the template with a different hook.
  • Use hyphens instead of underscores for consistency. The main template will never use underscores.
  • Suggestions work only when it is placed in the same directory as the base template. Templates can be placed in any sub-directory of the theme. They must be paired into the same location.
  • The theme registry does not have to be cleared for suggestions. It's only the base template that needs to be registered. Suggestions are discovered on the fly.

Comments

What I wanted to do was to have a templates based on the path. So, www.example.com/portfolio would call page-portfolio.tpl.php and page.tpl.php for the rest of the site. In addition, I wanted to specify a different template based on www.example.com/blog. Which calls the templates differently I guess because it's a node type of "blog" instead of a regular old "page"? I think?!? I'm not sure, I'm pretty new to Drupal and am just getting started.

Anyway, I learned I needed to be able to specify template based on node type in addition to path type. So, this is the script that I cobbled together from the script above and some script someone on IRC was generous to provide.

Like I said, I'm new to Drupal and PHP actually, so I'm sure there is a better way to do this. But, here it is anyways for anyone who would like to do something similar. It took me a lot of sleuthing to find all the pieces for this code! This code should go in your template.php file and your blog template should be named page-blog.tpl.php. Enjoy! =)

<?php
function phptemplate_preprocess_page(&$variables) {
global
$user;
if (
module_exists('path')) {
//allow template suggestions based on url paths.
$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;
}

$alias_array = explode('/', $alias);
$variables['template_files'] = $suggestions;
}


// Add a single suggestion.
if (module_invoke('throttle', 'status') && isset($user->roles[1])) {
$variables['template_file'] = 'page-busy';
}


// Add multiple suggestions.
if (!empty($user->roles)) {
foreach (
$user->roles as $role) {
$filter = '![^abcdefghijklmnopqrstuvwxyz0-9-_]+!s';
$string_clean = preg_replace($filter, '-', drupal_strtolower($role));
$variables['template_files'][] = 'page-'. $string_clean;
}
if (
drupal_is_front_page()) {
$variables['template_file'] = 'page-front';
}
}
}
}

?>

Thanks.. I dropped a simpler

Thanks.. I dropped a simpler function into a theme to just get page templates based on path aliases:

<?php
function phptemplate_engine_preprocess_page(&$variables) {
$alias = drupal_get_path_alias($_GET['q']);
if (
$alias != $_GET['q']) {
$template_filename = 'page';
foreach (
explode('/', $alias) as $path_part) {
$template_filename = $template_filename . '-' . $path_part;
$variables['template_files'][] = $template_filename;
}
}
}

?>

Theming a page by content type

Create a page template file for the content type you want to theme. For example, "page-node-my_content_type.tpl.php". Replace "my_content_type" with your content type obviously.

Now add the following to your template.php:

<?php
function my_theme_preprocess_page(&$variables) {
if (
$variables['node']->type == "my_content_type") {
$variables['template_files'][] = 'page-node-my_content_type';
}
}

?>

Replace "my_theme" with the name of your theme and again, "my_content_type" with the name of your content type.

Go to Site Configuration | Performance and clear your cache. Now nodes of the specified content type will get their own page template when viewed as a page.

Theming multiple content types

Just adding onto your code for theming multiple content types:

<?php
function my_theme_preprocess_page(&$variables) {
if (
$variables['node']->type == "my_content_type") {
$variables['template_files'][] = 'page-node-my_content_type';
} elseif (
$variables['node']->type == "my_content_type_2") {
$variables['template_files'][] = 'page-node-my_content_type_2';
} elseif (
$variables['node']->type == "my_content_type_3") {
$variables['template_files'][] = 'page-node-my_content_type_3';
} elseif (
$variables['node']->type == "my_content_type_4") {
$variables['template_files'][] = 'page-node-my_content_type_4';
}
}

?>

In this example I have four different content types with four different themes.

exclude node add and edit pages

if ($variables['node']->type == "my_content_type" && arg(2)!='edit' && arg(1) !='add') {
$variables['template_files'][] = 'page-node-my_content_type';
}

This could help if you don't want same layout when you add/edit the page content.

sorry... this post was

sorry... this post was duplicate.. so I removed content here

Thanks & Regards,
AnAnD | Drupal | Photographer @ MCS | Facebook | Twitter

I am unable to find

I am unable to find template.php file. I am using 'ad novus fluid' theme.

Please let me know how I can get this working

Thanks & Regards,
AnAnD | Drupal | Photographer @ MCS | Facebook | Twitter

I created one template.php

I created one template.php file and placed below code in it also cleared cache. But still did not work.

<?php
function my_theme_preprocess_page(&$variables) {
if (
$variables['node']->type == "my_content_type" && arg(2)!='edit' && arg(1) !='add') {
$variables['template_files'][] = 'page-node-my_content_type';
}
}

?>

Thanks & Regards,
AnAnD | Drupal | Photographer @ MCS | Facebook | Twitter

thanks

function phptemplate_preprocess_page(&$variables) {
if ($variables['node']->type == "content_type") {
$variables['template_files'][] = "page-node-content_type";
}
}

worked for me. I made the mistake of replacing phptemplate_preprocess_page with my_theme_preprocess_page. Now I have a different template based on content type.

Also I realise now that you can not have multiple preprocess functions so you need to wrap any functions using the same wrapper.

Many thx

Freelance Web Design and Development
---
http://www.danlobo.co.uk

Inside different preprocess functions a variable with the same name is used to set page templates and node templates:

  • Inside THEME_preprocess_page template_file(s) refers to page templates
  • Inside THEME_preprocess_node template_file(s) refers to node templates.

See Extending Drupal Templating for some good samples.

drupal 7

For drupal 7 you should use something like that:

<?php
function mythemename_preprocess_page(&$vars) {
if (
some_cond())
$vars['theme_hook_suggestions'][] = "page__sometemplate";
}

?>

if you want template page--sometemplate.tpl.php to be used.

I can't get this work. No

I can't get this work. No matter what I do, page.tpl.php is always rendered. I'm using Marinelli theme. My code:

<?php
function marinelli_preprocess_page(&$vars) {
if (
$vars['node']->type == "product") {
$vars['theme_hook_suggestions'][] = 'page--type--product';
}

//
}
?>

Any ideas what I'm doing wrong?

This works fine...now what?

This is working for me. How do I now access the node fields to theme them in 7?

I have tried many purmutations of feild_name and the following so far .
$noderefnode = node_load($field_pr_link[0][nid]);
print $noderefnode->field_pr_link[0]['value'];

Thanks,

"Everything Connects To Everything Else"

LD

This works for me in D7.

  • If you don't have a template.php file in your theme, create one.
  • If you already have a yourTheme_preprocess_page function in your template.php, copy-n-paste everything except the first line and closing bracket into your existing function (before the closing bracket is a good place).
  • If there is no yourTheme_preprocess_page function in your template.php, copy-n-paste the entire function below into your template.php file.
  • Replace 'yourTheme,' with the name of your theme.
function yourTheme_preprocess_page(&$variables, $hook) {
//Add multiple suggestions for pages based on content type
if ($variables['node']->type != "") {
$variables['theme_hook_suggestions'][] = 'page__' . $variables['node']->type . $string_clean;
}
}

Works

Works except what is $string_clean for? It wrecks everything.

So it should be this:

template.php

function yourTheme_preprocess_page(&$variables, $hook) {
//Add multiple suggestions for pages based on content type
if ($variables['node']->type != "") {
// (underscores used in page__ )
$variables['theme_hook_suggestions'][] = 'page__' . $variables['node']->type;
}
}

and the tpl.php should be named page--type.tpl.php (dashes)

Should the code be added to

Should the code be added to the current theme's template or the template of the other theme one wants to use for the content type? Where do you pick the theme once you add the code to the template?

Also does the devel_theme module need to be enabled to use this?

Templates suggestions for a custom theme hook

Hello,
I don't find where I can post my request so it seems it's the best place.
I add a new theme hook in my module :

/**
* Implements hook_theme().
*/
function dx_theme() {
return array(
'dx_detail' => array(
'pattern' => 'dx_detail__',
'variables' => array('element' => new stdClass(), 'table' => NULL),
'template' => 'dx_detail',
),
);
}

I've read that "pattern" is not necessary but with or not the template suggestions don't work for me.

I add suggestions with preprocess hook :

function dx_preprocess_dx_detail(&$variables) {
if($variables['table']) {
$variables['theme_hook_suggestions'][] = 'dx_detail__'. $variables['table']['nom'];
}
}

For example, I want that my theme function use dx_detail--contact.tpl.php, but Drupal doesn't look in .tpl.php files of my module or my theme for this, it takes always "dx_detail.tpl.php".

I've looked with theme developper module, and template suggestions are
"dx_detail__contact < sites/all/themes/sevenzoe/dx_detail.tpl.php"
Why it can't set suggestions to
"sites/all/themes/sevenzoe/dx_detail--contact.tpl.php < sites/all/themes/sevenzoe/dx_detail.tpl.php" ?
I wonder it looks only for function and not template file.

Thanks for your ideas !

Use hyphens instead of underscores

From experience, template file names with hyphens work better than underscores.

So, if you had:

<?php
/**
* Implements hook_theme().
*/

function dx_theme() {
return array(

'dx_detail' => array(
'pattern' => 'dx_detail__', // This line is actually optional.
'variables' => array('element' => new stdClass(), 'table' => NULL),
'template' => 'dx-detail',
),
);
}

?>

This should let phptemplate.engine discover the suggested theme hook.

Note on hook_theme() defined in your themes

If you declare theme hooks inside your actual theme, drupal_find_theme_templates() WILL NOT find your suggested hooks/templates. The theme registry is built in the following order (see hook_theme() for details):

  1. Modules
  2. Theme engine (base, then active)
  3. Theme (base, then active)

Typically, the $existing theme hooks passed into hook_theme() is passed through to drupal_find_theme_templates() to discover possible hook suggestions. The problem is that this happens in the theme engine, namely phptemplate.engine in its hook_theme() declaration. Theme hooks defined in your theme wouldn't have been registered at this point. To get around the problem, in your theme:

<?php
/**
* Implements hook_theme().
*/

function yourtheme_theme($existing, $type, $theme, $path) {
$hooks['yourtheme_part'] = array(
'variables' => array('name' => ''),
'template' => 'yourtheme-part',
);

$hooks += drupal_find_theme_templates($hooks, '.tpl.php', $path);
return
$hooks;
}


/**
* Preprocess variables.
*/

function yourtheme_preprocess_yourtheme_part(&$variables) {
if (
$variables['name']) {
$variables['theme_hook_suggestions'][] = 'yourtheme_part__' . $variables['name'];
}
}

?>

The specifics should be modified as needed, but this will make available templates provided in your theme. Of course, this code doesn't take subthemes into account. Looking from the code in drupal_find_theme_templates() and _theme_process_registry() I suppose subthemes can simply declare their own hook_theme() and do the same thing with yourtheme's yourtheme_part declaration for drupal_find_theme_templates().

This is as of Drupal 7.0. Similar mechanisms seem to be in play also in Drupal 6.

Hi Zhangtaihao, rkcreation and Everyone else out there.

I am using drupal 7 where a custom module in it's theme hook contain's the below mentioned code:

/*
* Implementation of hook_theme.
*/
function garc_theme($existing, $type, $theme, $path) {
return array(
'demo' => array(
'template' => 'templates/demo',
'variables' => array('rr' => NULL),
),
);
}

Then, created a subthem of bartik and named it as "adashboard" and placed the below code it's templated.php:

/**
* Implements hook_preprocess_maintenance_page().
*/
function adashboard_preprocess_page(&$variables) {
$variables['theme_hook_suggestions'][] = 'demo';
}

/**
* Overriding the custom module's theme.
*/
function adashboard_theme($existing, $type, $theme, $path) {
$hooks['demo'] = array(
'variables' => array('rr' => 'NULL'),
'template' => 'templates/demo',
);
$hooks += drupal_find_theme_templates($hooks, '.tpl.php', $path);
return $hooks;
}

All I need is this "demo" template file which is generated here, should inherit the page.tpl.php. So I copied the page.tpl.php of the theme and renamed it as the demo.tpl.php in the templates folder of the theme, but when I am executing this it is showing warnings as all the variables which are defined in the demo.tpl.php (which are copied from the page.tpl.php) as undefined.

I have also tried with naming the template as "page-demo.tpl.php" instead of "demo.tpl.php", but still same result.

Please let me know if I am missing anything or doing anything way differently.

I have researched for this, but most of the times I got how to theme a custom template defined by a new content type, the only place I got some hope is here http://drupal.org/node/223440#comment-4873350 . So I am posting this in the same thread. I believe I am not hijacking this thread, Sorry if this is so and please point me to the right one.

TIA,
Pradeep.

subtheme name

plz use your subtheme name. which is in sites/all/themes/yoursubthemename. hope it will help you.

region.tpl.php and region-[region].tpl.php in D6

Borrowed from Zen. Append the following to template.php:

/**
*
* Implementation of hook_theme
*
* The following is borrowed heavily from the Zen theme.
*
*/
function yourtheme_theme($existing, $type, $theme, $path) {
$templates = array(
'region' => array(
'arguments' => array('elements' => NULL),
'pattern' => 'region_',
'path' => drupal_get_path('theme', 'yourtheme') . '/regions',
'template' => 'region',
// drupal_find_theme_templates() requires this, so manually add it.
'include files' => array(),
),
);
// We have to manually find template suggestions since phptemplate_theme()
// is in charge of that, but runs before yourtheme_theme().
$templates += drupal_find_theme_templates($templates, '.tpl.php', $path);

return $templates;
}

/**
* Return a set of blocks available for the current user.
*
* @param $region
* Which set of blocks to retrieve.
* @param $show_blocks
* A boolean to determine whether to render sidebar regions or not. Should be
* the same value as passed to theme_page.
* @return
* A string containing the themed blocks for this region.
*/
function yourtheme_blocks($region, $show_blocks = NULL) {
// Since Drupal 6 doesn't pass $show_blocks to theme_blocks, we manually call
// theme('blocks', NULL, $show_blocks) so that this function can remember the
// value on later calls.
static $render_sidebars = TRUE;
if (!is_null($show_blocks)) {
$render_sidebars = $show_blocks;
}

// If yourtheme_blocks was called with a NULL region, its likely we were just
// setting the $render_sidebars static variable.
if ($region) {
$output = '';

// If $renders_sidebars is FALSE, don't render any region whose name begins
// with "sidebar_".
if ($render_sidebars || (strpos($region, 'sidebar_') !== 0)) {
// Allow context module to set blocks.
if (function_exists('context_blocks')) {
$output = context_blocks($region);
}
else {
foreach (block_list($region) as $key => $block) {
// $key == module_delta
$output .= theme('block', $block);
}
}
}

// Add any content assigned to this region through drupal_set_content() calls.
$output .= drupal_get_content($region);

$elements['#children'] = $output;
$elements['#region'] = $region;

// Set the theme hook suggestions.
$hook = array('region_' . $region);
if (strpos($region, 'sidebar_') === 0) {
$hook[] = 'region_sidebar';
}
$hook[] = 'region';
return $output ? theme($hook, $elements) : '';
}
}

/**
* Preprocess variables for region.tpl.php
*
* Prepare the values passed to the theme_region function to be passed into a
* pluggable template engine.
*
* @see region.tpl.php
*/
function yourtheme_preprocess_region(&$vars, $hook) {
// Create the $content variable that templates expect.
$vars['content'] = $vars['elements']['#children'];
$vars['region'] = $vars['elements']['#region'];

// Setup the default classes.
$vars['classes_array'] = array('region', 'region-' . str_replace('_', '-', $vars['region']));

// Sidebar regions get a couple extra classes.
if (strpos($vars['region'], 'sidebar_') === 0) {
$vars['classes_array'][] = 'column';
$vars['classes_array'][] = 'sidebar';
}
if (array_key_exists('classes_array', $vars) && !array_key_exists('classes', $vars)) {
$vars['classes'] = implode(' ', $vars['classes_array']);
}
}

And now for your region.tpl.php file:

<div class="<?php print $classes; ?>">
<?php print $content; ?>
</div><!-- /.region -->

is not working with drupal 7

Hi I am using the same procedure in template.php and creating new node--contetype.tpl.php . but i am not getting the content to be in new template . please help me ASAP .thanks in advance

Use question.

How do you use this after it is implemented? Do you need to use the theme function like this?

<?php print theme('region_regionname'); ?>

or can you simply do this?

<?php print $regionname; ?>

Thanks!

I will be using this in the future, thanks for the gem!

I've been printing it as

<?php
print $regionname;
?>
and I haven't been having any issues as of late. I will continue to comment on this if anything comes up.

We are using some complex region/block/context (with a little touch of ThemeKey) layouts too!

Apigee | Web Developer | Designer.

How do I put this into it's own module?

I'd like to be able to encapsulate this code as a module. When I turn the module on, region.tpl.php and region-[region].tpl.php files should work. I can't get it to work though. Any suggestions?

in drupal 7 it is not working

Hi I am using the same procedure in template.php and creating new node--contetype.tpl.php . but i am not getting the content to be in new template . please help me ASAP .thanks in advance

I believe...

I believe Drupal 7 allows you to utilize region.tpl.php out of box... I know I've used those template files before in D7

Apigee | Web Developer | Designer.

Regarding the section on "Theming a page by arbitrary content types" the function drop_preprocess_page did not work for me. However, phptemplate_preprocess_page did work. I'm using Drupal 6.

The instructions say to

The instructions say to replace the prefix "drop" with your theme name

One of the most frustrating things of D7

Why is it so extremely hard to have a template listen to a path?
It is such a basic function and yet so hard.

In the good old D6 days I would simply install the sections module and this works perfect.
However that module has been discontinued.

www.drupalsite/mypage
Has to listen to the page--mypage.tpl.php instead of page.tpl.php.

How can i achieve this?

prolly like this:function

prolly like this:

function mytheme_preprocess_page(&$vars) {
$path = drupal_get_path_alias();
if ($path == 'mypage') {
$vars['theme_hook_suggestions'][] = 'page__mypage';
}
}

 

普通分类: