Drupal 6 how to

Drupal 6 how tos.

Index

Customise contact form

This requires a module so you can use hook_form_alter(). E.g:

/**
 * Implements hook_form_alter() to add a checkbox for basic spam control.
 */
function anti_spam_contact_form_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'contact_mail_page') {
    $form['submit']['#weight'] = 2; // Set the weight of the submit button so we can position the checkbox.
    $form['human'] = array(
      '#type' => 'checkbox',
      // We add the asterix markup to the title as there seems to be a bug in Drupal that prevents it
      // being added automatically as it would if it were any other type of field.
      '#title' => t('Are you human? <span class="form-required" title="This field is required.">*</span>'),
      '#description' => t("This is a basic mechanism to prevent spam. Please check the box."),
      '#required' => TRUE,
      '#element_validate' => array('is_human_checked'),
      '#weight' => 1
    );
  }
}

/**
 * We need a validation function as there seems to be a bug in Drupal that prevents it
 * auto validating required checkboxes as it would if it were any other type of field.
 */
function is_human_checked($element, &$form_state) {
  if (empty($element['#value'])) {
    form_error($element, t("Please check the box to tell use you're human!"));
  }
}

Add a menu item, but for the path enter the full URL. e.g. http://www.google.com/

Hide menu items from anonymous users

Sometimes a menu item will show up even if the user doesn’t have access to view the content, e.g. the forums item will show even when clicking it generates “No forums defined”.

Two options:

  1. Create a block for access restricted menu items and deny anonymous users.
  2. TODO - reminder to look through my paper notes and update this!

Get users in a role

Given the name of a role, e.g. TheRole, get the role ID and use it to query the DB for user IDs. Then use user_load to get user objects.

$result = db_query("SELECT rid FROM {role} r WHERE r.name = '%s'", 'TheRole');
$record = db_fetch_object($result);
if ($record) { // We have role id.
  $results = db_query("SELECT u.uid FROM {users} u INNER JOIN {users_roles} ur ON u.uid=ur.uid WHERE ur.rid = %d AND u.status = 1", $record->rid);
  while($record = db_fetch_object($results)) {
    $account = user_load($record->uid);
    // Do whatever.
  }
}

Send email from a module

The code below is from a members_list module that I write for a project. It emails a file $filename (e.g. ‘sites/default/files/members_list.csv’) to all users in the ‘MailTest’ role. The first method of sending an email, using Drupal’s drupal_mail method, is commented out because it can not send attachments, though it can of course send emails without this requirement. The second method is members_list_send_email_via_mimemail, which is a wrapper that end up calling the mimemail method of the Mime Mail module. This can send attachments. The code below should be easy enough to interpret.

/**
* Email the members list to users with the Secretary role.
* @param string $filename The full filename of the file to email.
*/
function members_list_send_members_list($filename) {
  $attachments = array(
                   array('filepath' => $filename, 'filemime' => 'text/csv')
                 );

  // Get users with Secretary role and email them the attachments.
  // TODO: Roll the following two queries into one or continue hunt for Drupal API function to query users.
  $result = db_query("SELECT rid FROM {role} r WHERE r.name = '%s'", 'MailTest');
  $record = db_fetch_object($result);
  if ($record) { // We have role id.
    $results = db_query("SELECT u.uid, u.name, u.mail FROM {users} u INNER JOIN {users_roles} ur ON u.uid=ur.uid WHERE ur.rid = %d AND u.status = 1", $record->rid);
    while($record = db_fetch_object($results)) { // We have users.
      $account = user_load($record->uid); // Get user object.
      watchdog('members_list', 'Emailing '.$filename.' to '.$account->name.' at '.$account->mail.' with latest members list.');

      /* NOTE: We can't use drupal_mail (with members_list_email hook) because it doesn't support attachments.
      $params = array('account' => $record);
      drupal_mail('members_list', 'members_list', $record->mail, language_default(), $params); // Send email. Failure is logged by default.
      */

      members_list_send_email_via_mimemail($account, $attachments); // Use Mime Mail module to send email, as it can handle attachments.
    }
  }
  else {
    watchdog('members_list', 'ID of Secretary role could not be retrieved.'); // Log failure.
  }
}

