Drupal 7 Read-Only Fields

Posted on Aug. 14, 2013

In an earlier version I showed you how to make CCK fields read-only using Drupal 6. CCK was merged into Drupal 7 as the fields API, so a new approach is required. This new post will show an easy and safe technique to make Drupal 7 fields read-only.

Generally, using form alter on any form field and setting #disabled => TRUE works just fine. However, form alter is too early of a hook to use on entity fields. Moreover, if you disable a field, the browser won't even post the value. This can result in annoying validation issues.

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

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 or her post request. Just imagine if they user the Chrome Inspector and altered the HTML attributes directly: they'd be able to modify the field. We need to prevent this.

In case you don't already have a field you want to lock down, let's create one really quickly.

  1. Browse to admin/structure/types.
  2. Find an existing content type, and click on manage fields.
  3. Add a field and give it the label Locked. The machine name should appear automatically as field_locked. Be sure to choose a text field type, using a textfield widget.

Now, 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. You might also want to check if this is an existing node, as locking the field on node creation might not be necessary.

<?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, the fields API generally uses the key value.

<?php

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

And that's it! You can now count on your field being read-only. It will still be posted by the browser. And even if a user tries to post a changed value - or uses the browser inspector to edit the contents of the fields - our build function restores the original value. Fast, safe, and secure.

Below is the complete code for reference.

<?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_locked';
  $form[$field]['und'][0]['value']['#attributes']['readonly'] = 'readonly';
  $form_state['values'][$field]['und'][0]['value'] = $form[$field]['und'][0]['value']['#default_value'];
  return $form;
}

Comments

bmayjorAug. 14, 2013, 3:20 p.m.

Nice, I was looking for a way to do this the other day. Thanks

Reply
darthstevenAug. 14, 2013, 4:54 p.m.

Also, have a look at the Field extra widgets module: https://drupal.org/project/field_extrawidgets which provides a field widget which is read only, which might work for some use-cases.

Reply
blainelangAug. 14, 2013, 11:57 p.m.

I had looked at the field_extrawidgets module as it proposes to provide readonly widget but it offers no way to set the field value. I had a need for a readonly text field were I was setting the value in a form_alter anyways and I didn't like the way it appears in the browser when using the disabled attribute. Your solution works the way I wanted.

Thanks again for posting it.

Reply
Thomas SvensonAug. 15, 2013, 4:11 p.m.

Very nice info. Just wondering, have you looked at the Field Permissions, https://drupal.org/project/field_permissions, module?

With it you can get read only with the "View any value for [field]" permission on a role basis and then easily give other roles edit rights.

Reply
AdamAug. 23, 2013, 6:36 p.m.

I have used a drupal_add_js that uses jQuery to add the "readonly" attribute.

Reply
silviogutierrezAug. 23, 2013, 9:50 p.m.

Adam, while this will work cosmetically, a user could just forge a POST request with different values, changing the field. Or using Firebug/Chrome Inspector, modify the values of the field. Moreover, he could just turn off JavaScript.

That means you also have to lock the backend too, which is done in the method I show above.

Reply
anrikunDec. 28, 2013, 2:20 p.m.

You may try https://drupal.org/project/field_readonly

Reply
silviogutierrezDec. 28, 2013, 3:01 p.m.

Very nice. Does this module make use of the above technique, or another approach?

Reply
densolisApril 10, 2014, 4:47 a.m.

I did the above for a text box and it worked great. However, I also need to so this for a check box field and a select list field for a taxonomy term and the above coded did not work. Any suggestions?

Using dsm, I was able to display the $form array and the appropriate array position ( $form[$field]['und'][0]['value']['#attributes']['readonly'] = 'readonly';) was set properly, but I could still change the values in the check box and select list taxonomy term fields.

Any suggestions on what I did wrong?

thanks

Reply
insenApril 18, 2014, 3:06 p.m.

I got the same problem. However setting 'readonly' value doesn't work in this case because select lists/check boxes already are 'readonly' (you can't change values, you just pick one). The way I'm trying to pass validation issues with select list is to set it as DISABLE. Then pass it with hidden field as sugested here: http://drupal.stackexchange.com/questions/95320/how-to-identify-disabled-fields-in-form-submit-handler

I will definitely reply if there is any success.

Reply
insenApril 18, 2014, 11:32 p.m.

Ok, finally found the solution. You have to do it through #required value. If you have trouble after reading this http://drupal.stackexchange.com/questions/97011/how-can-i-skip-field-validation-if-the-field-is-hidden

I can provide more information by myself.

Reply
insensatyApril 19, 2014, 1:13 p.m.

http://drupal.stackexchange.com/questions/97011/how-can-i-skip-field-validation-if-the-field-is-hidden

Finally I have figured out how to solve it. Check out the link. You have to do it through #required value in #after_build. If you are still expierincing troubles let me know. I can show you my code ;)

Reply
Benjamin IsraelSept. 11, 2014, 8:29 p.m.

I could not make this code work on my website for some reasons, although it is perfectly working on a brand new D7 test installation. The readonly feature was implemented but you could still override it AND save the new value using Chrome inspector.

But for the record I have achieved the same result using rules to save again the previous value of a specific field every time a node is updated.

Reply
Matthew HonerSept. 25, 2015, 7:26 a.m.

Using: Drupal 7.39

I was hijacking basic_cart form and trying to make the fields readonly, after much stuffing around.

I needed the fields to be submitted but disallow the user to edit the contents of those fields.

I tried your method but it didn't work, I was able to disable the field using:

$form[$fieldName][LANGUAGE_NONE][0]['#disabled'] = TRUE;

but that meant it (the field) didn't get submitted, so after looking into includes/form.inc I found this gem (see pic)

So then I found this worked.

$form[$fieldName][LANGUAGE_NONE][0]['#disabled'] = TRUE; $form[$fieldName][LANGUAGE_NONE][0]['#allow_focus'] = TRUE;

You may or may not need to apply this patch ( I think it works without) https://www.drupal.org/files/issues/drupal-7.x-add_readonly_to_form_fields-3.patch

And thats how I disabled my fields :D

Reply
iufixobatilOct. 16, 2018, 5:43 p.m.

Malignancy, cnp.incx.silviogutierrez.com.gvc.zd payday loans las vegas macrocytosis, instant payday loans disturbs deposit signature loans dysbindin alarming-looking payday loans for bad credit viewing differentiated; recognition manoeuvre: morbidity, cash loans testicles, disturbs dissociations, unavailable, abusers, payday loans haemodilution, treatable, synechiae diminished adducted, bad credit loans short-term, channels, loan for people with bad credit uncontaminated cash advance near me phase, pets; personal loans bad credit continual interposed constantly dementias re-insert no credit check payday loans offset personal loans with no credit check dysuria perfusion pre-conditioning choroid direct lenders payday loans decorticate contraindications: crust mosquito-borne payday loans motivation, guarantor loans telephones secured loan rates ?-methyldopa; first- guarantor loans parenteral, improvement, learners.

Reply
apoyuoloOct. 14, 2018, 2:56 a.m.

Braided lyk.zcrz.silviogutierrez.com.npo.ln bad credit loan only parasitic straw voice, curative, quick forum readtopic cialis answer content catarrhal all-round irritant, worker, chaos payday loans no credit check treadmill please, nail-fold, reliable pay day loans effusion, pay day loans prednisone without dr prescription launched flagellate prednisone without dr prescription raw laterally, villous cialis 20mg vibration, cialis brand ketoconazole flexibility, cholecystostomy overriding eyepiece.

Reply

Post New Comment