I see (with grep) that the value of $element['#title'] in a render element is sometimes sanitized with check_plain(), and sometimes printed unfiltered.

Which one is correct? Is the value considered safe to print? Or does it depend on the theme hook?

Examples from core:

314:        'data' => '<label>' . t('!title !required', array('!title' => $element['#title'], '!required' => $required)) . "</label>",

(notice the "!" in the placeholder, this means that format_string() will not escape the placeholder value)

1052:  $variables['label'] = $variables['label_hidden'] ? NULL : check_plain($element['#title']);

This question applies in both ways:

  • When setting $element['#title'] in a render element.
  • When printing the value of $element['#title'].
  • When printing a $variables['title'] value that was extracted from a render element property.

Note: Very often the $element['#title'] property comes directly from a t() call.


It's user input and should be considered unsafe; you should always sanitise it.

For the specific example you've given where it isn't, the title is already sanitised before it's passed to the theme function containing the t() call. This happens in field_multiple_value_form()

$title = check_plain($instance['label']);


$element = array(
  '#title' => $multiple ? '' : $title,

As an aside, if you ever did need to preserve HTML in the title for whatever reason, you could consider using filter_xss() instead.

  • <strike>You are contradicting yourself, sort of</strike>. In the given example, $title is raw user input, but $element['#title'] is not. So it seems it depends on the render element type. – donquixote Apr 27 '19 at 19:24
  • Also the distinction is not necessarily about html vs plain text, but about trusted vs non-trusted. – donquixote Apr 27 '19 at 19:27
  • Sure, I was just referring to the fact that check_plain removes HTML and not using it preserves it. If you're asking whether #title in any render array, ever, can be trusted then yes the answer is definitely "it depends", because render array properties are arbitrary, and what a #title is to a form element isn't necessarily the same thing as it is to a different type of element. I assumed you were asking about the field module specifically because of the examples. It's been a long child-filled day so I might also be missing something about what you're asking ;) – Clive Apr 27 '19 at 19:30
  • 1
    Hmm, having re-read I think maybe i am contradicting myself here after all. You're absolutely right, if it was the same #title it wouldn't need to be escaped again. Will try to have a deeper look a bit later – Clive Apr 27 '19 at 19:48

The correct way is to check with check_plain() to prevent cross site scripting attacks in the first example from modules/field/field.form.inc $element['#title'] passed as arg to t function.
if you look at t function source code it call format_string function it check plain $args[$key] = check_plain($value);.

  • 1
    Actually no, in the first example the placeholder is "!title" with "!", which means no escaping will happen in format_string(). – donquixote Apr 27 '19 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.