Making CCK fields read-only in Drupal 6

Posted on May 14, 2012, midnight

Generally, using form alter on any form field and setting #disabled => TRUE works great. However, form alter is too early of a hook to use on CCK's fields. Moreover, if you disable a field, the browser won't even post the value. This can result in annoying validation issues. So why this post? I found that the most popular post on this topic did not work for me. This post applies to Drupal 6. But relax, there's a Drupal 7 technique.

The correct and safe way to do lock changes to a widget is to mark its HTML elements as read only, not as disabled. To do this, we use the readonly attribute. This ensures that the browser posts the value, unlike disabled. But we can't just stop here. We need to make sure the value isn't changed by a crafty user modifying his post request.

Learning Drupal? Subscribe to my Drupal articles, tips and tutorials.

First, let's hook in to the node form so we can add our #after_build callback. Keep in mind that in this example, we're adding our callback to all node forms. You might want to further limit this to a specific content type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php

/**                                                                           
 * Implements hook_form_alter().                                              
 */                                                                           
function example_form_alter(&$form, &$form_state, $form_id) {                 
  if (isset($form['#node']) && $form_id == $form['#node']->type .'_node_form') {
    $form['#after_build'][] = 'example_after_build';                          
  }                                                                           
}

Let's keep things simple and modify a text widget. For simple widgets, CCK generally uses the key value.

1
2
3
4
5
6
7
8
<?php

function example_after_build($form, &$form_state) {                           
  $field = 'field_example_cck_field';                                         
  $form[$field][0]['value']['#attributes']['readonly'] = 'readonly';          
  $form_state['values'][$field][0]['value'] = $form[$field]['#default_value']['value'];
  return $form;                                                               
}

And that's it! You can now count on your field being readonly. Yet it will still be posted by the browser. And even if a user tries to post a changed value - or uses Firebug to edit the contents of the fields - our build function restores the original value.

Below is the complete code for reference.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php

/**                                                                           
 * Implements hook_form_alter().                                              
 */                                                                           
function example_form_alter(&$form, &$form_state, $form_id) {                 
  if (isset($form['#node']) && $form_id == $form['#node']->type .'_node_form') {
    $form['#after_build'][] = 'example_after_build';                          
  }                                                                           
}

function example_after_build($form, &$form_state) {                           
  $field = 'field_example_cck_field';                                         
  $form[$field][0]['value']['#attributes']['readonly'] = 'readonly';          
  $form_state['values'][$field][0]['value'] = $form[$field]['#default_value']['value'];
  return $form;                                                               
}