You are here

HTML Encoding in Drupal Entity References

Corey Pennycuff's picture
double-escape.png
Double Encoding Issue

Building complex websites with Drupal will undoubtedly require you to use the Entity Reference module. Overall, this is a great module with a lot of power and flexibility. It does have one fault, however, and that is that Entity titles are double-encoded when being shown in select boxes, as you can see here. This is nothing more than a small annoyance for experienced users, but show this to a customer and they will swear that something is broken!

As it turns out, this is a known problem, and at the time of this writing no general solution has been developed, due to issues beyond the scope of this short blog post. I'm just going to tell you how to fix it for yourself! All that is needed is a simple hook_form_alter() that will cycle through the options and remove the extra encoding, as demonstrated here in our ficticious misc module.

The Code

function misc_form_alter(&$form, &$form_state, $form_id) {
  $to_fix = array('field_reference');
  foreach($to_fix as $fix) {
    if (isset($form[$fix]) && isset($form[$fix][$form[$fix]['#language']]['#options'])) {
      foreach($form[$fix][$form[$fix]['#language']]['#options'] as &$text) {
        $text = decode_entities($text);
      }
    }
  }
}
single-escape.png
Double Encoding Fixed

In this example, we are correcting a field named field_reference, but you can replace this with the name of any field that you have. You can also add as many additional fields to the array() declaration as you need. The result is clearly demonstrated in the picture, and the benefit to users in readability and less confusion is worth its proverbial weight in gold.

Explanation

Even though Drupal 7 allows us to have targeted form_alter()'s, I prefer to have a single location for this type of code. It is fast and will add almost no overhead to your form creation. It is also useful if you reuse fields in different entity types, as this single instance will catch all of those instances without requiring any additional codeing from you. For each field name in the array, we simply loop through its options and run the option text through decode_entities().

Caveat

If you use this method, there are a few things you should watch out for. If, in the future, this defect is fixed, then you may need to remove the code, else there could be a security issue. Also, this code only works for fields in the first level of the form. If you have fields buried deeper in the form array, then you need to account for that added depth in the code. Other than these two points, this method is safe, and has been useful in quite a number of projects.

Tags: 

4 Comments

Peter's picture

Rather than whitelisting, you

Rather than whitelisting, you can try to detect EntityReference select widgets and fix all of them:

function misc_form_alter(&$form, &$form_state, $form_id) {
  foreach ($form as $key => &$field) {
    if (is_array($field) && isset($field['#attributes']) && isset($field['#attributes']['class'])) {
          $attr = $field['#attributes']['class'];
          if (in_array('field-type-entityreference', $attr) && in_array('field-widget-options-select', $attr)) {
            foreach ($field[$field['#language']]['#options'] as &$label) {
                  $label = decode_entities($label);
                }
          }
        }
  }
}
Missing_Linke's picture

What I've been looking for, but need a little help

I've been looking for a solution to this problem for weeks now, thank you so much for posting this. I did run into one issue though, it seems when my entity reference spans multiple types, I get an error:
Warning: html_entity_decode() expects parameter 1 to be string, array given in decode_entities()
for each type I have in the view. For example, If my view contains Pages, Articles & Blogs, I'll get that error 3 times.

I don't suppose you know anyway around this particular issue? I've been working at it for a couple hours and can't seem to figure it out.

Thank you in advance for your help!

Corey Pennycuff's picture

Hmm... I'm not sure without

Hmm... I'm not sure without seeing the code/data involved. Your data structure may be different if the form element has been moved (e.g., it was put into a frameset, for example). I suggest examining the array structure using dsm() from the Devel module.