/**
* Send an email using the Mime Mail module.
* @param User object $account User object
* @param array $attachments 2D array of attachments. See Mime Module README.txt.
* @return Return value of mimemail function call.
*/
function members_list_send_email_via_mimemail($account, $attachments) {
  $language = user_preferred_language($account);
  $sender = variable_get('site_mail', false);
  $variables = user_mail_tokens($account, $language);
  $recipient = $account->mail;
  $subject = t('Members list from !site', $variables, $language->language);
  $body = t("Dear !username\n\nSee attached for latest member's list.", $variables, $language->language);
  return mimemail($sender, $recipient, $subject, $body, true, array(), NULL, $attachments, '');
}

/**
* Mime Mail hook to prevent it using site's CSS for the email.
*/
function members_list_mimemail_message($body) {
	return $body;
}

/**
* Drupal hook to compose email with members list attached.
* NOTE: This does not currently work because attachments are not supported by default Drupal mail functionality.
*
* @param array $key A key to determine which email is sent. Currently only 'members_list' is available.
* @param array $message The message, as already set up by Drupal and modified in this function.
* @param array $params Must contain an 'account' key whos value is a user account object that has at least the 'uid', 'name' and 'mail' member variables.
*/
function members_list_mail($key, &$message, $params) {
  $language = $message['language'];
  $variables = user_mail_tokens($params['account'], $language);
  switch($key) {
    case 'members_list':
      $message['subject'] = t('Members list from !site', $variables, $language->language);
      $message['body'][] = t("Dear !username\n\nSee attached for latest member's list.", $variables, $language->language);
      break;
  }
}

Get system variables

Site domain

global $base_url;

e.g. “http://the.web.site/”

‘files’ directory path

$path = files_directory_path();

e.g. ‘sites/default/files’

Site language

$language = language_default();

$language is an object. $language->language gives language name.

User’s preferred language

$language = user_preferred_language($account);

If the user hasn’t set a language the site default will be used.

Save a file

file_save_data('the data', 'the/file/name');

A third argument can be used to determine whether to replace, append or do nothing if the file already exists.

Programmatically download a file

Had to use cURL to login in to drupal and get URL to save as file. Need to be able to do it from Drupal’s cron.php without having to authenticate via cURL (which requires password).

So, TODO - reminder to look through my sites to extract details and update this!

Class per menu item

To show a class for each menu item that reflect its href, override the theme_menu_item_links and modify the link class. E.g. a modification of the override provided by the Zen theme…

/**
 * Implements theme_menu_item_link(), taken from zen's template.php and adds class to
 * each item that reflects the href.
 */
function [theme]_menu_item_link($link) {
  if (empty($link['localized_options'])) {
    $link['localized_options'] = array();
  }

  // If an item is a LOCAL TASK, render it as a tab
  if ($link['type'] & MENU_IS_LOCAL_TASK) {
    $link['title'] = '<span class="tab">' . check_plain($link['title']) . '</span>';
    $link['localized_options']['html'] = TRUE;
  }

  // Add class that reflects href.
  $class = preg_replace('/[^a-z0-9]+/i','-',$link['href']);
  $link['localized_options']['attributes']['class'] = $link['localized_options']['attributes']['class'].' menu-item-'.$class;

  return l($link['title'], $link['href'], $link['localized_options']);
}

Rename the contact form

The contact form takes its title from its default menu item, so rename that and the page name will change. This works even if the default menu item is disabled and you’ve a custom item in another menu.

Translate URLs in PHP

This example shows translation of URLs (and use of t function):

<?php
$lang_code = i18n_get_lang();
$theme_path = path_to_theme();
// Build link to node 21 using "friendly" URL alias.
$path = 'node/21';
$translation_paths = translation_path_get_translations($path);
$translation_path = $translation_paths[$lang_code];
if ($translation_path != '') {
  $path = $translation_path;
}
$alias = drupal_get_path_alias($path,$lang_code);
?>
<div class="icon"><a href="/<?php print $lang_code.'/'.$alias ?>"><img src="/<?php print $theme_path; ?>/images/icons/classified_ads_32.png" alt="<?php print t('Classified adverts'); ?>" title="<?php print t('Classified adverts'); ?>"/></a><a href="/<?php print $lang_code.'/'.$alias ?>"><?php print t('Classified adverts'); ?></a></div>

See Get correct link to translated version of given node

Handle string translation in PHP

Use the t function so that the string appears in the i18n’s translate interface.

