2

When rendering HTML in hook_node_presave(), everything works as expected when I save the node manually.

However, when I use the "Save content" action on the content admin view (at /admin/content), then the page is rendered with the admin theme templates (Seven), instead of the templates of my custom theme/the site theme.

I tried using both Claro and Seven as the admin theme, and I get the same result: I can save the page manually and the site theme's templates are used, but if I use the "Save content" action to bulk re-save nodes, they are rendered incorrectly with the admin theme templates.

Here's the code that is causing the issue:

function MYMODULE_node_presave(NodeInterface $node) {
  $content_type = $node->getType();
  if ($content_type == 'page') {
    // Render the entire node and save that HTML to a specific field.
    $render_controller = \Drupal::entityTypeManager()
      ->getViewBuilder($node->getEntityTypeId());
    $render_output = $render_controller->view($node, 'mymarkup_torender', 'ja');
    $html = \Drupal::service('renderer')->renderPlain($render_output);
    $node->set('field_text_cached_html', $html);
    $node->field_text_cached_html->format = 'mymarkup_processed';
  }

Is there a way to force Drupal to use the site theme instead of the admin theme when rendering?

On the Appearance administration page, "Use the administration theme when editing or creating content" is unchecked.

2
  • 1
    Did you try using theme negotiator to set active theme for this case?
    – MrD
    Dec 21 '20 at 6:12
  • @MrD Thanks, that did the trick! Dec 21 '20 at 13:14
2

Based on the comment by @MrD, I found a working solution.

I implemented a custom theme negotiator based on this information:

I needed to change the theme for the admin content page, so here is the code I used:

mymodule.services.yml

  MYMODULE.theme.negotiator:
    class: Drupal\MYMODULE\Theme\ThemeNegotiator
    tags:
      - { name: theme_negotiator, priority: -20 }

Here, I used a low priority to ensure my code runs first.

MYMODULE/src/Theme/ThemeNegotiator.php

<?php

namespace Drupal\MYMODULE\Theme;

use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Theme\ThemeNegotiatorInterface;

/**
 * Select the correct theme for various routes.
 */
class ThemeNegotiator implements ThemeNegotiatorInterface {

  /**
   * {@inheritDoc}
   */
  public function applies(RouteMatchInterface $route_match) {
    return $this->negotiateRoute($route_match) ? TRUE : FALSE;
  }

  /**
   * {@inheritDoc}
   */
  public function determineActiveTheme(RouteMatchInterface $route_match) {
    return $this->negotiateRoute($route_match) ?: NULL;
  }

  /**
   * Select the theme for special cases.
   *
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The currently matched route.
   *
   * @return bool|string
   *   The theme name to use (string) or false (bool).
   */
  private function negotiateRoute(RouteMatchInterface $route_match) {
    $route_name = $route_match->getRouteName();
    if ($route_name === 'system.admin_content') {
      return 'MYTHEMENAME';
    }
    else {
      return FALSE;
    }
  }

}

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.