Drupal Theme from Scratch ![]()
Theming a Drupal 7 Website
Before we can explore the template.php file, we should first make sure you understand a little bit about PHP. If you are already comfortable with PHP, then proceed to the template.php stuff.
What do those snippets of code mean? Those snippets of code are actually a mixture of PHP and Drupal code.
Programming can be a difficult process to understand, but reading the code isn't quite as tricky. This example is one of the easier ones:
<?php print render($content['field_main_image']); ?>
And here's how to decipher it:
The way PHP works is simple. As long as you save your file with a .php extension on a web server that has PHP running, the server will know to look for your PHP code and process it properly. The resulting HTML is what will be sent to the browser. This is why you will not see any PHP code when you right-click and 'view source' in your browser.
Now that you have practically no PHP knowledge (at least none from me), let's get more technical.
:)
The template.tpl.php file will be used to store any Drupal override functions you need. Preprocess functions in Drupal allow you to alter core functions before a given web page is rendered. Basically, if you have the desire or need to alter any of Drupal's core programming, you do it in THIS file. Never edit any core files.
When using any of the following functions, be sure to precede them with the machine name of your theme. Even though the template.php file is in your myTheme folder, Drupal needs to be reminded that the function in question is meant to work with your theme and your theme only.
The following code will alter the search form's input field type from 'text' to the HTML5 'search' type. This works by 'hooking' into Drupal's preprocess_search_box_form function and using PHP's str_replace function...
<?php
function myTheme_preprocess_search_block_form(&$vars) {
$vars['search_form'] = str_replace('type="text"', 'type="search"', $vars['search_form']);
}
?>
This piece of code is altering two forms by 'hooking' into Drupal's form_alter function. The first snippet looks for the search form, then alters its label text, sets the label to invisible, sets the size of the field, adds some Javascript, adds some placeholder text and adds some classes.
The second snippet looks for the login form, makes the labels invisible, adds some placeholders and some Javascript to both the name and password fields. Finally, some additional JavaScript and a class are added to the form.
<?php
function myTheme_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'search_block_form') {
$form['search_block_form']['#title'] = t('Search'); // Change the text on the label element
$form['search_block_form']['#title_display'] = 'invisible'; // Toggle label visibilty
$form['search_block_form']['#size'] = 40; // define size of the textfield
// Prevent user from searching the default text
$form['#attributes']['onsubmit'] = "if(this.search_block_form.value=='Search'){ alert('Please enter a search'); return false; }";
// Alternative (HTML5) placeholder attribute instead of using the javascript
$form['search_block_form']['#attributes']['placeholder'] = t('Search');
$form['search_block_form']['#attributes']['class'][] = 'search';
$form['actions']['#attributes']['class'][] = 'element-invisible';
}
if($form_id == 'user_login' ) {
$form['name']['#title_display'] = 'invisible';
$form['name']['#attributes']['placeholder'] = t('User Name');
$form['name']['#attributes']['onblur'] = "if (this.value == '') {this.value = 'User Name';}";
$form['name']['#attributes']['onfocus'] = "if (this.value == 'User Name') {this.value = '';}";
$form['pass']['#title_display'] = 'invisible';
$form['pass']['#attributes']['placeholder'] = t('Password');
$form['pass']['#attributes']['onblur'] = "if (this.value == '') {this.value = 'Password';}";
$form['pass']['#attributes']['onfocus'] = "if (this.value == 'Password') {this.value = '';}";
$form['#attributes']['onsubmit'] = "if(this.user_login.name.value=='User Name'){ alert('Please enter your user name'); return false; }";
$form['#attributes']['onsubmit'] = "if(this.user_login.pass.value=='Password'){ alert('Please enter your password'); return false; }";
$form['actions']['submit']['#attributes']['class'][] = 'button';
}
}
?>
Notice that these two forms are being altered by the same function. This is because we can only call each function once. We can't call the myTheme_form_alter once for the search form and then a second time for the login form otherwise an error will be produced.
"Do we have to alter forms this way?" If you use Drupal's Form API, yes. If you create PHP forms on your own some how, then probably not. However, if you wish to take advantage of Drupal's built-in form security measures, you'll want to learn the Form API.
For the sake of speeding up your load time, especially on mobile devices, your can use the css_alter function to prevent CSS files from loading if they are not needed by your theme. They will still load on the backend as long as the backend is controlled by a different theme.
<?php
function myTheme_css_alter(&$css) {
$exclude = array(
'modules/comment/comment.css' => FALSE,
'modules/node/node.css' => FALSE,
'modules/search/search.css' => FALSE,
'modules/system/system.menus.css' => FALSE,
'modules/system/system.messages.css' => FALSE,
'modules/system/system.theme.css' => FALSE,
'modules/taxonomy/taxonomy.css' => FALSE,
'modules/user/user.css' => FALSE,
'modules/shortcut/shortcut.css' => FALSE,
'modules/field/theme/field.css' => FALSE,
'sites/all/modules/calendar/css/calendar_multiday.css' => FALSE,
'sites/all/modules/date/date_api/date.css' => FALSE,
'sites/all/modules/date/date_popup/themes/datepicker.1.7.css' => FALSE,
'sites/all/modules/picture/picture_wysiwyg.css' => FALSE,
'sites/all/modules/views/css/views.css' => FALSE,
'sites/all/modules/ckeditor/css/ckeditor.css' => FALSE,
'sites/all/modules/ctools/css/ctools.css' => FALSE,
);
$css = array_diff_key($css, $exclude);
}
?>
Your list of CSS files will of course be different than this one. Make sure not to cancel any that are needed by your theme or frontend modules. There may be some testing needed on your part but the list above has worked for me, so far.
If you place your search form in your page header, then chances are good that you might not need it to show up again in another location.
<?php
function myTheme_form_search_form_alter(&$form, &$form_state) {
if ((arg(1) == 'node') && (arg(2) != NULL)) {
$form['#access'] = FALSE;
}
}
?>
As if we didn't have enough templates to deal with. Now I'm showing you how to make more...
<?php
function myTheme_theme() {
$items = array();
$items['user_login'] = array(
'render element' => 'form',
'path' => drupal_get_path('theme', 'myTheme') . '/templates',
'template' => 'user-login',
);
$items['user_register_form'] = array(
'render element' => 'form',
'path' => drupal_get_path('theme', 'myTheme') . '/templates',
'template' => 'user-register-form',
);
$items['user_pass'] = array(
'render element' => 'form',
'path' => drupal_get_path('theme', 'myTheme') . '/templates',
'template' => 'user-pass',
);
return $items;
}
?>
This function will allow you to create the following templates:
The following existing templates can be copied out of the modules/user folder and pasted into your templates folder for additional customization options...
Remember to always flush Drupal's cache after adding or creating new templates.
Another good reason to create your own 'main' menu is if you want to remove the 'leaf' class from Drupal's menus. I found the solution here and wound up with my version below. This is an example of Drupal's theme_menu_link function which you would add to your template.php file.
<php
// remove 'leaf' class from menu li...
function myTheme_menu_link(array $variables) {
// This is the part that removes or changes the 'leaf' class.
if (!empty($variables['element']['#attributes']['class'])) {
foreach ($variables['element']['#attributes']['class'] as $key => $class) {
if ($class == 'leaf') {
// To remove the 'leaf' class.
unset($variables['element']['#attributes']['class'][$key]);
}
}
}
return theme_menu_link($variables);
}
?>
If you read the article I link to above, you can get more details on how this relates to making your own menus.
This documentation is a work-in-progress. As I continue to learn more about the software, I will try to keep this documentation updated. I'm no expert of anything, so if anyone feels they need to correct me about something I've written or wish to add some additional tips, feel free to mention it in the comments.
"Drupal 7 Theme from Scratch" was written by TenTen71 because no one else would.