Lauri Eskola (lauriii)
Front end track | Twitter: @laurii1
Front end track | Twitter: @laurii1
Provides flexible way to output safe HTML
Laziness is the first step towards efficiency.
<?php
function template_process_html(&$variables) {
// Render page_top and page_bottom into top level variables.
$variables['page_top'] = drupal_render($variables['page']['page_top']);
$variables['page_bottom'] = drupal_render($variables['page']['page_bottom']);
// Place the rendered HTML for the page body into a top level variable.
$variables['page'] = $variables['page']['#children'];
$variables['page_bottom'] .= drupal_get_js('footer');
$variables['head'] = drupal_get_html_head();
$variables['css'] = drupal_add_css();
$variables['styles'] = drupal_get_css();
$variables['scripts'] = drupal_get_js();
}
Wastes resources if something doesn't get printed
Drupal 8
<?php
$variables['list'] = theme('item_list', array(
'items' => $items,
));
Drupal 7
<?php
$variables['list'] = [
'#theme' => 'item_list',
'#items' => $items,
];
<php
function theme_item_list($variables) {
$items = $variables['items'];
$title = $variables['title'];
$type = $variables['type'];
$attributes = $variables['attributes'];
// Only output the list container and title, if there are any list items.
// Check to see whether the block title exists before adding a header.
// Empty headers are not semantic and present accessibility challenges.
$output = '<div class="item-list">';
if (isset($title) && $title !== '') {
$output .= '<h3>' . $title . '</h3>';
}
if (!empty($items)) {
$output .= "<$type" . drupal_attributes($attributes) . '>';
$num_items = count($items);
$i = 0;
foreach ($items as $item) {
$attributes = array();
$children = array();
$data = '';
$i++;
if (is_array($item)) {
foreach ($item as $key => $value) {
if ($key == 'data') {
$data = $value;
}
elseif ($key == 'children') {
$children = $value;
}
else {
$attributes[$key] = $value;
}
}
}
else {
$data = $item;
}
if (count($children) > 0) {
// Render nested list.
$data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes));
}
if ($i == 1) {
$attributes['class'][] = 'first';
}
if ($i == $num_items) {
$attributes['class'][] = 'last';
}
$output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n";
}
$output .= "</$type>";
}
$output .= '</div>';
return $output;
}
{%- if items or empty -%}
<div class="item-list">
{%- if title is not empty -%}
<h3>{{ title }}</h3>
{%- endif -%}
{%- if items -%}
<{{ list_type }}{{ attributes }}>
{%- for item in items -%}
<li{{ item.attributes }}>{{ item.value }}</li>
{%- endfor -%}
</{{ list_type }}>
{%- else -%}
{{- empty -}}
{%- endif -%}
</div>
{%- endif %}
Drupal 7 vs Drupal 8: 154 / 8
<?php
/**
* Implements hook_theme().
*/
function sandwich_theme() {
return [
'sandwich' => [
'variables' => [
'attributes' => [],
'name' => '',
'bread' => '',
'cheese' => '',
'veggies' => [],
'protein' => '',
'condiments' => [],
],
],
];
}
<?php
public function build() {
return [
'#theme' => 'sandwich',
'#name' => $this->t('Chickado'),
'#attributes' => [
'id' => 'best-sandwich',
'class' => ['menu--left', 'clearfix'],
],
'#bread' => $this->t('Sourdough'),
'#cheese' => $this->t('Gruyère'),
'#veggies' => [
$this->t('Avocado'),
$this->t('Red onion'),
],
'#protein' => $this->t('Chicken'),
'#condiments' => [
$this->t('Mayo'),
$this->t('Dijon'),
],
];
}
node.html.twig
node--article.html.twig
<?php
/**
* Implements hook_theme_suggestions_sandwich().
*/
function sandwich_theme_suggestions_sandwich($variables) {
return 'sandwich__' . strtolower($variables['name']);
}
/**
* Implements hook_theme_suggestions_sandwich_alter().
*/
function sandwich_theme_suggestions_sandwich_alter(&$suggestions, $variables) {
}
<?php
/**
* Implements template_preprocess_sandwich().
*/
function template_preprocess_sandwich(&$variables) {
$variables['name'] = 'Kitten';
}
/**
* Implements hook_preprocess_sandwich().
*/
function sandwich_preprocess_sandwich(&$variables) {
$variables['name'] = 'Llama';
}
/**
* Implements hook_preprocess_sandwich__chickado().
*/
function sandwich_preprocess_sandwich__chickado(&$variables) {
$variables['name'] = 'Flamingo';
}
<?php
/**
* Implements template_preprocess_sandwich().
*/
function template_preprocess_sandwich(&$variables) {
$variables['name'] = t('Kitten');
if (!empty($variables['name']['#machine_name'])) {
$variables['name'] = $variables['name']['#machine_name'];
}
}
<section{{ attributes }}>
<h2>{{ name }}</h2>
{% if bread %}
<p><strong>Bread:</strong> {{ bread }}</p>
{% endif %}
{% if protein %}
<p><strong>Protein:</strong> {{ protein }}</p>
{% endif %}
{% if cheese %}
<p><strong>Cheese:</strong> {{ cheese }}</p>
{% endif %}
{% if veggies %}
<strong>Veggies:</strong>
<ul>
{% for veg in veggies %}
<li>{{ veg }}</li>
{% endfor %}
</ul>
{% endif %}
{% if condiments %}
<strong>Accoutrement:</strong>
<ul>
{% for condiment in condiments %}
<li>{{ condiment }}</li>
{% endfor %}
</ul>
{% endif %}
</section>
{{ sandwich.cheese }}
// Array key.
$sandwich['cheese'];
// Object property.
$sandwich->cheese;
// Also works for magic get (provided you implement magic isset).
$sandwich->__isset('cheese'); && $sandwich->__get('cheese');
// Object method.
$sandwich->cheese();
// Object get method convention.
$sandwich->getCheese();
// Object is method convention.
$sandwich->isCheese();
// Method doesn't exist/dynamic method.
$sandwich->__call('cheese');
Meant to manipulate a variable. Takes the first parameter from the variable before "|".
{% set name = 'Lauri' %}
{# Print varibale using lenght filter. #}
{{ name|length }}
Example
Returns
5
Functions with more logic and multiple parameters meant to create simple front-end logic
{{ dump() }}
Example
{# We give you what you ask for. #}
{{ content|without('comments', 'links') }}
Drupal 7
Drupal 8
<?php
// We hide the comments and links now so that we can render them later.
hide($content['comments']);
hide($content['links']);
print render($content);
How to create a Twig extension
<?php
/**
* A class providing my own Twig extension.
*/
class TrimString extends \Twig_Extension {
/**
* {@inheritdoc}
*/
public function getFilters() {
return [
new \Twig_SimpleFilter('trim_string', [$this, 'trimString']),
];
}
public function trimString($string, $length = 10) {
return substr($string, 0, $length);
}
}
services:
trim_string.twig.trimstring:
class: Drupal\trim_string\TwigExtension\TrimString
tags:
- { name: twig.extension }
trim_string.services.yml
{% set variable = 'my text' %}
{{ variable|trim_string(2) }}
my
Returns
https://github.com/lauriii/trim-string
<?php
use Drupal\Component\Utility\Html
print Html::escape('Some escaped <em>text</em>');
Prints markup
Some escaped <em>text</em>
Some escaped <em>text</em>
{{ markup }}
Prints markup
Some escaped <em>text</em>
Some escaped <em>text</em>
<?php
function sandwich_preprocess_sandwich(&$variables) {
$variables['markup'] = '<em>text</em>';
}
{{ markup }}
Prints markup
Some escaped <em>text</em>
Some escaped text
<?php
function sandwich_preprocess_sandwich(&$variables) {
$variables['markup']['#markup'] = '<em>text</em>';
}
{{ markup }}
Prints markup
Some escaped <em>text</em>
Some escaped text
<?php
use Drupal\Component\Utility\SafeMarkup;
function sandwich_preprocess_sandwich(&$variables) {
$variables['markup'] = SafeMarkup::format('<em>@txt</em>', ['@txt' => 'text']);
}
<?php
use Drupal\Component\Utility\SafeMarkup;
SafeMarkup::format('<em@txt></em>', ['@txt' => 'text']);
SafeMarkup::format('<a href="@url"></a>', ['@url' => 'http://kittens.com']);
SafeMarkup::format('<a href="@url"></a>', ['@url' => 'javascript:alter(0)']);
<?php
use Drupal\Component\Utility\SafeMarkup;
SafeMarkup::format('<a href=":url"></a>', [':url' => 'javascript:alter(0)']);
Which means using PHP Template or Theme functions is not safe by default
Sprint with the Community on Friday.
We have tasks for every skillset.
Mentors are available for new contributors.
An optional Friday morning workshop for first-time sprinters will help you get set up.
Follow @drupalmentoring.
https://www.flickr.com/photos/amazeelabs/9965814443/in/faves-38914559@N03/
Front end track | Twitter: @laurii1