How does Drupal 7 render out a page? What's its equivalent to an MVC's view system.
When it comes to the rendering out the final HTML page for a request, most PHP frameworks (MVC based) I've worked with take an approach where a top-level layout/page PHP file sets out the basic document structure, and then renders our various sub-views via includes or view rendering methods.
//Simplified version
Page.phtml
Head.phtml
Body.phtml
Banner.phtml
Topnav.phtml
Left.phtml
Content.phtml
Footer.phtml
I'm a little confused as to Drupal's take on this. I'm reading through Pro Drupal Development, and it starts off in similar territory with a page.tpl.php. However, it glosses over how the theme engine (is that the right term?) gets the various parts of PHP into this page (not a criticism, the book's taking an approach that different from the path I'm on).
Also, the Drupal 7 themes don't seem to have the page.tpl.php file, so its not clear (to me) where the page skeleton comes from. Also, from what I've read it seems like "Blocks" are involved, but it's not clear to me if "Blocks" makeup the entire page, or if blocks are something used selectively by themes.
So, working from high level concepts (or get as detailed as you'd like), how does Drupal 7 render out a page?
I realize you can, and probably should, start with Drupal without understand how everything ties together. I'm specifically trying to learn how the various Drupal systems come together. Apologies to people tired of reading this disclaimer!
I think there are two questions here. First, how does a single theme/template get rendered/used/displayed and second, how does the whole site come together. I think the second question has already been answered above, so I'm going to try to explain the first a bit more.
First, a module (that's why system.module exists, for all these stuff that only a module can do like implementing hook_menu()) needs to define that a specific theme function/template exists, by declaring it in hook_theme()
Speaking of that, there are two different things which can be used. A theme function, which is a function prefixed with theme_. Often used for smaller elements of a page wich have more complex logic/PHP like theme_table(). And a template, which is a file with the tpl.php like page.tpl.php
To use a theme function/template, you can either call theme() like this:
$output = theme('table', array('rows' => $rows, 'header' => $header));
Or you can use the new, so called renderable array thing. That is basically an array of data + information which theme to use:
$output = array(
'#theme' => 'table',
'#rows' => $rows,
'#header' => $header,
);
The second is preferred because it means that it will be themed as late as possible and other modules can change it in hooks. The result will be exactly the same, drupal_render() will then call theme() itself during the final rendering.
When theme() is called, it looks up the function/file to use, looks if it has been overriden the used theme, if there are so called template suggestions and then uses them.
To override a theme function in a theme, copy it to your template.php file and replace "theme_" with "yourthemename_", if it is a tpl.php file, copy it to your directory.
Now, what the final rendering process is doing is basically building up a large $page array, that is a renderable array (Some documentation of that is in hook_page_alter() and then call drupal_render() on it.
The global structure of the page/template hierarchy (which is not hardcoded, but given through whatever is in $page) is something like this:
html.php.tpl
head.php.tpl
page.php.tpl
multiple regions
multiple blocks
Almost everything is a block in Drupal 7, including the actual content, which is typically a node. A theme defines which regions it has and then you can assign blocks to it in the UI.
When trying to understand how the templates fit together, the best tool I've found is the Theme Developer module. It works a little like Firebug and allows you click on areas of a page to see the theme functions or template files that are used for various parts of the page, along with the "suggestions" that can be used for overriding them.
Templates can fit together in a variety of ways. Drupal does make some assumptions about how they'll be nested, which are reflected in the default variables that are available in the templates files. However, both the template suggestions and the available variables within them can be modified.
As I understand it, page.tpl.php has been replaced by html.tpl.php in Drupal 7.
The best description I've heard for "Blocks" is that they're what you use to display content that will be re-used in various areas site. The most common use is for sidebars, such as "Recently updated pages" lists or "Who is online now" lists.
Try take a look a presentation on How pages are built on Drupal 7 from drupalcon at http://sf2010.drupal.org/conference/sessions/page-render-drill-down-drupal-7 specially after 5 minutes from start (05:10). Sorry can't specify much detail here cause i still watch it my self. And try to understand it as well. ;)
[Update]
After watch the presentation here is my quick conclusion on how drupal 7 render out a page:
Instead of common approach that you mention from your question
where a top-level layout/page PHP file
sets out the basic document structure,
and then renders our various sub-views
via includes or view rendering methods
Drupal render a page through a rendering flow approach like this
bootstrap
menu_execute_active_handler
page_callback
delivery_callback
hook_page_alter()
drupal_render($page)
However, it glosses over how the theme
engine (is that the right term?) gets
the various parts of PHP into this
page (not a criticism, the book's
taking an approach that different from
the path I'm on).
that various parts is served starting from rendering flow number 3 (page_callback) through flow number 6 (drupal_render($page)) where its start to return an array of drupal render-able array and then latter in your theme you can use the $page variable (served from drupal_render($page)) to render i.e drupal content.
Related
I am currently experimenting with Joomla (3.7) templating system for my company. I am not new in php and inclusion, but a beginner with Joomla.
I have been searching through the web and i haven't found any clear structure schema for the file inclusion in Joomla, something like what we can find here for wordpress for example: https://codex.wordpress.org/File:Template_Hierarchy_2015.png
For example, i stumbled upon this: while experimenting with template creation, i wanted to store a value that could be used in a layout, testing setUserState function. The layout i tested was the one used to render custom fields (which are new in 3.7). The result is that it seems that fields/render.php is actually executed before template's index.php (the value is only available after page reload when set in index.php, whereas it is immediate when set in render.php).
Did someone saw a clear schema of this inclusion structure? It is not only for the said example, but mostly for a better understanding of the framework.. sorry if already asken or if too vague for the site.
edit - note about my example: collecting info bits by bits, it seems that the template file index.php is executed first and buffered so that it can be parsed for jdoc statements. Intuitively, because an article content is in this case imported by a jdoc (<jdoc:include type="component" />, the main content in the article page), the custom fields render.php should be called after index.php. Could it be the buffering part that prevents the user state to be set in time?
As a small part of a university project I'm working on (custom MVC based project management system), I need to develop a template engine. I don't wish to use an off the self system such as Smarty because I've written every other part of the project myself and don't want to go back on that now.
Anyway, I've managed to code something simple so far, I have a class, create an instance of it, add some data to the instance, then pass in a template file. The file has a series of tags like {this} when then get replaced with the data. Simple.
The issue I'm having is when it comes to looping things - i.e. a table of users or a list of categories. At the moment I have a template file for the page (users.html) which contains the opening and closing tags, with a template tag between them called {users}. I then have another template file (users-detail.html) which displays a table row with the user info in. I'm creating a new instance of the users-detail.html template, adding the data, parsing it, then placing the output (string of HTML) into an array. I then loop this array, attach all the strings together, then assign this to the {users} tag in the users.html template file.
As you can probably tell from that explanation it is a bit of a bodge, and there are probably better methods out there for doing what I'm trying to achieve. Ideally I want to avoid using PHP in the template files if possible, and I often need to have multiple loops within one template file.
If anyone has any tips / advice on how I can achieve this, or any tutorials I could follow to get some inspiration that would be much appreciated.
Thanks in advance.
I've seen that approach before (including another template for the insides of loops). I used to work on an old version of vbulletin which does (or did) this. It makes things annoyingly complicated because you can't just add a loop to a template - without setting up a whole new template for each layer of looping.
I'd advise you instead to go along the route of Smarty.
Classically, this statement:
I don't wish to use an off the self system such as Smarty because I've written every other part of the project myself and don't want to go back on that now.
... indicates you really should just be using Smarty. In the real world that would be a poor justification for re-implementing something yourself. But I am like you, and I understand that you want to implement something yourself (because you want to learn, you find it fun, you are a perfectionist, etc). As long as you do it on your own time and it's a personal project, go for it.
It would be worth studying Smarty to see how it works (not just the syntax but how it compiles templates, stores the compiled version etc). Are you comfortable writing a tokeniser/parser in PHP which can compile your template language and output PHP? If you are advanced enough to do it, do it. At the very simplest, you read in a tag like {foreach from=$something} and somehow translate it to <?php foreach ($something as $thing) { ?>. You check token types, etc to make sure the template tag is valid, and so on.
I am trying to theme node page based on content type. Here I tried to follow the instructions as in http://drupal.org/node/249726.
What I did , copied node.tpl.php file to my theme directory. Renamed it as page-node-mycontenttype.tpl.php and wrote preprocess function in my template file as shown in above link.
Apparently found that It displays only the Node contents but not the common layout elements(HTML) (logo,header, footer and sidebars etc. which is defined in page.tpl.php).
So is it necessary for me to define same common layout elements(HTML) once again (those defines in page.tpl.php) in page-node-mycontenttype.tpl.php?
If so then I have to manage 2 template files. Any HTML changes need to be done twice in both template files.
Is there any better way of having common layout template file referred by both page and node content type only the middle content area is coming from two different files (page or node content type)?
Could you please suggest common practice and way to achieve this?
Note: Make sure that to override node template file with respect to content type then both template files node.tpl.php and node-[content_type].tpl.php file need to be in your theme directory.
The file you're looking for is node-mycontenttype.tpl.php . You want a node template, not a page template. If you rename page-node-mycontenttype.tpl.php to node-mycontenttype.tpl.php, you'll get the result you're expecting.
The page template (page.tpl.php) in Drupal defines the overall markup and where the contents of the various regions will be outputted. Traditionally it includes the logo, menu, footer message, and a few other static elements. The Drupal theme system allows you to override the entire page template for a specific node type (which is what you ended up doing), but based on your explanation, what you're really trying to do is override just the node template.
Further reading:
Explanation & diagram of what files control which pieces of output: http://drupal.org/node/171194
General documentation on overriding output in the theme system: http://drupal.org/node/341628
When reading the above, make sure to note the version of Drupal that it applies to (there's a tag up at the top of each page). Things changed fairly dramatically between 5 and 6 and have shifted again (though not nearly as much) between 6 and 7.
t-dub is right about node-contenttypename.tpl.php.
However, if you want to retheme the entire page for a given content type (maybe a landing page), you have two options (there are likely other options but these are the ones I've discovered.
You may use a module called sections and then create a theme for each of the different content types.
OR
You can add the following function to your theme's template.php:
function templatename_preprocess_page(&$vars) {
// Template change based on node->type
if (isset($vars['node'])) {
// Add template naming suggestion. It should alway use hyphens.
$vars['template_files'][] = 'page-'. str_replace('_', '-', $vars['node']->type);
}
}
Just swap out templatename (in the function name) for the name of your template. Then you can create page-contenttypename.tpl.php for a unique design for nodes of that content type.
I've used sections in the past, but I prefer using the method described in #2 because it feels more drupal-ly. Its also a lot simpler to maintain.
Hope this helps someone!
I'm a little new to drupal but have been using things like devel module and theme developer to speed up the learning process.
My question, is it possible to theme an entire views BLOCK from a single views tpl.php page OR even a preprocess?
When I'm grabbing the $view object I can see results $node->result, it has all of the results, but it doesn't have all my views fields. I'm missing things like, node path, taxonomy titles and paths, etc.
From my understanding, Drupal wants you to individually theme EACH output field. It seems rather superfluous to create so many extra templates when I've already got over HALF of my results coming through the $view object
Would outputting node over field make this easier? Or am going in the wrong direction with $view->result?
Thanks!
this page might help: http://drupal.org/node/342132
I rarely theme at the views field level -- agreed: it's too many files to edit. So I either do it at the node/teaser level, or load the view programmatically, and then display it in a function in my glue module.
whether to do nodes or fields depends on how else you're displaying the items. for example, if the only way you're using teasers is in this view, it might simplify things to do the theming in the node-mytype.tpl.php file. If you have four different views, all of which have different themes, you might use the glue module approach. There's also the css-only appraoch. Or, sometimes, views theming truly is the best option.
update: you can also use node_load in your glue module to get more node info. That can be expensive, performance-wise, depending on the size of your view and how often the nodes change. (node_load does some caching...)
I have a web application developed using PHP. I want my users to select themes for their pages throughout the application.
Where should I start before using PHP themes?
What should I know about Themes in a PHP application?
Edit:
My question about themes is only about changing the color of the layout, not the images.
Suppose My ADMIN user will have white and Orange, but my staff user will have white and green...
How it can be done in PHP with CodeIgniter?
There are lots of directions you can go with this.
1) "CSS ZEN"
This is where the markup remains unchanged, but you totally change the design just by using CSS and images. Demonstrated very well on http://www.csszengarden.com/
2) MVC Stylee
This is where you create a model that represents the page data and then pass it to a view, which contains some inline echo statements. The idea is that you could send the same model to a totally different view so it could look entirely different, HTML and all. Cake PHP is a good start for this: http://cakephp.org/
Example:
<div class="content">
<? echo $Page->Content ?>
</div>
3) Micro-Markup
With this method, you add your own "special tags" to an HTML page. You then read in your plain HTML page and replace the special tags with the information you want to display. This is good if you want your templates to be recognisable to HTML guys that don't know PHP and might break the PHP code in the MVC app.
Example:
<div class="content">
<#Content#>
</div>
Out of all of these, MVC is a very structured way of achieving what you want - however, I listed the other options as they cater for specific scenarios that might be relevant to you.
I have implemented the concept in all three of these, in situations that were appropriate for each.
Regarding The Edit In The Question
I imagine you'll have "something" that represents your user - so it is as easy as:
(In the event of just wanting to override a few settings...)
<link href="style.css" type="text/css" rel="stylesheet">
<?php if ($User->Type === USER_ADMIN) { ?>
<link href="admin.css" type="text/css" rel="stylesheet">
<?php } ?>
You can adjust this example in the following ways:
Use a switch statement if there will be many user types
If the replacement is total, rather than just a few overrides, you may want to completely swap the stylesheet.
You would usually set up template files that contain the HTML and CSS, and build in the PHP generated values at runtime.
The best approach to this is to have the theme reside in a separate directory, containing no code, just template variables like {mainmenu}, {backbutton}, {content} ... you get my drift. Those are then filled by your PHP script, possibly with the help of a template engine like Smarty (No need to re-invent the wheel here).
There is also the approach of having PHP markup directly in the template file(s) like echo $xyz; while this is a perfectly valid practice I use myself often, I recommend using a template engine over using PHP markup in the code if you want a solid, future-proof templating system because:
First, there is less that a designer can break when working on the HTML.
Second, having PHP markup in the code is a temptation to program PHP logic inside the template (loops, conditions) instead of properly preparing them in the PHP code at the point where the template variables are created. That is terrible for maintenance and the further use of your templates, because you have to replicate that PHP soup into every new template again. After all, you want to have a template engine so others can create new looks for your product, without having to know how to program it.
Third, with the templating engine based approach you have the possibility to add caching where necessary without any additional work. Not possible with the scripting approach. Yes, in a web application you won't be able to cache that much, but with a lot of data, there will be instances where it will help the user experience.
Fourth and least important, it makes your template less easy to export to other applications, and import templates from other applications.
The CSS Zen approach mentioned by Sohnee is great for websites, but is going to be too limited for a web application that uses complex input elements, JS based menus, and the like. It is too often that those elements need to be changed and customized in the markup.
If you have a look at my CodeIgniter Template library it briefly explains how you can set up themes and layouts (the equivalent of header & footer).
If you set up global code such as a Hook or a MY_Controller then you can dynamically set your theme based on the logged in user, the user type, etc.
Eg:
if($user->role == 'admin')
{
$this->template->set_theme('admin_skin');
}
else
{
$this->template->set_theme($user->theme);
}
That is just a VERY basic example of the sort of thing you could use this Template library for.
CMS Solutions
Magento and Wordpress package all theme related files into their own seperate directories. These contain the serverside code, stylesheets, images and javaScript for the theme. The user in effect chooses a directory to use which affects how the page is layed out and styled.
An easier approach
A much easier way to get started would be to accept that the actual content, e.g. HTML of a page would stay the same, but let the user choose from various CSS style sheets.
When choosing a style sheet the system could use JavaScript to load it in dynamically so that the user can preview the look they are choosing.
If you have really good semantic HTML it will be enough to change the CSS files. Unless the design changes are really heavy. Then it would make sense to provide PHP templates that are build with some sort of modules: variables which contain certain HTML structure like navigation or sidebar, etc.
For themes you do not need PHP. Just define your themes in CSS (the best way is one file for each theme) and use a simple JavaScript chooser like at this site: http://www.fotokluburan.cz/switchcss.js.