'image', * '#attributes' => array('class' => array('foo')), * '#theme_wrappers' => array('container'), * ); * @endcode * and we need to pass the class 'bar' as an attribute for 'container', we * can rewrite our element thus: * @code * array( * '#theme' => 'image', * '#attributes' => array('class' => array('foo')), * '#theme_wrappers' => array( * 'container' => array( * '#attributes' => array('class' => array('bar')), * ), * ), * ); * @endcode * - If this element has an array of #post_render functions defined, they * are called sequentially to modify the rendered #children. Unlike * #pre_render functions, #post_render functions are passed both the * rendered #children attribute as a string and the element itself. * - If this element has #prefix and/or #suffix defined, they are * concatenated to #children. * - The rendering of this element is now complete. The next step will be * render caching. So this is the perfect time to update the the stack. At * this point, children of this element (if any), have been rendered also, * and if there were any, their bubbleable rendering metadata will have * been bubbled up into the stack frame for the element that is currently * being rendered. The render cache item for this element must contain the * bubbleable rendering metadata for this element and all of its children. * However, right now, the topmost stack frame (the one for this element) * currently only contains the metadata for the children. Therefore, the * topmost stack frame is updated with this element's metadata, and then * the element's metadata is replaced with the metadata in the topmost * stack frame. This element now contains all bubbleable rendering * metadata for this element and all its children, so it's now ready for * render caching. * - If this element has #cache defined, the rendered output of this element * is saved to Renderer::render()'s internal cache. This includes the * changes made by #post_render. * - If this element has an array of #post_render_cache functions defined, * or any of its children has (which we would know thanks to the stack * having been updated just before the render caching step), they are * called sequentially to replace placeholders in the final #markup and * extend #attached. Placeholders must contain a unique token, to * guarantee that e.g. samples of placeholders are not replaced also. But, * since #post_render_cache callbacks add attach additional assets, the * correct bubbling of those must once again be taken into account. This * final stage of rendering should be considered as if it were the parent * of the current element, because it takes that as its input, and then * alters its #markup. Hence, just before calling the #post_render_cache * callbacks, a new empty frame is pushed onto the stack, where all assets * #attached during the execution of those callbacks will end up in. Then, * after the execution of those callbacks, we merge that back into the * element. Note that these callbacks run always: when hitting the render * cache, when missing, or when render caching is not used at all. This is * done to allow any Drupal module to customize other render arrays * without breaking the render cache if it is enabled, and to not require * it to use other logic when render caching is disabled. * - Just before finishing the rendering of this element, this element's * stack frame (the topmost one) is bubbled: the two topmost frames are * popped from the stack, they are merged and the result is pushed back * onto the stack. * So if this element e.g. was a child element, then a new frame was * pushed onto the stack element at the beginning of rendering this * element, it was updated when the rendering was completed, and now we * merge it with the frame for the parent, so that the parent now has the * bubbleable rendering metadata for its child. * - #printed is set to TRUE for this element to ensure that it is only * rendered once. * - The final value of #children for this element is returned as the * rendered output. * * @param array $elements * The structured array describing the data to be rendered. * @param bool $is_root_call * (Internal use only.) Whether this is a recursive call or not. See * ::renderRoot(). * * @return string * The rendered HTML. * * @throws \LogicException * If a root call to ::render() does not result in an empty stack, this * indicates an erroneous ::render() root call (a root call within a * root call, which makes no sense). Therefore, a logic exception is thrown. * @throws \Exception * If a #pre_render callback throws an exception, it is caught to reset the * stack used for bubbling rendering metadata, and then the exception is re- * thrown. * * @see \Drupal\Core\Render\ElementInfoManagerInterface::getInfo() * @see \Drupal\Core\Theme\ThemeManagerInterface::render() * @see drupal_process_states() * @see drupal_process_attached() * @see ::renderRoot() */ public function render(&$elements, $is_root_call = FALSE); /** * Gets a cacheable render array for a render array and its rendered output. * * Given a render array and its rendered output (HTML string), return an array * data structure that allows the render array and its associated metadata to * be cached reliably (and is serialization-safe). * * If Drupal needs additional rendering metadata to be cached at some point, * consumers of this method will continue to work. Those who only cache * certain parts of a render array will cease to work. * * @param array $elements * A renderable array, on which ::render() has already been invoked. * * @return array * An array representing the cacheable data for this render array. */ public function getCacheableRenderArray(array $elements); /** * Merges the bubbleable rendering metadata o/t 2nd render array with the 1st. * * @param array $a * A render array. * @param array $b * A render array. * * @return array * The first render array, modified to also contain the bubbleable rendering * metadata of the second render array. * * @see \Drupal\Core\Render\BubbleableMetadata */ public static function mergeBubbleableMetadata(array $a, array $b); }