Hi,
I'm fairly new to Drupal. I've downloaded and installed Drupal 5.1, and we've got it working with multiple sites and modules very quickly. A lot of things *just*work*, which is great.
One aspect I've found quite confusing is the principles behind templating (I can manage the PHP nitty-gritty reasonably well). There seems to be a number of different ways of doing templates - PHPTemplate, XTemplate, a .theme file - which I appreciate may be for historical reasons. I've also seen conflicting advice on the Drupal site for how to override default templates and functions.
Our Drupal themes would end up quite large owing to specific client requirements, so I really want to start as I mean to go on! So what's the best practice for templating?
A few examples of stuff I want to do might help illustrate the problems I've been having:
1. If I wanted to hook into the code that creates e.g. $sidebar_left, how would I do that? It seems to be created by theme('blocks' , 'left') in the phptemplate engine. Should I just discard $sidebar_left, or is there some hierarchy of function names that theme() calls? Can I put any such functions into some file in my theme directory and they'll always get recognized?
Should I call such functions e.g. theme_block_left, or phptemplate_block_left, or THEMENAME_block_left ? Or should I instead use .tpl.php files exclusively e.g. block-left.tpl.php?
2. For different node types, I just can't seem to get the system described at http://drupal.org/node/104316 working properly. It works fine for the node-content sub-templates e.g. node-video.tpl.php will get called over node.tpl.php, but e.g. page-video-edit.tpl.php just doesn't get called.
Is there something I'm missing? Would this hack here http://drupal.org/node/117491 be worth looking into?
3. A bit of a random one, but say I wanted to change the content of an admin page. We'd be using Drupal for very heterogeneous sites (so e.g. events nodes, news nodes, courses, content, press releases etc. etc.) so the "Create content" page would start to look very cluttered. Any way of overriding that at the theme level? Also, we could have many user roles, so we would want to change the look of the permissions pages too.
Many thanks in advance,
J-P
On Thu, 05 Apr 2007 17:06:01 +0100, J-P Stacey jp.stacey@torchbox.com wrote:
Hi,
I'm fairly new to Drupal. I've downloaded and installed Drupal 5.1, and we've got it working with multiple sites and modules very quickly. A lot of things *just*work*, which is great.
Yay!
One aspect I've found quite confusing is the principles behind templating (I can manage the PHP nitty-gritty reasonably well). There seems to be a number of different ways of doing templates - PHPTemplate, XTemplate, a .theme file
- which I appreciate may be for historical reasons. I've also seen
conflicting advice on the Drupal site for how to override default templates and functions.
XTemplate is dead, long live PHPTemplate. :-) .theme files are there for legacy reasons. I don't know of anyone that actually uses them in production sites. Really, just use PHPTemplate.
Our Drupal themes would end up quite large owing to specific client requirements, so I really want to start as I mean to go on! So what's the best practice for templating?
A few examples of stuff I want to do might help illustrate the problems I've been having:
- If I wanted to hook into the code that creates e.g. $sidebar_left, how
would I do that? It seems to be created by theme('blocks' , 'left') in the phptemplate engine. Should I just discard $sidebar_left, or is there some hierarchy of function names that theme() calls? Can I put any such functions into some file in my theme directory and they'll always get recognized?
Should I call such functions e.g. theme_block_left, or phptemplate_block_left, or THEMENAME_block_left ? Or should I instead use .tpl.php files exclusively e.g. block-left.tpl.php?
PHPtemplate in a nutshell:
In Drupal, there are theme_foo() functions. In your theme's template.php file, you can override them with a function named phptemplate_foo(). That, in turn, will get overridden by themename_foo(). Calling theme('foo') will call themename_foo(), phptemplate_foo(), or theme_foo(), whichever it finds first in that order. So if you wanted to override the "blocks" theme, you'd use phptemplate_blocks($region). Generally the easiest way is to just find theme_blocks(), copy and paste it to your template.php file, and rename it.
As a general rule, you should use phptemplate_foo() instead of themename_foo() in most cases. The exception is when the PHPTemplate engine itself already has a phptemplate_foo() function in the phptemplate.engine file.
OPTIONALLY, in the phptemplate_foo() function you can "stub out" the function to a template file. Any override function may do that, but in many cases you don't have to. The PHPTemplate engine itself already has override functions that "stub out" common theme functions (page, node, etc.), so you don't need to most of the time. Have a look in phptemplate.engine to see how it works for the standard overrides, and follow that pattern for your own when you need them.
- For different node types, I just can't seem to get the system described
at http://drupal.org/node/104316 working properly. It works fine for the node-content sub-templates e.g. node-video.tpl.php will get called over node.tpl.php, but e.g. page-video-edit.tpl.php just doesn't get called.
Check phptemplate.engine in the phptemplate_page() function to see how it builds the "suggestions" list. I don't think you can do page-video-edit.tpl.php, but I'm not certain. This may be a case where you do want to override phptemplate_page() with themename_page() to change the suggestion list to your liking. :-)
Is there something I'm missing? Would this hack here http://drupal.org/node/117491 be worth looking into?
- A bit of a random one, but say I wanted to change the content of an
admin page. We'd be using Drupal for very heterogeneous sites (so e.g. events nodes, news nodes, courses, content, press releases etc. etc.) so the "Create content" page would start to look very cluttered. Any way of overriding that at the theme level? Also, we could have many user roles, so we would want to change the look of the permissions pages too.
You can add your own menu callbacks in a custom module that point to the node add form (see node.module's hook_menu()) for the types you want, then hide the default create content menu. Then you can style or link to your own pages however you want and build your very own admin area. :-)
Cheers!
--Larry Garfield
Hi,
Larry Garfield wrote:
things *just*work*, which is great.
Yay!
Yay indeed! Thanks very much for your reply, and sorry I haven't got back to you sooner. There's no accounting for elderly relatives' internet access.... What you've said is all very comprehensive, and I'll have a hack away at the suggestions.
Many thanks, J-P
I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the module? I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to figure this out.
################################################# module code - mymod.php #################################################
function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; }
function mymod_foo() { $data = array('foo' => 'bar'); return $data; }
################################################# template.php code #################################################
function phptemplate_mymod_foo() { return _phptemplate_callback('mymod_foo'); }
################################################# mymod_foo.tpl.php #################################################
<h1>I want to output value of $data['foo'] here</h1>
Easiest way is the the following. In this case, the html output represented by $foo is presented in the content area of page.tpl. Note you don't need custom theme functions and custom tpl files to do this.
Now you could invoke the theme engine as well, but I wanted to make sure you understood this easier way first.
Dave
________________________________
From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Cyberswat Sent: Tuesday, April 10, 2007 11:47 AM To: support@drupal.org Subject: Re: [support] Templating in Drupal 5.1 - the cleanest way to do it?
I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the module? I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to figure this out.
################################################# module code - mymod.php #################################################
function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; }
function mymod_foo() { $data = array('foo' => 'bar'); $output = '<h1>Here is the value of '.$data['foo'].' here. </h1>'; return $output ; }
Thanks for the response. I understand the approach you outline and have been using it exclusively so far. I'm starting to work with structures that are more complex than my original example and would ultimately like to task a designer to create/modify the tpl files without editing the module at all. How do I go about invoking the theme engine to accomplish this in a similar to my original example?
On 4/10/07, Metzler, David metzlerd@evergreen.edu wrote:
Easiest way is the the following. In this case, the html output represented by $foo is presented in the content area of page.tpl. Note you don't need custom theme functions and custom tpl files to do this.
Now you could invoke the theme engine as well, but I wanted to make sure you understood this easier way first.
Dave
*From:* support-bounces@drupal.org [mailto:support-bounces@drupal.org] *On Behalf Of *Cyberswat *Sent:* Tuesday, April 10, 2007 11:47 AM *To:* support@drupal.org *Subject:* Re: [support] Templating in Drupal 5.1 - the cleanest way to do it?
I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the module? I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to figure this out.
################################################# module code - mymod.php #################################################
function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; }
function mymod_foo() { $data = array('foo' => 'bar'); $output = '<h1>Here is the value of '.$data['foo'].' here. </h1>'; return $output ; }
-- [ Drupal support list | http://lists.drupal.org/ ]
See Larry Garfields response for the full answer. He provided an excellent example.
in Your module:
mymod_foo calls theme() to make sure that the output is themeable. (by phptemplate or other theme engines)
theme_foo_or_something() provides the default view if not overriden by the theme.
in the template.php file for the php template theme:
phptemplate_foo_or_somthing() matches up the foo_or_something.tpl file with the intercepted theme function.
in the foo_or_something.tpl The overriden template is specified by the designer.
Larry's post is as follows: <snip>
#################################################
module code - mymod.php
#################################################
function mymod_foo() {
$data = array('foo' => 'bar');
return theme('foo_or_something', $data); }
function theme_foo_or_someting($data) {
return "something you do with $data that generates a string"; }
#################################################
template.php code
#################################################
function phptemplate_foo_or_something() {
return _phptemplate_callback('foo_or_something', $data); }
#################################################
foo_or_something.tpl.php
#################################################
<h1>I want to output value of $foo here</h1>
________________________________
From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Cyberswat Sent: Tuesday, April 10, 2007 1:08 PM To: support@drupal.org Subject: Re: [support] Templating in Drupal 5.1 - the cleanest way to do it?
Thanks for the response. I understand the approach you outline and have been using it exclusively so far. I'm starting to work with structures that are more complex than my original example and would ultimately like to task a designer to create/modify the tpl files without editing the module at all. How do I go about invoking the theme engine to accomplish this in a similar to my original example?
On 4/10/07, Metzler, David metzlerd@evergreen.edu wrote:
Easiest way is the the following. In this case, the html output represented by $foo is presented in the content area of page.tpl. Note you don't need custom theme functions and custom tpl files to do this. Now you could invoke the theme engine as well, but I wanted to make sure you understood this easier way first. Dave
________________________________
From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Cyberswat Sent: Tuesday, April 10, 2007 11:47 AM To: support@drupal.org Subject: Re: [support] Templating in Drupal 5.1 - the cleanest way to do it? I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the module? I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to figure this out. ################################################# module code - mymod.php ################################################# function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; } function mymod_foo() { $data = array('foo' => 'bar'); $output = '<h1>Here is the value of '.$data['foo'].' here. </h1>'; return $output ; }
-- [ Drupal support list | http://lists.drupal.org/ ]
################################################# module code - mymod.php #################################################
function mymod_foo() { $data = array('foo' => 'bar'); return theme('foo_or_something', $data); }
function theme_foo_or_someting($data) { return "something you do with $data that generates a string"; }
################################################# template.php code #################################################
function phptemplate_foo_or_something() { return _phptemplate_callback('foo_or_something', $data); }
################################################# foo_or_something.tpl.php #################################################
<h1>I want to output value of $foo here</h1>
(In this case $foo will have a value of 'bar').
Cheers.
--Larry Garfield
On Tue, 10 Apr 2007 12:47:28 -0600, Cyberswat cyberswat@gmail.com wrote:
I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the module? I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to figure this out.
################################################# module code - mymod.php #################################################
function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; }
function mymod_foo() { $data = array('foo' => 'bar'); return $data; }
################################################# template.php code #################################################
function phptemplate_mymod_foo() { return _phptemplate_callback('mymod_foo'); }
################################################# mymod_foo.tpl.php #################################################
<h1>I want to output value of $data['foo'] here</h1>
That's what I was looking for ... Thanks!
On 4/10/07, Larry Garfield larry@garfieldtech.com wrote:
################################################# module code - mymod.php #################################################
function mymod_foo() { $data = array('foo' => 'bar'); return theme('foo_or_something', $data); }
function theme_foo_or_someting($data) { return "something you do with $data that generates a string"; }
################################################# template.php code #################################################
function phptemplate_foo_or_something() { return _phptemplate_callback('foo_or_something', $data); }
################################################# foo_or_something.tpl.php #################################################
<h1>I want to output value of $foo here</h1>
(In this case $foo will have a value of 'bar').
Cheers.
--Larry Garfield
On Tue, 10 Apr 2007 12:47:28 -0600, Cyberswat cyberswat@gmail.com wrote:
I have another question regarding this subject. If I create a custom module how do I use the templating engine to work with the output of the
module?
I know this code is bad, but it summarizes what I would like to do. Any help is appreciated as I'm starting to feel dense from not being able to
figure
this out.
################################################# module code - mymod.php #################################################
function mymod_menu($may_cache) { $items = array(); $items[] = array('path' => 'mymod_view', 'title' => t('mymod_view'), 'callback' => 'mymod_foo', 'type' => MENU_LOCAL_TASK, 'access' => user_access('view mymod'), 'weight' => 0, ); return $items; }
function mymod_foo() { $data = array('foo' => 'bar'); return $data; }
################################################# template.php code #################################################
function phptemplate_mymod_foo() { return _phptemplate_callback('mymod_foo'); }
################################################# mymod_foo.tpl.php #################################################
<h1>I want to output value of $data['foo'] here</h1>
-- [ Drupal support list | http://lists.drupal.org/ ]
The threads probably getting old ... but just in case anyone else is following this, Larry's example is almost perfect. Simply modify
function phptemplate_foo_or_something() {
to
function phptemplate_foo_or_something($data) {
Then everything will work. Thanks for the help David and Larry.
On 4/10/07, Larry Garfield larry@garfieldtech.com wrote:
################################################# module code - mymod.php #################################################
function mymod_foo() { $data = array('foo' => 'bar'); return theme('foo_or_something', $data); }
function theme_foo_or_someting($data) { return "something you do with $data that generates a string"; }
################################################# template.php code #################################################
function phptemplate_foo_or_something() { return _phptemplate_callback('foo_or_something', $data); }
################################################# foo_or_something.tpl.php #################################################
<h1>I want to output value of $foo here</h1>
(In this case $foo will have a value of 'bar').
Cheers.
--Larry Garfield
Drat. I knew I'd forget something. :-)
The important part is that phptemplate_themekey() takes the same parameters as the theme_ function it's overriding, but _phptemplate_callback() takes a named array of values that turn into variables in the template file itself.
On Tuesday 10 April 2007 4:04 pm, Cyberswat wrote:
The threads probably getting old ... but just in case anyone else is following this, Larry's example is almost perfect. Simply modify
function phptemplate_foo_or_something() {
to
function phptemplate_foo_or_something($data) {
Then everything will work. Thanks for the help David and Larry.
On 4/10/07, Larry Garfield larry@garfieldtech.com wrote:
################################################# module code - mymod.php #################################################
function mymod_foo() { $data = array('foo' => 'bar'); return theme('foo_or_something', $data); }
function theme_foo_or_someting($data) { return "something you do with $data that generates a string"; }
################################################# template.php code #################################################
function phptemplate_foo_or_something() { return _phptemplate_callback('foo_or_something', $data); }
################################################# foo_or_something.tpl.php #################################################
<h1>I want to output value of $foo here</h1>
(In this case $foo will have a value of 'bar').
Cheers.
--Larry Garfield
Hi,
I've been fiddling with what you sent, trying to get a new menu to appear on the frontend, but I'm getting nowhere. My first problem is that function overrides just don't seem to be happening:
As a general rule, you should use phptemplate_foo() instead of themename_foo() in most cases. The exception is when the PHPTemplate engine itself
already has
a phptemplate_foo() function in the phptemplate.engine file.
Re: the documentation at http://drupal.org/node/29139, I thought I'd get an immediate effect by writing an override for phptemplate_regions() .
My theme directory is "garlandquux" (no guesses for what that's based on!) so presumably the function should be called garlandquux_regions() ? So if I put in template.php:
<?php function garlandquux_regions() { return array(); } ?>
then shouldn't my garland-based page lose all its content? Nothing seems to happen when I do the above.
My second problem is that I probably won't know where to go from there: I want a different set of primary links to appear in admin and on the frontend. I have a separate menu set up, but I can't see how to bring that into garlandquux's templates.
Cheers, J-P
Hi again,
Sorry to respond to my own post: this function does seem to work in populate the dropdowns at /admin/build/block :
<?php function garlandquux_regions() { return array("fooregion" => t("foo region"); // edit: added entry } ?>
i.e. any elements returned from the function appear on the dropdown. And that seems to work in page.tpl.php, with
<?php print $fooregion ?>
printing all blocks assigned to that region.
(I notice the HTML class of the fooregion containing div is "block-region" - so is a region treated during templating as a special sort of block, a superblock?)
I'm definitely getting there, but the behaviour still seems a bit odd: on the one hand there seems to be lots of variables e.g. $primary_links, $tabs, $title, $help etc. that are handed to page.tpl.php despite not being in the region list. On the other hand, $content always seems to appear on the page even if garlandquux_regions() returns an empty array. This seems a bit arbitrary - am I missing something?
Cheers, J-P
Yes. :-) The regions hook defines *block regions only*. $content is not a block region, and neither are $primary_links nor $secondary_links nor $help, etc. There's a lot in a page that is not block regions.
If you don't want one of those to show, just don't print them.
--Larry Garfield
On Wed, 11 Apr 2007 16:48:02 +0100, J-P Stacey jp.stacey@torchbox.com wrote:
Hi again,
Sorry to respond to my own post: this function does seem to work in populate the dropdowns at /admin/build/block :
<?php function garlandquux_regions() { return array("fooregion" => t("foo region"); // edit: added entry } ?>
i.e. any elements returned from the function appear on the dropdown. And that seems to work in page.tpl.php, with
<?php print $fooregion ?>
printing all blocks assigned to that region.
(I notice the HTML class of the fooregion containing div is "block-region"
so is a region treated during templating as a special sort of block, a superblock?)
I'm definitely getting there, but the behaviour still seems a bit odd: on the one hand there seems to be lots of variables e.g. $primary_links, $tabs, $title, $help etc. that are handed to page.tpl.php despite not being in the region list. On the other hand, $content always seems to appear on the page even if garlandquux_regions() returns an empty array. This seems a bit arbitrary - am I missing something?
Cheers, J-P -- [ Drupal support list | http://lists.drupal.org/ ]
Remember also that you can control on what pages a block appears in the block configuration. So then the empty block. When I wanted regions to display on only specific pages, this is how a did it. If there are no blocks in a region fooregion, then $fooregion will be empty.
I did a custom mod to my php template once that took advantage of this:
In page.tpl.php
<?php if ($fooregion){?> <....The html content I want to appear when I want to display this region ....> <?php } else {?> <.... The html content I wanted to appear when I didn't have any region content to display...> <?php } ?>
Then on the block configuration page for the new menu block, I added php conditions to output this block only when on specific pages.
Does that make sense?
Dave
-----Original Message----- From: support-bounces@drupal.org [mailto:support-bounces@drupal.org] On Behalf Of Larry Garfield Sent: Wednesday, April 11, 2007 9:19 AM To: support@drupal.org Subject: Re: [support] Templating in Drupal 5.1 - the cleanest way to do it?
Yes. :-) The regions hook defines *block regions only*. $content is not a block region, and neither are $primary_links nor $secondary_links nor $help, etc. There's a lot in a page that is not block regions.
If you don't want one of those to show, just don't print them.
--Larry Garfield
On Wed, 11 Apr 2007 16:48:02 +0100, J-P Stacey jp.stacey@torchbox.com wrote:
Hi again,
Sorry to respond to my own post: this function does seem to work in populate the dropdowns at /admin/build/block :
<?php function garlandquux_regions() { return array("fooregion" => t("foo region"); // edit: added
entry
} ?>
i.e. any elements returned from the function appear on the dropdown. And that seems to work in page.tpl.php, with
<?php print $fooregion ?>
printing all blocks assigned to that region.
(I notice the HTML class of the fooregion containing div is
"block-region"
so is a region treated during templating as a special sort of block, a superblock?)
I'm definitely getting there, but the behaviour still seems a bit odd:
on the one hand there seems to be lots of variables e.g. $primary_links, $tabs, $title, $help etc. that are handed to page.tpl.php despite not being in the region list. On the other hand, $content always seems to appear on the page even if garlandquux_regions() returns an empty array. This seems a bit arbitrary - am I missing something?
Cheers, J-P -- [ Drupal support list | http://lists.drupal.org/ ]
-- [ Drupal support list | http://lists.drupal.org/ ]
Defining no regions like that should make all your regions disappear; not the whole page. At least I think so, as I've never tried. :-) Remember that the main body of the site does not appear in a block region.
Primary and secondary links are site-wide. If you want a given menu to appear only on one part of the site, I'd suggest not using primary/secondary links at all but instead using a menu block. You can enable/disable that block separately for each theme and even based on the path within the site. You can also put a menu block in a header block region and CSS it to be horizontal (I think <g>).
Cheers.
--Larry Garfield
On Wed, 11 Apr 2007 16:21:08 +0100, J-P Stacey jp.stacey@torchbox.com wrote:
Hi,
I've been fiddling with what you sent, trying to get a new menu to appear on the frontend, but I'm getting nowhere. My first problem is that function overrides just don't seem to be happening:
As a general rule, you should use phptemplate_foo() instead of
themename_foo()
in most cases. The exception is when the PHPTemplate engine itself
already has
a phptemplate_foo() function in the phptemplate.engine file.
Re: the documentation at http://drupal.org/node/29139, I thought I'd get an immediate effect by writing an override for phptemplate_regions() .
My theme directory is "garlandquux" (no guesses for what that's based on!) so presumably the function should be called garlandquux_regions() ? So if I put in template.php:
<?php function garlandquux_regions() { return array(); } ?>
then shouldn't my garland-based page lose all its content? Nothing seems to happen when I do the above.
My second problem is that I probably won't know where to go from there: I want a different set of primary links to appear in admin and on the frontend. I have a separate menu set up, but I can't see how to bring that into garlandquux's templates.
Cheers, J-P
-- [ Drupal support list | http://lists.drupal.org/ ]