<?php print t('whatever'); ?>

Have a view handle multi-lingual content

To show only language neutral nodes those in current language: Filter by ‘Node translation: Language’ and select “Current user’s language” and “No language”.

Create a view that groups by taxonomy vocabulary terms

  1. Set row style to ‘fields’.
  2. Add ‘Taxonomy: All terms’ as a field, selecting the vocab you want to group by and excluding it from display. Here you can also choose the vocab and other display options such as whether or not to link to the vocab.
  3. Set style as ‘unformatted’ and group by ‘All terms’.

Note: To have the taxonomy terms translated properly, you need to override and edit the View module’s views-view-unformatted.tpl.php (or the equivalent for whatever display style you’re using) and replace this…

<h3><?php print $title; ?></h3>

…with this…

<?php $term = taxonomy_get_term_by_name($title); ?>
<?php if ($term): ?>
  <h3><?php print i18nstrings('taxonomy:term:'.$term[0]->tid.':name', $term[0]->name);  ?></h3>
<?php endif; ?>

Specify a theme’s module dependencies

In the theme’s .info file:

dependencies[] = content
dependencies[] = views
etc

Note: Use ‘content’ instead of ‘cck’.

Use preprocessor functions for specific content types

First you must register the functions in the theme_preprocess_node function in template.php (from Zen’s template.php):

function mytheme_preprocess_node(&$vars, $hook) {
  ...
  // Optionally, run node-type-specific preprocess functions, like
  // mytheme_preprocess_node_page() or mytheme_preprocess_node_story().
  $function = __FUNCTION__ . '_' . $vars['node']->type;
  if (function_exists($function)) {
    $function($vars, $hook);
  }
  ...
}

Theme a node to reorder fields

Note: You could instead use the Content Display Order module to do this. See above. ???

  1. Create a template for the node, e.g. sites/all/themes/[mytheme]/templates/node.tpl.php or node-contenttype.tpl.php.
  2. Instead of using $content to output all markup, you can index into the $node array to pick out the fields you want to display.
  3. CCK sets variables for each field, so you can access their values directly, e.g:

    $field_url[0]['view'] == 'http://example.com'
    
    $field_image[0]['view'] == '<img  class="imagefield imagefield-field_image" width="128" height="128" alt="Advert for puppies" src="http://example.com/en/system/files/adverts/dev-128x128.png?1311779084" />'
    

    However, this only includes the field’s markup and not the markup that would normally be added around the field.

  4. CCK also sets vars for the field’s rendered markup (including the markup that would normally be added around the field). See http://drupal.org/node/807330

    $field_url_rendered
    

    E.g. if you have a normal body and CCK fields for URL and image, then…

    <?php print $content; ?>
    

    …is equivalent to…

    <?php print $node->content['field_url']['#children']; ?>
    <?php print $node->content['body']['#value']; ?>
    <?php print $node->content['field_image']['#children']; ?>
    

    …is equivalent to…

    <?php print $field_url_rendered; ?>
    <?php print $node->content['body']['#value']; ?>
    <?php print $field_image_rendered; ?>
    

Use PHP in a block

  1. Enable the PHP Filter core module.
  2. Administer -> Site building -> Input formats.
  3. Make sure only the desired roles can use the new ‘PHP code’ format. Keep as ‘no roles’ if you’ll only be adding PHP as admin.
  4. Create/edit a block and set its input format to PHP code.

Create a block to output site mission

The site “mission” is a short introduction to the purpose of the site, or a slogan or tag line or anything else that goes some way to explaining the site and that you’d like to show on many pages, either in the template or in a block, as follows:

  1. Set up ability to use PHP in a block, as described above.
  2. Add the following as the block content:

    <?php
      $mission = variable_get('site_mission','');
      if ($mission) {
        echo '<div id="mission">'.$mission.'</div>';
      }
    ?>
    

Moving user menu items

Put login, my account and logout menu items in a different menu (e.g. in Secondary Links).

Log in: Create a menu item pointing to /user/login.

Log out: Move ‘Log out’ menu item from Navigation menu to the other menu.

My account: Move ‘My account’ menu item from Navigation menu to the other menu.

Translate menu items

