Overview of the Theme system and Render API.
The main purpose of Drupal's Theme system is to give themes complete control over the appearance of the site, which includes the markup returned from HTTP requests and the CSS files used to style that markup. In order to ensure that a theme can completely customize the markup, module developers should avoid directly writing HTML markup for pages, blocks, and other user-visible output in their modules, and instead return structured "render arrays" (see Render arrays below). Doing this also increases usability, by ensuring that the markup used for similar functionality on different areas of the site is the same, which gives users fewer user interface patterns to learn.
For further information on the Theme and Render APIs, see:
@todo Check these links. Some are for Drupal 7, and might need updates for Drupal 8.
The core structure of the Render API is the render array, which is a hierarchical associative array containing data to be rendered and properties describing how the data should be rendered. A render array that is returned by a function to specify markup to be sent to the web browser or other services will eventually be rendered by a call to drupal_render(), which will recurse through the render array hierarchy if appropriate, making calls into the theme system to do the actual rendering. If a function or method actually needs to return rendered output rather than a render array, the best practice would be to create a render array, render it by calling drupal_render(), and return that result, rather than writing the markup directly. See the documentation of drupal_render() for more details of the rendering process.
Each level in the hierarchy of a render array (including the outermost array) has one or more array elements. Array elements whose names start with '#' are known as "properties", and the array elements with other names are "children" (constituting the next level of the hierarchy); the names of children are flexible, while property names are specific to the Render API and the particular type of data being rendered. A special case of render arrays is a form array, which specifies the form elements for an HTML form; see the Form generation topic for more information on forms.
Render arrays (at each level in the hierarchy) will usually have one of the following three properties defined:
$output['admin_filtered_string'] = array( '#markup' => '<em>This is filtered using the admin tag list</em>', ); $output['filtered_string'] = array( '#markup' => '<em>This is filtered</em>', '#allowed_tags' => ['strong'], ); $output['escaped_string'] = array( '#plain_text' => '<em>This is escaped</em>', );
Render elements are defined by Drupal core and modules. The primary way to define a render element is to create a render element plugin. There are two types of render element plugins:
See the Plugin API topic for general information on plugins. You can search for classes with the RenderElement or FormElement annotation to discover what render elements are available. API reference sites (such as https://api.drupal.org) generate lists of all existing elements from these classes. Look for the Elements link in the API Navigation block.
Modules can define render elements by defining an element plugin.
The Drupal rendering process has the ability to cache rendered output at any level in a render array hierarchy. This allows expensive calculations to be done infrequently, and speeds up page loading. See the Cache API topic for general information about the cache system.
In order to make caching possible, the following information needs to be present:
Cache information is provided in the #cache property in a render array. In this property, always supply the cache contexts, tags, and max-age if a render array varies by context, depends on some modifiable data, or depends on information that's only valid for a limited time, respectively. Cache keys should only be set on the portions of a render array that should be cached. Contexts are automatically replaced with the value for the current request (e.g. the current language) and combined with the keys to form a cache ID. The cache contexts, tags, and max-age will be propagated up the render array hierarchy to determine cacheability for containing render array sections.
Here's an example of what a #cache property might contain:
'#cache' => [ 'keys' => ['entity_view', 'node', $node->id()], 'contexts' => ['languages'], 'tags' => ['node:' . $node->id()], 'max-age' => Cache::PERMANENT, ],
At the response level, you'll see X-Drupal-Cache-Contexts and X-Drupal-Cache-Tags headers.
See https://www.drupal.org/developing/api/8/render/arrays/cacheability for details.
The #attached property can also be used to specify HTTP headers and the response status code.
$build['#attached']['library'] = 'core/jquery'; $build['#attached']['drupalSettings']['foo'] = 'bar'; $build['#attached']['feed'] = [$url, $this->t('Feed title')];
See \Drupal\Core\Render\AttachmentsResponseProcessorInterface for additional information.
See \Drupal\Core\Asset\LibraryDiscoveryParser::parseLibraryInfo() for more information on how to define libraries.
Render arrays have a placeholder mechanism, which can be used to add data into the render array late in the rendering process. This works in a similar manner to \Drupal\Component\Render\FormattableMarkup::placeholderFormat(), with the text that ends up in the #markup property of the element at the end of the rendering process getting substitutions from placeholders that are stored in the 'placeholders' element of the #attached property.
For example, after the rest of the rendering process was done, if your render array contained:
$build['my_element'] = [ '#attached' => ['placeholders' => ['@foo' => 'replacement']], '#markup' => ['Something about @foo'], ];
then #markup would end up containing 'Something about replacement'.
Note that each placeholder value can itself be a render array, which will be rendered, and any cache tags generated during rendering will be added to the cache tags for the markup.
The term "render pipeline" refers to the process Drupal uses to take information provided by modules and render it into a response. See https://www.drupal.org/developing/api/8/render for more details on this process. For background on routing concepts, see Routing API.
There are in fact multiple render pipelines:
Routes whose controllers return a \Symfony\Component\HttpFoundation\Response object are fully handled by the Symfony render pipeline.
Routes whose controllers return the "main content" as a render array can be requested in multiple formats (HTML, JSON, etc.) and/or in a "decorated" manner, as described above.
|Element||core/lib/Drupal/Core/Render/Element.php||Provides helper methods for Drupal render elements.|
|FormElement||core/lib/Drupal/Core/Render/Annotation/FormElement.php||Defines a form element plugin annotation object.|
|FormElement||core/lib/Drupal/Core/Render/Element/FormElement.php||Provides a base class for form element plugins.|
|RenderElement||core/lib/Drupal/Core/Render/Annotation/RenderElement.php||Defines a render element plugin annotation object.|
|RenderElement||core/lib/Drupal/Core/Render/Element/RenderElement.php||Provides a base class for render element plugins.|
|ElementInterface||core/lib/Drupal/Core/Render/Element/ElementInterface.php||Provides an interface for render element plugins.|
|FormElementInterface||core/lib/Drupal/Core/Render/Element/FormElementInterface.php||Provides an interface for form element plugins.|
© 2001–2016 by the original authors
Licensed under the GNU General Public License, version 2 and later.
Drupal is a registered trademark of Dries Buytaert.