7

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.

  • Why are you trying to override the HTML_tag element? – Eyal Apr 7 '16 at 16:57
  • Might be to override the default void elements @Eyal – Clive Apr 7 '16 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 '16 at 9:54
6

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) {
    // ...
  }

}
  • This is interesting. Will this lead to issues if multiple contrib modules do this? – Kevin Apr 7 '16 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 '16 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 '16 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);? – 4k4 Apr 8 '16 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 '16 at 8:33
0

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, privacy policy and cookie policy

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