Notes about Drupal 7 gotchas / bugs.
Index
- Theming blocks inside panels
- cron.php 404 not found
- Can’t use dpm() in templates
- Date field rounding when editing
- Temporary managed files and the private filesystem
- Rules OR condition format
- Set form #action so they still work when cached
- Can’t set border on radio buttons
- No paragraphs with Filtered HTML format
- ‘Main-page-content’-block-ordering
- Content type missing from ‘add content’ page
- Don’t mix and match field arrays
- Taxonomy term menu callback called too many times
- Yes/No checkbox
- Email Sender header doesn’t match the From address
- Theming taxonomy term pages
- A blank template override will be ignored
- View name must not contain hyphen
- Get stylesheet
- Module caching
- Hiding node links
- Theme functions vs preprocessors
- Usability
- Images
- Stylesheet / css loading
- path_to_theme()
- Sub theme inheritance
- Comments in [theme].info
- Display of excluded fields in Views
- Field vs view naming (Views 3)
- Search page vs block
- Filtering views by taxonomy vocabulary
- Form state does not show when form is submitted
- ‘Undefined index’ errors
Theming blocks inside panels
If you add a block to a panel(https://www.drupal.org/project/panels){:.weblink} then you won’t be able to use theme it using the normal template_preprocess_block()
function (or templates presumably) unless you change its style to ‘System block’ (via its settings when editing the panel content).
You could alternatively use the panels preprocess functions template_preprocess_panels_pane()
but this doesn’t seem to give you much to play with.
Cron.php 404 not found
If you’re on shared hosting and you find that wget http://example.com/cron.php
returns a 404 not found, it could be because cron.php is group writable. You should get a 403 forbidden (unless you provide the correct cron key
parameter, in which case it should be found).
To fix, deny the group write permission:
chmod g-w cron.php
Can’t use dpm() in templates
The dpm()
function won’t work in theme templates or template functions.
Use kpr()
instead.
Date field rounding when editing
I had an unlimited Date field on an entity bundle, which stored its date values correctly in the database but rounded to the nearest 5 minutes when editing the entity. The dates showed correctly when viewing the entity.
Turned out this was due to a bug with the Date module’s Text Field widget, which unlike the pop-up calendar widget does not allow you to choose an increment and defaults to a value larger it should.
The bug report is here: date field minutes and seconds rounding after update/save
As a work-around, until the bug is fixed, use the pop-up calendar widget instead of the text widget.
Temporary managed files and the private filesystem
If you try and upload a file destined for the private filesystem, but you haven’t set your private filesystem path via admin/config/media/file-system
, you may get the following error:
Warning: is_dir() [function.is-dir]: Unable to find the wrapper “private” - did you forget to enable it when you configured PHP? in file_prepare_directory() (line 437 of /home/test/drupal7/includes/file.inc).
The file will not have been uploaded (because the private filesystem path wasn’t set) but Drupal may have added a temporary entry to the file_managed
table, depending on how the module you were using was implemented. Temporary entries will have a URI beginning with temporary://
. They will be cleared up automatically via cron. Alternatively you can delete it manually from the file_managed
table.
If you try and upload the same file again before its temporary entry is removed from the file_managed
table, then you may get the following error:
Recoverable fatal error: Object of class stdClass could not be converted to string in DatabaseStatementBase->execute() (line 2171 of /home/test/drupal7/includes/database/database.inc).
Rules OR condition format
When using an OR conditional in a rule, each condition should be a child of the conditional. So x OR y OR z should be specified as follows:
- OR
- x
- y
- z
References
Set form #action so they still work when cached
If you are defining a form that will appear on multiple different pages (which it most likely will knowing Drupal) then you must set its #action
parameter:
/**
* Implements hook_form().
*
* @param array $form
* @param array $form_state
* @param string $form_id
* @return array Form config.
*/
function my_form($form, &$form_state) {
...
$form['#action'] = '#';
...
}
If you don’t do this then the form’s action parameter will be cached as the URL of the page on which the form is first rendered, causing it to always submit to that page regardless of which other pages it is shown on.
Can’t set border on radio buttons
If you’d like to set a border on radio buttons when there’s an error, you need to use the outline
property:
.form-item input.form-radio.error {
outline: 1px solid red;
}
Note that I’ve targetted input.form-radio.error
rather than just input.error
because use of override
will prevent you overriding border
on the other elements.
No paragraphs with Filtered HTML format
Despite the help text of the ‘Filtered HTML’ text format informing you that that “Lines and paragraphs break automatically”, they don’t. Line breaks and paragraphs will be filtered out because they aren’t listed in the allowed HTML tags.
To add them, go to Configuration -> Text formats -> Configure (Filtered HTML) -> ‘Limit allowed HTML tags’ section and add <p>
and <br/>
to the list of allowed tags.
‘Main page content’ block ordering
Drupal 7 comes with a block called ‘Main page content’ in the Content region. You may find that the ordering of this block is ignored by Drupal when you add other blocks to the region. To fix, simply change the position the ‘Main page content’ block within the region, save, then change it back - for some reason it takes this reshuffling for Drupal to update the weight of the block.
Content type missing from ‘add content’ page
Is the Node Limit module restricting the available types?
Don’t mix and match field arrays
At least in Views.
This works:
foreach($variables['fields'] as $id => $field) {
$field->wrapper_prefix = '';
$field->label_html = '';
$field->wrapper_suffix = '';
}
This doesn’t (it will generate errors, though oddly still render the fields):
foreach($view->field as $id => $field) {
$field->wrapper_prefix = '';
$field->label_html = '';
$field->wrapper_suffix = '';
$variables['fields'][$id] = $field;
}
Taxonomy term menu callback called a too many times
Given the following code…
function [mymodule]_menu_alter(&$items) {
if (isset($items['taxonomy/term/%taxonomy_term'])) {
$items['taxonomy/term/%taxonomy_term']['access callback'] = '[mymodule]_access_check';
$items['taxonomy/term/%taxonomy_term']['access arguments'] = array(2);
}
}
function [mymodule]_access_check($term) {
...
}
… The [mymodule]_access_check
function will be called loads of times. I counted 19 times on a taxonomy term page that showed only 4 nodes.
Yes/No checkbox
It is not possible to have a checkbox return ‘No’ when unchecked - it can only return 0. You can change it to return ‘Yes’ when checked, by using the ‘#return_value’ setting, e.g:
$form['communications'] = array(
'#title' => t('Further communications'),
'#description' => t("Check the box if you'd like to receive communications from Some Company."),
'#type' => 'checkbox',
'#default_value' => 'No',
'#return_value' => 'Yes',
'#required' => FALSE
);
Note: default value can be anything other than ‘Yes’ to have the checkbox unchecked by default.
Email Sender header doesn’t match the From address
drupal_mail()
doesn’t change the Sender header when you change the From address (though it does when it defaults to use the site email). This can cause problems in some email clients. Instead, you can do this from your hook_mail()
implementation:
$message['headers']['Sender'] = $message['headers']['Return-Path'] = $message['headers']['From'];
Theming taxonomy term pages
taxonomy-term.tpl.php is only responsible for outputting the term’s fields, not the nodes categorised by that term. The nodes are themed via node.tpl.php.
You can use preprocess functions to e.g. check for a particular vocabulary in order to theme the templates differently. E.g:
[mytheme]_preprocess_node(&$variables, $hook) {
...
// Determine whether we're viewing the 'Agents' vocab (ID 4).
$variables['viewing_agents_vocab'] = FALSE;
if (arg(0) == 'taxonomy') {
$term = taxonomy_term_load(arg(2));
if ($term->vid == 4) {
$variables['viewing_agents_vocab'] = TRUE;
}
}
...
}
function [mytheme]_preprocess_taxonomy_term(&$variables, $hook) {
// Determine whether we're viewing the 'Agents' vocab (ID 4).
$variables['viewing_agents_vocab'] = FALSE;
$term = $variables['term'];
if ($term->vid == 4) {
$variables['viewing_agents_vocab'] = TRUE;
}
}
The $viewing_agents_vocab
variable will now be available in both taxonomy-term.tpl.php and node.tpl.php, which allows you to conditionally theme depending on whether you’re viewing the ‘Agents’ vocab or not.
A blank template override will be ignored
If you override a template it must return some content (even if it’s a space character) otherwise it will be ignored and the next template up the hierarchy will be used instead.
For example, you override taxonomy-term.tpl.php in your theme:
<?php if ($term->vid == 4): ?>
.. some content ..
<?php endif; ?>
If $term-vid == 4
it won’t output any markup and will be ignored by Drupal, so the term page will still render as the parent template will be used instead.
If you add this to the end it’ll work fine because it’ll output markup regardless of the condition:
<?php print ' '; ?>
View name must not contain hyphen
Views should not allow you to create a view with a hyphen in its name, but as of 20/04/2011 it does. This will break Panels when trying to add a view pane. See Call to undefined method get_argument_input().
Get stylesheet
drupal_add_css()
returns the stylesheet array. drupal_get_css()
returns their rendered HTML links.
Module caching
When developing modules, you will need to clear the site cache to register any new methods added to yourmodule.module file.
Hiding node links
You can hide particular node links by removing them before render:
<?php unset($content['links']['comment']['#links']['comment-add']); ?>
Alternatively, in the page template, you can hide all node links but not specific links and you have to target a specific part of the render array.
This works:
<?php hide($page['content']['system_main']['nodes']['1']['links']['node']); ?>
These don’t work:
<?php hide($page['content']['system_main']['nodes']['1']['links']); ?>
<?php hide($page['content']['system_main']['nodes']['1']['links']['node']['#links']['node-readmore']); ?>
<?php hide($page['content']['system_main']['nodes']['1']['links']['node']['#links']); ?>
Theme functions vs preprocessors
Theme functions, e.g. theme_form
, are responsible for generating markup, while preprocess functions e.g. theme_preprocess_html
are responsible for setting up variables used in a template.
Usability
Main menu shows in default theme but main menu block is not set to display anywhere.
Images
This is probably due to my server setup. Some directories in sites/X/files only get 700 permission, e.g. files/fields and files/styles/large | medium | thumbnail, resulting in broken images. |
Stylesheet / css loading
You can not use a theme’s .info file to load multiple stylesheets with the same basename. E.g. the following won’t work:
stylesheets[handheld][] = f3-yaml/css/screen/anti.css
stylesheets[only screen and (max-device-width: 480px)][] = f3-yaml/css/screen/anti.css
Only the second anti.css will be used.
See Stylesheet override logic prevents loading of stylesheets of third-party libraries.
The work-around is to use drupal_add_css
function, supplying it a basename.
path_to_theme()
The path_to_theme()
function will return the sub-theme’s path when it’s used in code that’s “inherited” by the sub-theme. Use drupal_get_path
instead:
drupal_get_path('theme','the_theme_name')
Sub theme inheritance
See Creating a sub-theme.
A sub theme does not inherit regions, screenshot and logo from parent theme, so these have to be defined in its .info file.
You can override templates and theme functions (i.e. the sub-theme’s templates/functions are used over its parents), but preprocess functions are inherited (i.e. the parent’s preprocess functions are run before the sub-theme’s ones).
Remember: Theme functions, e.g. theme_form
, are responsible for generating markup, while preprocess functions e.g. theme_preprocess_html
are responsible for setting up variables used in a template.
Comments in [theme].info
In the [theme].info file, comments must be on their own line. E.g. If you have a comment after a variable assignment, the comment will be part of the assignment:
settings['f3_setting'] = 'Value' ; Comment
...
theme_get_setting['f3_setting'] -> 'Value ; Comment'
Display of excluded fields in Views
If you exclude a field from display, its content will still show up if used as the format’s grouping field. This can actually be used to create nested grouping, whereby you aggregate the content of many excluded fields into the (rewritten) output of another excluded field that’s used as the format’s grouping field.
Field vs view naming (Views 3)
Field name includes field_
prefix, view name doesn’t have a prefix: field_[field_name]
vs view_name
.
Search page vs block
The search page has a form with a “Enter your keywords” label and options for an advanced search (when permissions allow). The search block form has neither.
Filtering views by taxonomy vocabulary
You can filter a view by multiple vocabularies, by using the taxonomy term ID filter. If you expose the filter, there’s no problem - the user can select the term - but if you don’t expose the filter you won’t immediately be able to select the term - you’ll see “Taxonmy: Term (or Unknown)” on saving the filter.
In order to select the term, you have to first save the view, then edit the filter to select the term, because the view won’t know which terms are availble until you save it.
Form state does not show when form is submitted
Bug.
function [mymodule]_form($form, &$form_state) {
...
// This is always set and always empty.
$form_state['submitted']
...
}
‘Undefined index’ errors
Drupal 7 has apparently turned PHP error reporting to E_ALL
, so that notices are shown (I believe by default PHP won’t show notices). This can result in ‘undefined index’ errors. For example, the contact module of Drupal 7.17 will generate the following when you attempt to use it at an anoymous user (I also got it with admin) because it checks for a ‘copy’ field that wasn’t added to the form:
> Notice: Undefined index: copy in contact_site_form_submit() (line 155 of /var/www/html/modules/contact/contact.pages.inc).
See my bug report here: Undefined index: copy in contact_site_form_submit().
A temporary solution is to turn off PHP notices, by adding the following line to sites/default/settings.php:
/**
* Ignore PHP notice errors - Drupal 7 now shows them by default, but even core
* modules generate them (e.g. contact.pages.inc line 155 with anonymous user)
*/
ini_set('error_reporting', 'E_ALL ^ E_NOTICE');
“Notice: Undefined index” quick fix in drupal7 error reporting