0

In a hook_entity_postsave() function in my custom D7 module, I'm doing the following when a node is saved:

$_ = node_view($entity, 'full');   
$html = drupal_render($_);         

But the renderd HTML seems to miss the active theme's templates. e.g. turning on theme debug, I get

 FILE NAME SUGGESTIONS:
   * paragraphs-items--field-sections--full.tpl.php
   * paragraphs-items--field-sections.tpl.php
   x paragraphs-items.tpl.php

Yet paragraphs-items--field-sections--full.tpl.php is defined in the site's active theme (and is used correctly on presentation of normal node pages).

EDIT: I think this may be because the admin theme is active when this code runs? Is there a way to switch that?

1 Answer 1

1

It is definitely because your admin theme is active when you do the render.

There is no straight-forward and easy way to switch the theme in the middle of a request and you will likely run into further problems.

I would consider other options, e.g. creating the nodes markup via a menu callback that uses the frontend theme, either directly in your hook_entity_postsave or in a cron job for example.

If you still want to try it by switching themes, this is the way it worked for my now after a bit of tinkering with the code from https://stackoverflow.com/a/56358189/368479 and borrowing code from drupal_theme_initialize(). The most notable change is the clearing of the cache at the end of the switch function. Performance-wise this is awful, but I couldn't make it work without it.

/**
 * Switch to or from an alternative theme in the middle of a request.
 *
 * This is useful if you need to render something (like a node) in a different
 * theme without changing the theme of the entire page. An example use case is
 * when you need to render something for a front end user from an admin page.
 *
 * Usage example:
 *     my_module_switch_theme('bartik');
 *     $node = node_load(1);
 *     $renderable = node_view($node);
 *     $rendered = render($renderable);
 *     my_module_switch_theme();
 *
 * @param string|null $to
 *   The name of the theme to switch to. If NULL, it switches back to the
 *   original theme.
 */
function my_module_switch_theme(string $to = NULL) {
  global $theme, $theme_key;

  // Backup the original theme.
  static $original_theme;
  if (empty($original_theme)) {
    $original_theme = $theme;
  }

  // Perform the switch.
  $theme = $to ?? $original_theme;
  $theme_key = $theme;

  // Find all our ancestor themes and put them in an array.
  $themes = list_themes();
  $base_theme = array();
  $ancestor = $theme;
  while ($ancestor && isset($themes[$ancestor]->base_theme)) {
    $ancestor = $themes[$ancestor]->base_theme;
    $base_theme[] = $themes[$ancestor];
  }
  _drupal_theme_initialize($themes[$theme], array_reverse($base_theme));

  // Themes can have alter functions, so reset the drupal_alter() cache.
  drupal_static_reset('drupal_alter');

  // Clear the cache.
  drupal_flush_all_caches();
}

Note that this might not work if you implement hook_custom_theme for the page where the action happens, but if you use the admin theme then I guess that is not the case.

The code above can then be used like in the following example and correctly uses the node.tpl.php from the bartik theme instead of the one that the current theme uses, at least in my test setup.

my_module_switch_theme('bartik');
$node = node_load(1);
$renderable = node_view($node);
$rendered = render($renderable);
my_module_switch_theme();
3
  • Thanks, I tried this but it doesn't work. I've also tried the fuller version at stackoverflow.com/a/20476484/623519 too. It's just not picking up the templates from the theme :-( Commented Nov 6, 2021 at 9:03
  • 1
    @artfulrobot You are right. Also there is no global $custom_theme variable. I was mislead by something I saw and didn't verify. I have updated my answer now. I would strongly suggest to do the rendering at a later point if that is possible. Switching the themes during the active request will easily lead to trouble.
    – berliner
    Commented Nov 6, 2021 at 19:40
  • 1
    Thanks! it works! I have found a peformance gain: replace drupal_flush_all_caches() with system_rebuild_theme_data();drupal_theme_rebuild(); Commented Nov 7, 2021 at 7:39

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.