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()
    $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.

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

1 Answer 1


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:


    class: Drupal\MYMODULE\Theme\ThemeNegotiator
      - { name: theme_negotiator, priority: -20 }

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



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 and acknowledge you have read our privacy policy.

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