Localize date format using i18n

Tested on:

  1. Drupal 6.16+
  2. Date API 6.x-2.4
  3. Internationalization 6.x-1.3

Any date format is stored as system variable (on the global $conf variable).

Since Internationalization module allows to declare some system variables as Multilingual, you could add to your $conf[‘i18n_variables’] on settings.php these lines to use different date format for different languages:

$conf['i18n_variables'] = array(
// Other variables
// bla bla bla
// Date variables

date_format variables are Long, Medium and Short date format, used in many places (including Views).

date_first_day is the first day displayed on calendars (e.g. Sunday for English, Monday for Italian).

Note that you have to save the value twice via:


And one more time:


After the first time, you can change format as you like without double checking.

See also:

How to automatically translate your Drupal module

You’ve created your module. But how to translate it into different languages?

Tested with:

  • Translation template extractor 6.x-3.0
  • Drupal 6.x
  • English default + Italian translation


  • Another language active apart default (English)
  • Use t() function for all translatable string, including ones on my_funny_module.admin.inc (Administration interface).

If you use t() function correctly on your module, you can create your own translation using the handy Translation template extractor module.

  1. Download and install Translation template extractor module.
  2. Create a directory named “translations” within my_funny_module directory (your module directory)
  3. Go to admin/build/translate/extract
  4. Select your module from Directory lists
  5. Select “Language independent template” and click “Extract”
  6. Save file to my_funny_module/translations directory as my_funny_module.pot
  7. In the same screen, select “Template file for Italiano translations” (where Italiano is your destination language)
  8. If you’ve already translated some strings into Italiano language, check “Include translations” to include these strings
  9. Click “Extract”, and save file to my_funny_module/translations directory as it.po, where “it” is the ISO 639-2 code for Italiano language
  10. You can add information about translation changing the first part of both files (translator mail, name, etc.)

Now, when you install your module translation strings will be added automatically. If you apply some changes to these files, and in any case the first time you complete this procedure on an active module, you have to refresh translation cache. To do this, go to admin/build/translate/refresh and use Refresh strings and Update translations after you’ve checked all boxes. If problem persists (strings are not updated or you got some weird errors), try to reinstall your module.

Disable upload and comment for a new content type programmatically

Following code is useful when installing a module that create a new content type programmatically on Drupal 6.x.

Basically, it adds two variables setting default values for comments (core Comment module) and attachments (core Upload module).

Code to write on my_funny_module/my_funny_module.install.

function my_funny_module_install() {
  // Disable attachments
  // Read http://api.drupal.org/api/function/upload_nodeapi/6 on "load"
  variable_set("upload_my_content_type", 0);

  // Disable comments for this content type
  // Read http://api.drupal.org/api/function/comment_form_alter/6
  variable_set('comment_my_content_type', COMMENT_NODE_DISABLED);

  // Install schema as usual (if any)

Note that this code assign only default values for my_content_type: as any content type, this value could be later changed via GUI.

Theme a multiple CCK field with a table

Sometimes CCK contrib modules cannot do exactly what you want. It’s time to build your custom CCK field!

Official documentation on CCK fields creation for Drupal 6 is incomplete and some passages are obscure. If there is a good howto you have to read before do any CCK customization, this is Creating Custom CCK Fields. This howto supposes you’ve read and understand it before continue. If you want to create a custom field, you can read the complete Creating a Compound field. A custom multiple compound field (with more than one field for element, e.g. an image and its description).

Read these howto well, you’ll spare time later

Well, you have followed the howto, you have your own compound field but now you have a problem. You want to display compound field data as cells in a table, and each field as row.

On following example, we have a name list made with a multiple compound field with “firstname” and “lastname” columns.

KarenS tell you that you’ve to use CONTENT_HANDLE_MODULE instead of CONTENT_HANDLE_CORE on hook_formatter_info() .

// The machine name of the formatter.
function my_funny_module_field_formatter_info() {
  return array(
    'default' => array(
      'label' => t('Default'),
      // An array of the field types this formatter
      // can be used on.
      'field types' => array('examplefield'),
      // CONTENT_HANDLE_CORE:   CCK will pass the formatter
      // a single value.
      // CONTENT_HANDLE_MODULE: CCK will pass the formatter
      // an array of all the values. None of CCK's core
      // formatters use multiple values, that is an option
      // available to other modules that want it.
      'multiple values' => CONTENT_HANDLE_MODULE,

/** Set the formatter **/
function my_funny_module_theme() {
  return array(
    'my_funny_module_formatter_default' => array(
      'arguments' => array('element' => NULL),
      'function' => 'funny_display_table',

/** Here you format your table data as array **/
function my_funny_module_formatter_default($element) {
  $data = array(
  return $data;

/** This function will display a table even where data array is empty:
 ** You have to put an additional control statement to avoid this.
 ** $element will have $data from formatter_default() above
function my_funny_module_display_table($element) {
  $header = array(
    t('First name'),
    t('Last name'),
  $i = 0;
  while (!$end) {
    /** Any row will contains **/
    if(array_key_exists($i, $element)) {
      $rows[] = array(
        'firstname' => $element[$i]['#item']['firstname'],
        'lastname' =>$element[$i]['#item']['lastname'],
    else {
      $end = TRUE;
  /** Theme a table with data from element and header **/
  return theme('table', $header, $rows);

Note: to format a table you have to change only “multiple values” on my_funny_module_field_formatter_info(): you can leave my_funny_module_widget_info() as is.

See also:

Add CSS style for a block into the same block

This simple code can be pasted into a PHP filtered block (or into a block declared by a module) to set some style from a block into the block container itself.

echo 'My block content';
/** Put styles inline on html head**/
drupal_set_html_head('<style type="text/css">
#my-block-id {
  /* my style*/

This code is placed on html head, applied only to the pages where block appears, without touching css optimization. If you want to include an external CSS file instead, use drupal_add_css instead: in any case you can exclude this file for aggregation, setting $preprocess attribute to FALSE.

If block appears in very few pages, and it can change quickly (e.g. a banner with custom styles on home page), using drupal_set_html_head could be the best way, even according to Yahoo Performance Best Practices. In other cases, use drupal_add_css.

See also:

Cron cannot run on Drupal: the drupal_goto() case

Sometimes you want to redirect a page to another on drupal. You can do this using a simple function called drupal_goto().

On few sites I’ve enabled the PHP filter module and then created a new page with PHP code input format with drupal_goto(‘node/2’) to redirect the current page to a specified node. Bad idea.

I’ve noticed that, after this change, cron.php operations failed, if you have Search module enabled. On cron new contents are indexed by the Search module: when it got my PHP page, it tries to index it but suddenly is redirected to another. You can also found an error like “Maximum function nesting level of ‘100’ reached” on php error log, symptom of an indexing blocked by pages with drupal_goto inside.


  1. Comment all drupal_goto() instruction in your site within pages.
  2. Use an alternative method to redirect from a node to another.
  3. Run cron from Status Report page: you can adjust indexed content per cron on Search configuration page (admin/settings/search on 6.x)

You can add a new block with PHP code inside or (better) create a new module for this simple block (with a simple PHP switch statement as content), displaying it only on specified pages (on the bottom of block configuration). But if you create a PHP block via UI, and you put that block on every page, your site could be loop, so creating a module is the cleanest and secure way (if something go wrong, you can delete your module from the codebase and correct it). You can also find some contrib modules for redirect on drupalmodules.com.

See also:

Fatal error: Maximum function nesting level of ‘100’ reached, aborting!