You’ll need localisation set up. See ‘Locale, Content Translation, i18n and Language Icons’ section above. ???

  1. Create a menu item, setting its Language to ‘All Languages’.
  2. Administer -> Site building -> Translate interface.
  3. Search for the item (you can limit the search to only menu items).
  4. Edit the item for the language you need to add (its language code will be crossed through, indicating it doesn’t have a translation).
  5. Add the translation and save.

Translating system variables

Most variables can be translated via Administer -> Site building -> Translate interface. However, some Drupal default variables are handled differently.

See Multilingual Variables

With the i18n module installed, add the following to sites/default/settings.php:

/**
 * Multilingual settings
 *
 * This is a collection of variables that can be set up for each language when i18n is enabled.
 * These are the basic ones for Drupal core, but you can add your own here.
 */
$conf['i18n_variables'] = array(
  // Site name, slogan, mission, etc..
  'site_name',
  'site_slogan',
  'site_mission',
  'site_footer',
//  'anonymous',
  // Different front page for each language
//  'site_frontpage',
  // Primary and secondary links
//  'menu_primary_links_source',
//  'menu_secondary_links_source',
  // Contact form information
//  'contact_form_information',
  // For theme variables, read more below
//  'theme_settings',
//  'theme_garland_settings',
);

Now the site name, slogan, mission statement and footer can be translated by visiting Administer -> Site configuration -> Site information, switching to the language (using the switch provided by the languageicons module) and updating the variables.

Create rotating adverts

  1. Install the following modules:
    • CCK. Enable Content and Text.
    • FileField. Required by ImageField. Enable FileField.
    • ImageAPI. Required by ImageCache. Enable ImageAPI and ImageAPI GD2 or ImageAPI ImageMagick.
    • teration. Required by ImageCache. Enable Transliteration.
    • ImageCache. Enable ImageCache.
    • ImageField. Enable ImageField.
    • Views. Enable Views and Views UI.
    • Views Slideshow (enable Views Slideshow and Views Slideshow: SingleFrame).
  2. For advert images, create a new ImageCache preset called “Small” (at Administer -> Site building -> ImageCache).
  3. Create a new ‘Advert’ content type. Disable ‘Promoted to front page’ and comments.
  4. Give the Advert a new CCK image field called Image (type File, widget Image).
  5. Give the Advert a new CCK text field called URL (type Text, widget ‘Text field’).
  6. Edit the Advert’s basic display fields to hide the image label and set its teaser to ‘Small image’.
  7. Create a new view called “Adverts”.
  8. Set its Defaults as follows:
    • Filters: ‘Node: Type’ is one of ‘Advert’. ‘Node: Published’ Yes.
    • Fields: ‘Node: Body’, ‘Content: Image (field_image) - data’ (exclude from display, data key: alt), Content: URL (field_url) (exclude from display), ‘Content: Image (field_image)’ (output field as a link - with link page [field_url_value] and alt text [field_image_data] - no label and format ‘Small image’).
    • Sort criteria: ‘Global: Random’. 9 Add a Block display called “Block - Slideshow”.
  9. Override Style and set it to ‘Slideshow’.
  10. Save.
  11. Add the slideshow view to whatever part of the page you want it to show.

Create an events calendar

  1. Install the following modules:
    • Views (enable Views).
    • Date (enable Date API and Date Timezone).
    • Calendar.
  2. TODO - reminder to looks through my sites to extract details and update this!

Prevent ‘submitted by’ showing

To prevent a content type showing ‘submitted by’ info, go to Administer -> Site building -> Themes, Configure tab, Global settings. In the ‘Display post information on’ section choose the content types you’d like to show post info.

Determine which blocks are present

The block_list function will list blocks in a particular region, e.g:

$section_menu_in_sidebar_second = array_key_exists('section_menu_0', block_list('sidebar_second')) ? true : false;

Get private filesystem virtual path from actual path

When using the private filesystem, each private file gets a virtual ‘system’ path.

To rewrite from a file’s actual path to its virtual path, use the file_create_url function (unfortunately you can’t use file_create_path as it’s broken and doesn’t work with both public and private filesystems - see file_create_path($image) breaks URL when private file directory is used):

file_create_url('sites/default/files/pretty-picture.jpg') -> 'http://example.com/system/files/pretty-picture.jpg'

Last modified: 12/11/2012 Tags: ,

This website is a personal resource. Nothing here is guaranteed correct or complete, so use at your own risk and try not to delete the Internet. -Stephan

Site Info

Privacy policy

Go to top