8

There is a Drupal 8 RenderElement called HtmlTag, which controls how HtmlTags are rendered. I would like to override this so that I can change its default behaviour.

I could write a class that extends HtmlTag and override what I need, but then how would Drupal core and the theme system know to use my new class?

Alternatively, maybe I should be using hook_theme_registry_alter() to tell Drupal 8 to use my new class?

I'm not really sure of the best way of achieving this and there don't seem to be any examples of this being done.

3
  • Why are you trying to override the HTML_tag element?
    – Eyal
    Apr 7, 2016 at 16:57
  • Might be to override the default void elements @Eyal
    – Clive
    Apr 7, 2016 at 17:34
  • To convert all script tags to just plain paths for use in a JSON array. This is for use in a javascript based script loader.
    – Lomax
    Apr 8, 2016 at 9:54

2 Answers 2

7

Using hook_element_info_alter() would be one option, not sure it's the best.

The existing class sets 2 pre render callbacks, which you can override in your own class:

function MYMODULE_element_info_alter(array &$types) {
  $types['html_tag']['#pre_render'] = [
    [\Drupal\mymodule\HtmlTag::class, 'preRenderConditionalComments'],
    [\Drupal\mymodule\HtmlTag::class, 'preRenderHtmlTag'],
  ];
}

...

namespace Drupal\mymodule;

use Drupal\Core\Render\Element\HtmlTag as CoreHtmlTag;

class HtmlTag extends CoreHtmlTag {

  public function preRenderHtmlTag($element) {
    // ...
  }

  public function preRenderConditionalComments($element) {
    // ...
  }

}
11
  • This is interesting. Will this lead to issues if multiple contrib modules do this?
    – Kevin
    Apr 7, 2016 at 17:45
  • There will be a race @Kevin, yep - but no more so than hooks in previous versions. It's predictable too, and we still have good 'ol hook_module_implements_alter to force an order on the hook implementations if that does happen
    – Clive
    Apr 7, 2016 at 18:57
  • I should add this doesn't feel right for other reasons @Kevin - there's a distinct possibility of violating DRY if the OP wants to, for example, just override the static $voidElements var - because the parent class uses self rather than static to reference it, the whole of preRenderHtmlTag would need to be copy-pasted across
    – Clive
    Apr 7, 2016 at 19:03
  • @Clive, is it possible to overwrite the content of $voidElements, because it is only protected not private and then call $element = parent::preRenderHtmlTag($element);?
    – 4uk4
    Apr 8, 2016 at 6:27
  • Unfortunately not @4k4 - if the parent class was referring to it with the static keyword it would work, but with it using self::$voidElements it'll always refer to the variable in core's HtmlTag, not the extending class
    – Clive
    Apr 8, 2016 at 8:33
2

If hook_element_info_alter() doesn't go far enough for you, there's a core issue to add a hook_element_plugin_alter() to directly alter the plugin class for an Element (of which RenderElements are a subset): https://www.drupal.org/project/drupal/issues/2987208

The core patch is a one-line addition of $this->alterInfo('element_plugin'); in ElementInfoManager, which specifies this new alter hook.

Then in your custom module:

function hook_element_plugin_alter(array &$definitions) {
 // Use a custom class for the HtmlTag element.
 $definitions['html_tag']['class'] = '\Drupal\mymodule\RenderElement\MyHtmlTagElement';
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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