Unmanaged Files - Part 4

Tutorial

Part 4: Using a Twig Template to Render Unmanaged Files

In Part 3 we exposed the file handler through a Block Plugin, letting site builders drop the output into regions via the UI. That works great for flexibility, but sometimes you want tighter control: a fixed piece of markup directly in a page template, not dependent on the block system at all.

That’s where today’s approach comes in: registering a module-provided Twig template. We’ll use Drupal’s theme system (hook_theme()) to make our own template file discoverable, then hand it variables directly from the controller.

Register the template

Every template must be declared so Drupal knows about it. In our case, the unmanaged_files.module file advertises a new theme hook called unmanaged_files_test.

/**
 * Implements hook_theme().
 *
 * Registers a module-provided template so we don't need a custom theme.
 */
function unmanaged_files_theme() {
  return [
    'unmanaged_files_test' => [
      'variables' => [
        'image_url' => NULL,
        'uri' => NULL,
        'message' => NULL,
      ],
      'template' => 'unmanaged-files-test',
    ],
  ];
}

Figure 1

The controller

We update our controller to render using that new theme hook, instead of hard-coding markup in PHP.

/**
 * Renders the unmanaged files test page using the module template.
 */
public function view(): array {
  $uri = $this->handler->getRandomFile();

  if (!$uri) {
    return [
      '#theme' => 'unmanaged_files_test',
      '#message' => $this->t('No files found under public://segregated_maps'),
      '#cache' => ['max-age' => 1],
    ];
  }

  $url = $this->urlGen->generateAbsoluteString($uri);

  return [
    '#theme' => 'unmanaged_files_test',
    '#image_url' => $url,
    '#uri' => $uri,
    '#cache' => ['max-age' => 1],
  ];
}

Figure 2

The template

Finally, we drop a Twig file at modules/custom/unmanaged_files/templates/unmanaged-files-test.html.twig:

{#
/**
 * @file
 * Renders a random unmanaged file picked by the service.
 */
#}

<div class="unmanaged-files-test">
  <h2>Unmanaged files test</h2>

  {% if image_url %}
    <p>Picked: <code>{{ uri }}</code></p>
    <img src="{{ image_url }}" alt="Random unmanaged file" />
  {% else %}
    <p><em>{{ message }}</em></p>
  {% endif %}
</div>

Figure 3

Enable & test

  1. Disable the Part 3 block if you created it, to avoid duplication.
  2. Clear caches:
    ddev drush cr
  3. Visit /unmanaged-files/test and you should see your random file rendered by the Twig template.

Why this approach?

Part 3 (Block Plugin): Great when you want site builders to place output in the UI, with visibility conditions, region placement, etc.

Part 4 (Twig Template): Ideal when themers or developers want direct template control, exact markup, or when output should always appear in a specific template rather than be configurable.

Both approaches call the same service, but the integration point is different: Block vs. Theme layer. Use whichever fits your project’s editorial vs. theming needs.

In Part 5 we’ll look at a third integration: exposing the handler through a Twig function, so you can drop {{ random_unmanaged_file() }} into any template.

  • Drupal Planet