How to disable individual fields in the node edit screen

Consider this problem: you want to disable a few fields on the node edit screen for particular node types. Let’s say the body, although this could apply to any and all fields. The reason for this is that for our client’s e-commerce system, the products are synched from an external POS system, and most fields should not be touched AT ALL… and certainly shouldn’t be overwritten with content copy-pasted from MS Word, which has happened a few times and prompted us to take preventative measures.

Consider this problem: you want to disable a few fields on the node edit screen for particular node types. Let’s say the body, although this could apply to any and all fields. The reason for this is that for our client’s e-commerce system, the products are synched from an external POS system, and most fields should not be touched AT ALL… and certainly shouldn’t be overwritten with content copy-pasted from MS Word, which has happened a few times and prompted us to take preventative measures.

I should clarify that at least one field (images) does still need to be editable, which is why we’re not just taking away edit permissions altogether.

Okay, so I’m not saying what follows is the best solution, just what I came up with, inspired by a Stack Overflow thread I can’t seem to find right now. It uses hook_form_alter() to (a) hide the body edit field group, and (b) replace it with static markup displaying the body content. I thought about replacing it with a disabled textarea, but in Firefox, for instance that’ll show up with a medium grey background that really doesn’t look very good.

$CONTENT_TYPE = 'product'; 
function MODULE_form_alter(&$form, $form_state, $form_id) {
  if(isset($form['#node']) && $form_id == $CONTENT_TYPE . '_node_form') {
    $form['displaybody'] = array(
      '#value' => '' . $form['body_field']['body']['#title'] . ':
' . $form['body_field']['body']['#default_value'] . '
', '#weight' => $form['body_field']['#weight'], ); $form['body_field']['#access'] = FALSE; } }

A few notes:

Line 3: I’m not really sure what the first condition is for. At first I thought it was to cover only editing existing nodes, but that doesn’t appear to be the case. The second condition is to cover only certain node types

Lines 4–10: we insert a new form element, ‘display body’. It will show the body field label and content, and will be have the same weight as the existing body field, so it shows up in the same position on the screen.

Line 11: This hides the body field, unconditionally.

But what if we wanted to allow some users to edit that field? That’s certainly doable, but it gets a bit awkward. I could use hook_perm() to create a special permission—call it ‘edit body’—and replace line 3 above with:

if(isset($form['#node']) && $form_id == $CONTENT_TYPE . '_node_form' && !user_access('edit body')) {

However, that permission would show up in my own module’s section, not with the other uc_product permissions, so that’s a bit annoying. I could hack uc_product.module, but that’s not really a good solution. If there were a way to add to a third party module’s permissions, that would be very awesome!