Drupal 8 Certification Study Guide
Notes based on the Acquia Certified Drupal 8 Developer Study Guide and other resources.
For the record, I officially passed my exam on 4/24/2017 at DrupalCon Baltimore.
Feel free to open PRs, adding new info and correcting any mistakes you may find.
It is highly recommended that you also read the Drupal 8 User Guide as much of the site building section (including the missing notes in this repo) covers what is in the user guide.
Update: 4/2/2018: I'm presently studying for both the Front End Specialist and Back End Specialist exams and have started updating the documentation to go a bit more in depth on certain topics. The material is all still relevant for the general developer exam, but may be a little more detailed than you need. Either way, I feel like it's important information to know regardless of whether or not it is asked on the certification exam.
Update: 4/9/2018: I've successfully completed both the front end and back end exams. As to avoid giving anything specific away, I will say this study guide does have pretty decent coverage for both, but there are a few things missing.
On the front end, it's a bit important to familiarize yourself with some of the newer aspects of HTML5 if you came from a XHTML background. I'll also say just knowing about the breakpoint module isn't enough from a performance perspective. Also, it helps to know some of the more advanced features in Twig, even if you don't use them every day. I highly recommend reading The Drupal 8 Theming Guide. It is a rather helpful resource and definitely proved to be beneficial to me.
On the backend, the best thing you can do is just build a module or two. We could add all kinds of things to the study guide, but nothing beats actual experience here. I'd also emphasize knowing the differences between plugins and services, and different ways you might validate and sanitize user input in a variety of contexts.
This study guide used in tandem with the 'Drupal 8 Certification Crash Course':
Presentation Slides: https://docs.google.com/presentation/d/1EJ1xMnnfd1Sdg8bNb08scNnOzramPlP_II5WtEPlrgk/edit?usp=sharing
PRs Welcome!
Disclaimer: This is not officially related to the Acquia certification process. These notes are just based on what I thought was important while I studied. Your results may vary.
- 2.1 - Content Types
- 2.2 - Display Modes
- 2.3 - Taxonomies
- 2.4 - Blocks
- 2.5 - Menus
- 2.6 - Views
- 2.7 - Configuration Management
- 2.8 - Multilingual
- 2.9 - Web Services
- 3.1 - Creating Themes and Subthemes
- 3.2 - Theming Concepts
- 3.3 - Twig Syntax
- 3.4 - Overriding Twig Templates
- 3.5 - Preprocessors
- 4.1 - Object-Oriented Programming
- 4.2 - Custom Modules
- 4.3 - Data Storage
- 4.4 - Essential APIs
- 4.5 - Coding Standards
- 4.6 - Performance
- 4.7 - Security
Fundamental Web Development Concepts
HTML/CSS
HTML/CSS is a very large subject matter, and the presumption is that you understand at least the bare essentials to take the certification exam, and there are plenty of places to learn HTML/CSS online. As such the notes for this section only cover some specific topics.
HTML5 Tags
| Tag | Description |
|---|---|
<article> | Defines an article |
<aside> | Defines content aside from the page content |
<details> | Defines additional details that the user can view or hide |
<figcaption> | Defines a caption for a <figure> element |
<figure> | Specifies self-contained content, like illustrations, diagrams, photos, code listings, etc. |
<footer> | Defines a footer for a document or section |
<header> | Specifies a header for a document or section |
<main> | Specifies the main content of a document |
<mark> | Defines marked/highlighted text |
<nav> | Defines navigation links |
<section> | Defines a section in a document |
<summary> | Defines a visible heading for a <details> element |
<time> | Defines a date/time |
CSS Specificity
A selector's specificity is calculated as follows:count the number of ID selectors in the selector (= a) count the number of class selectors, attributes selectors, and pseudo-classes in the selector (= b) count the number of type selectors and pseudo-elements in the selector (= c) ignore the universal selector Selectors inside the negation pseudo-class are counted like any other, but the negation itself does not count as a pseudo-class.Concatenating the three numbers a-b-c (in a number system with a large base) gives the specificity.
Examples:
* /* a=0 b=0 c=0 -> specificity = 0 */
LI /* a=0 b=0 c=1 -> specificity = 1 */
UL LI /* a=0 b=0 c=2 -> specificity = 2 */
UL OL+LI /* a=0 b=0 c=3 -> specificity = 3 */
H1 + *[REL=up] /* a=0 b=1 c=1 -> specificity = 11 */
UL OL LI.red /* a=0 b=1 c=3 -> specificity = 13 */
LI.red.level /* a=0 b=2 c=1 -> specificity = 21 */
#x34y /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO) /* a=1 b=0 c=1 -> specificity = 101 */
!important
When an important rule is used on a style declaration, this declaration overrides any other declarations. Although technically !important has nothing to do with specificity, it interacts directly with it. Using !important, however, is bad practice and should be avoided because it makes debugging more difficult by breaking the natural cascading in your stylesheets. When two conflicting declarations with the !important rule are applied to the same element, the declaration with a greater specificity will be applied.Some rules of thumb:
- Always look for a way to use specificity before even considering !important
- Only use !important on page-specific CSS that overrides foreign CSS (from external libraries, like Bootstrap or normalize.css).
- Never use !important when you're writing a plugin/mashup.
- Never use !important on site-wide CSS.
CSS Source Order
If multiple competing selectors have the same importance and specificity, the third factor that comes into play to help decide which rule wins is source order — later rules will win over earlier rules.
CSS Combinators
Using one selector at a time is useful, but can be inefficient in some situations. CSS selectors become even more useful when you start combining them to perform fine-grained selections. CSS has several ways to select elements based on how they are related to one another. Those relationships are expressed with combinators as follows (A and B represent any selector seen above):
| Name | Syntax | Selects |
|---|---|---|
| Group of selectors | A, B | Any element matching A and/or B (see Group of selectors on one rule, below - Group of Selectors is not considered to be a combinator). |
| Descendant selector | A B | Any element matching B that is a descendant of an element matching A (that is, a child, or a child of a child, etc.). |
| Child selector | A > B | Any element matching B that is a direct child of an element matching A. |
| Adjacent sibling selector | A + B | Any element matching B that is the next sibling of an element matching A (that is, the next child of the same parent). |
| General sibling selector | A ~ B | Any element matching B that is one of the next siblings of an element matching A (that is, one of the next children of the same parent). |
Javascript/jQuery
Javascript is a very large subject matter, and the presumption is that you understand at least the bare essentials to take the certification exam, and there are plenty of places to learn Javascript online. As such the notes for this section will just cover Drupal-related Javascript topics.
One change from Drupal 7 to Drupal 8, is that jQuery is no longer automatically loaded. This means jQuery must be manually pulled in as a dependency. There are examples of that below.
Adding Javascript Libraries
Theme and module Javascript should be loaded in using asset libraries (i.e.
*.libraries.yml files where * is the name of the theme or module).Local Javascript Libraries
Suppose you have a theme named
mytheme, which needs to include the following Javascript files:fancy-ui-tabs.js
fancy-ui-accordion.js
fancy-ui-tables.js (dependent on underscore and jQuery)
It would follow that you would create
mytheme.libraries.yml with the following contents:fancy-ui:
version: 1.x
js:
js/fancy-tabs.js: {}
js/fancy-accordion.js: {}
fancy-ui-tables:
version: 1.x
js:
js/fancy-tables.js: {}
dependencies:
- core/underscore
- core/jquery
External Javascript Libraries
Though it can be problematic for performance and security reasons, there are times when you will need to load external Javascript into your site.
For example loading AngularJS via a CDN, from Adding stylesheets (CSS) and JavaScript (JS) to a Drupal 8 theme:
angular.angularjs:
remote: https://github.com/angular
version: 1.4.4
license:
name: MIT
url: https://github.com/angular/angular.js/blob/master/LICENSE
gpl-compatible: true
js:
https://ajax.googleapis.com/ajax/libs/angularjs/1.4.4/angular.min.js: { type: external, minified: true }
Attaching Javascript
Once libraries have been defined, they need to be attached where they are needed.
Attaching to All Pages
To attach Javascript to all pages:
Under the
libraries: section of mytheme.info.yml:libraries:
- 'mytheme/global-styling'
- 'mytheme/bootstrap-scripts'
- 'mytheme/fancy-ui'
Attaching to a Subset of Pages
You can use hooks to add conditionally.
For example, to only load on nodes (skipping other entities), add the following function to your
mytheme.theme file.function mytheme_preprocess_node(&$variables) {
$variables['#attached']['library'][] = 'mytheme/fancy-tables';
}
Or if you only want to load on the maintenance page:
function mytheme_preprocess_maintenance_page(&$variables) {
$variables['#attached']['library'][] = 'mytheme/fancy-tables';
}
Drupal.behaviors
Instead of using
$(document).ready(function() {}), as is common in jQuery development, it is better to make use of Drupal.behaviors as it will ensure code runs on normal page loads, ajax calls and inside BigPipe.
To enable
Drupal.behaviors you must add core/drupal as a Javascript dependency in your theme/module.my-js-lib:
version: 1.x
js:
js/my-js-lib.js: {}
dependencies:
- core/drupal
Example from Javascript API Overview:
Drupal.behaviors.myBehavior = {
attach: function (context, settings) {
// Using once() to apply the myCustomBehaviour effect when you want to do just run one function.
$(context).find('input.myCustomBehavior').once('myCustomBehavior').addClass('processed');
// Using once() with more complexity.
$(context).find('input.myCustom').once('mySecondBehavior').each(function () {
if ($(this).visible()) {
$(this).css('background', 'green');
}
else {
$(this).css('background', 'yellow').show();
}
});
}
};
attach() is called once the DOM has loaded for all Drupal.behaviors properties, both on the initial page load, and any subsequent ajax calls.Closures
Since Drupal's implementation of jQuery uses
jQuery.noConflict(), it is also considered good practice to wrap your custom Drupal javascript inside of a closure like this:(function ($, Drupal) {
Drupal.behaviors.myModuleBehavior = {
...
};
})(jQuery, Drupal);
Translating Strings in Javascript
When necessary, string translation can be performed in Javascript using
Drupal.t():var translatedString = Drupal.t('This is a string about @subject that needs to be translated', {@subject: 'Javascript in Drupal'});
Distinguish between plural and singular translations in Javascript using
Drupal.formatPlural():var typeVar = 'list';
var countingString = Drupal.formatPlural(count, 'I have 1 @type item', 'I have @count @type items', {@type: typeVar});
^ Note:
@count is a special placeholder and does need to be defined in your variable array, like @type does. Additionally @count should ever be used in the singular string, only the plural.Preventing Cross-site Scripting (XSS)
Any user-provided input that has not been properly sanitized previously via Twig or PHP should be passed through
Drupal.checkPlain() in JavaScript.Strict Mode
ECMAScript 5's strict mode is a way to opt in to a restricted variant of JavaScript, thereby implicitly opting-out of "sloppy mode". Strict mode isn't just a subset: it intentionally has different semantics from normal code. Browsers not supporting strict mode will run strict mode code with different behavior from browsers that do, so don't rely on strict mode without feature-testing for support for the relevant aspects of strict mode. Strict mode code and non-strict mode code can coexist, so scripts can opt into strict mode incrementally.Strict mode makes several changes to normal JavaScript semantics:
- Eliminates some JavaScript silent errors by changing them to throw errors.
- Fixes mistakes that make it difficult for JavaScript engines to perform optimizations: strict mode code can sometimes be made to run faster than identical code that's not strict mode.
- Prohibits some syntax likely to be defined in future versions of ECMAScript.
To place javascript in strict mode add
'use strict'; to the top of the document, closure, or function. For example:(function ($, Drupal) {
'use strict';
Drupal.behaviors.myModuleBehavior = {
...
};
})(jQuery, Drupal);
Strict Mode Restrictions
| Language element | Restriction | Error | Example |
|---|---|---|---|
| Variable | Using a variable without declaring it. | SCRIPT5042: Variable undefined in strict mode | testvar = 4; |
| Read-only property | Writing to a read-only property. | SCRIPT5045: Assignment to read-only properties is not allowed in strict mode | var testObj = Object.defineProperties({}, { prop1: { value: 10, writable: false // by default }, prop2: { get: function () { } } }); testObj.prop1 = 20; testObj.prop2 = 30; |
| Non-extensible property | Adding a property to an object whose extensible attribute is set to false. | SCRIPT5046: Cannot create property for a non-extensible object | var testObj = new Object(); Object.preventExtensions(testObj); testObj.name = "Bob"; |
| delete | Deleting a variable, a function, or an argument. Deleting a property whose configurable attribute is set to false. | SCRIPT1045: Calling delete on is not allowed in strict mode | var testvar = 15; function testFunc() {}; delete testvar; delete testFunc; Object.defineProperty(testObj, "testvar", { value: 10, configurable: false }); delete testObj.testvar; |
| Duplicating a property | Defining a property more than once in an object literal. | SCRIPT1046: Multiple definitions of a property not allowed in strict mode | var testObj = { prop1: 10, prop2: 15, prop1: 20 }; |
| Duplicating a parameter name | Using a parameter name more than once in a function. | SCRIPT1038: Duplicate formal parameter names not allowed in strict mode | function testFunc(param1, param1) { return 1; }; |
| Future reserved keywords | Using a future reserved keyword as a variable or function name. | SCRIPT1050: The use of a future reserved word for an identifier is invalid. The identifier name is reserved in strict mode. | - implement- interface- package- private- protected- public- static- yield |
| Octals | Assigning an octal value to a numeric literal, or attempting to use an escape on an octal value. | SCRIPT1039: Octal numeric literals and escape characters not allowed in strict mode | var testoctal = 010;var testescape = \010; |
| this | The value of this is not converted to the global object when it is null or undefined. | function testFunc() { return this; } var testvar = testFunc();In non-strict mode, the value of testvar is the global object, but in strict mode the value is undefined. | |
| eval as an identifier | The string "eval" cannot be used as an identifier (variable or function name, parameter name, and so on). | var eval = 10; | |
| Function declared inside a statement or a block | You cannot declare a function inside a statement or a block. | SCRIPT1047: In strict mode, function declarations cannot be nested inside a statement or block. They may only appear at the top level or directly inside a function body. | var arr = [1, 2, 3, 4, 5]; var index = null; for (index in arr) { function myFunc() {}; } |
| Variable declared inside an eval function | If a variable is declared inside an eval function, it cannot be used outside that function. | SCRIPT1041: Invalid usage of 'eval' in strict mode | eval("var testvar = 10"); testvar = 15;Indirect evaluation is possible, but you still cannot use a variable declared outside the eval function. var indirectEval = eval; indirectEval("var testvar = 10;"); document.write(testVar);This code causes an error SCRIPT5009: 'testVar' is undefined. |
| Arguments as an identifier | The string "arguments" cannot be used as an identifier (variable or function name, parameter name, and so on). | SCRIPT1042: Invalid usage of 'arguments' in strict mode | var arguments = 10; |
| arguments inside a function | You cannot change the values of members of the local arguments object. | function testArgs(oneArg) { arguments[0] = 20; }In non-strict mode, you can change the value of the oneArg parameter by changing the value of arguments[0], so that the value of both oneArgand arguments[0] is 20. In strict mode, changing the value of arguments[0] does not affect the value of oneArg, because the arguments object is merely a local copy. | |
| arguments.callee | Not allowed. | function (testInt) { if (testInt-- == 0) return; arguments.callee(testInt--); } | |
| with | Not allowed. | SCRIPT1037: 'with' statements are not allowed in strict mode | with (Math){ x = cos(3); y = tan(7); } |
git
Git is a version control tool used by Drupal.
It is recommended you learn git separately, but here are some commonly used commands:
Basic git commands
git add- Adds files to staging area.git commit- Commits files to repo.-a: Adds all unstaged files.-m: Sets commit message from command line.--amend: Amends the most recent commit message.
git push- Pushes local repo to a remote repo.git pull- Incorporates changes from a remote repository into the current branch.git clone- Clones a remote repo to your local system.git checkout- Switch to another branch-b: Create a new branch prior to switching
git rebase- Changes the history of a commit relative to another commit.git merge- Merges one branch into another.git reset- Resets HEAD to specified state.git clean- Removes unstaged files from working tree.git revert- Reverts changes made in a commit.git log- Show commit logs.
Advanced git commands
git cherry-pick- Applies changes introduced by another commit (useful across branches).git bisect- Finds commit that introduced bug/functionality change using binary search which is O(lg n).git grep- Find lines/files matching pattern within repo.git reflog- Manage reflog information.git gc- Performs garbage collection on local repository.
Site Building
Content Types
Content types typically contain the main content of a page on a Drupal site.
Content Entities
According to Drupal.org - Content Entities and Fields:
A content entity (or more commonly, entity) is an item of content data, which can consist of text, HTML markup, images, attached files, and other data that is intended to be displayed to site visitors. Content entities can be defined by the core software or by modules.
Content entities are grouped into entity types, which have different purposes and are displayed in very different ways on the site. Most entity types are also divided into entity sub-types, which are divisions within an entity type to allow for smaller variations in how the entities are used and displayed.
Adding a Content Type
- Navigate to
Structure->Content Types. The Content types page appears showing all the available types of content. - Click
Add Content Type.
Field Types
| General | Number | Reference | Text |
|---|---|---|---|
| Boolean | List (float) | Content | List (Text) |
| Comments | List (integer) | File | Text (formatted) |
| Date | Number (decimal) | Image | Text (formatted, long) |
| Number (float) | Taxonomy Term | Text (formatted, long, with summary) | |
| Link | Number (integer) | User | Text (plain) |
| Timestamp | Other... | Text (plain, long) |
Adding Fields to a Content Type
- Navigate to
Structure->Content Types. The Content types page appears showing all the available types of content. - Click
Manage Fieldslink in the dropdown for the Operations column. - Click
Add field.
Display Modes
According to Drupal.org - Display Modes, View Modes, and Form Modes:
Display modes exist to provide different presentations of Content Entities for either viewing or editing. The two types of display modes are "view modes" and "form modes." Both of these display mode types—view modes and form modes—are examples of "configuration entities."
uuid: 15dc7aa9-13fd-4412-9c06-06d09f915d08
langcode: en
status: false
dependencies:
module:
- node
id: node.full
label: 'Full content'
targetEntityType: node
cache: true
reference: core.entity_view_mode.node.full.yml
The main property to take note of is the "targetEntityType" property. Each display mode (view mode or form mode) is associated with one, and only one, type of Content Entity.
View Modes
View modes exist to allow Drupal site building tools like Entity Reference fields to request a given entity be rendered in a certain way.
To update the available View Modes for a specific content type navigate to 
Structure -> Content types -> Edit -> Manage display -> Custom Display Settings. 
Form Modes
Form modes allow for multiple sets of field widget orderings and customizations, just as view modes allow for different orderings and customization of field formatters.
Unlike view modes (which fall back to the default view display if view display does not exist for a given view mode) form modes will not use the ‘default’ operation by default.
Taxonomies
According to Drupal.org - Taxonomy:
Taxonomy is used to classify website content. One common example of taxonomy is the tags used to classify or categorize posts in a blog website; the farmers market website could use an ingredients taxonomy to classify recipes. Individual taxonomy items are known as terms and a set of terms is known as a vocabulary
Technically, taxonomy terms are an entity type and the entity subtypes are the vocabularies. Like other entities, taxonomy terms can have fields attached; for instance, you could set up an image field to contain an icon for each term.
An individual vocabulary can organize its terms in a hierarchy, or it could be flat.
Taxonomy terms are normally attached as reference fields to other content entities to provide categorization of content.
Adding a New Vocabulary
To add a new vocabulary to your Taxonomy list:
Adding a Term Reference
- Navigate to
Structure->Content types->Manage fields->Add field. - Pick
Taxonomy termfrom the dropdown and provide a label. - Select the type of item to reference.
Taxonomy reference. - Click
Save field settings. - Click
Save settings.
Adding New Terms to Your Vocabulary
To add new terms to your Vocabulary:
Free Tagging
Allows new terms to be created right on the content editing form.
To enable the ability to add terms while editing content:
- Navigate to
Structure->Content types->Manage fields. - Click
Editfor your Term Reference field. - Check
Create referenced entities if they don't already exist. - Using the dropdown, choose the vocabulary your new terms will be saved to.

Blocks
Blocks are individual pieces of your site’s web page layout. They are placed inside the regions of your theme, and can be created, removed, and rearranged in the Block layout (admin/structure/block) administration page. Examples of blocks include the Who’s online listing, the main navigation menu, and the breadcrumb trail. The main page content is also a block.Some modules make new blocks available for placement on your site. For example, when the core Search module is installed and configured, it provides a block that contains a search form. You may also create and place your own custom blocks.Each block has its own configuration settings, which allow you to select which pages of your site will display the block. It is even possible to place multiple copies of a block, each with its own separate configuration and visibility rules.
Block Management
Blocks can be found at
Structure -> Block layout.
You can configure a specific block by clicking the
Configure button next to that block.Block Visibility
You can configure a blocks visibility settings (i.e. where they will and won't show up), based on:
- Language (If Multilingual is enabled)
- Content Type
- Page
- User Role
Block Placement
You can either place a specific block into a region by configuring the block, or by clicking the "Place block" button for a particular region on the
Block layout page.Menus
Menus are a collection of links (menu items) used to navigate a website. The core Menu UI module provides an interface to control and customize the menu system. Menus are primarily displayed as a hierarchical list of links. By default, new menu items are placed inside a built-in menu labeled Main navigation, but administrators can also create custom menus.The core Standard installation profile contains five menus:Main navigationLinks to sections intended for site visitors. They are usually created by site administrators.Administration
- Links to administrative tasks. This menu mainly contains links supplied by modules on your site.
User account menu
- Links to tasks associated with the user account such as My account and Log out.
Footer
- Links to important pages within the site intended for the footer. They are usually created by site administrators.
Tools
- Links to tasks necessary for site visitors. Some modules feature their links here.
Menu Management
You can see all menus in your system by going to
Structure -> Menus.
You can edit an existing menu by clicking the
Edit menu button next to the respective menu you wish to manipulate.
You can edit an existing menu link by clicking 
Edit next to the particular menu item you wish to modify on the menu edit page. 
Menu Placement
Menus are exposed in Drupal 8 as block, so you can use standard block placement to insert a menu onto your site.
See Blocks for more information about blocks in Drupal.
Views
There is a lot of functionality around views. It is recommended you read through the official Views Module documentation.
This guide will just cover the bare functionality.
What Are Views?
Using the Views module, you can fetch content from the database of your site and present it to the user as lists, posts, galleries, tables, maps, graphs, menu items, blocks, reports, forum posts etc. Different content types including nodes, users, and other bundles can be displayed.Views UI, a submodule within Views, provides a graphical interface underneath which lies a powerful SQL query builder that can access virtually any information in your database and display it in any format.Different displays can present the query results as pages with fixed URLs on your site (or URLs accepting arguments), blocks, feeds, or panel panes.
Existing Views
If you enable the
Views UI module you can see all views in your system by going to Structure -> Views.
You can edit or delete a view by clicking the respective link for the view you wish to manipulate.
By editing a view, you can see the various components of a view:
Adding a New View
- You can add a new view by going into
Structure->Views->Add.
Displays
- The various displays inside a view:You can add additional displays clicking the
Addbutton. - You can also use the views display menu for more options:
- A display's title can be set here:
- Additionally each display may have settings specific to the display type:
- Page Display:
- Rest Export Display Settings:
Format
- Depending on the format of your view, your view output can vary widely. Some include the ability to output specific fields, and others include options to output entities themselves. You will find the format here:
- By clicking the
Addbutton you can choose from a large list of all available fields. (Note: You can add a field to just the particular display you are on, or all displays).
Filtering and Sorting
- You can use certain fields and other criteria for filtering and sorting your results. (Note: You can "expose" filters and sorting criteria in a view, to allow users to specify these values dynamically)
- By clicking the
Addbutton you can choose from a large list of all available fields, filters and sorting criteria. (Note: You can add a field to just the particular display you are on, or all displays).
Headers/Footers/No Results
- You can specify specific content for the views header, footer and also define the behavior when a view returns no results:
Pager
- You can set pagination settings for your view results.
Language
- If your site is configured for Multilingual support, you can specify language-specific settings for your results.
Advanced
The advanced section provides functionality useful in more advanced use cases.
Contextual Filters
Views is a highly flexible module to start with, but the contextual filters increase the use cases for the module by an order of magnitude. Contextual filters work similarly to regular filters, but there is one important difference. Instead of setting a filter value manually, the value is fetched from variables sent programmatically to the view. A regular filter could give you all nodes written by a specified user. A contextual filter for a node author would be able to display all nodes written by the currently viewed user, or the same user who wrote the currently viewed node. The concept is that contextual filters prepare a view for filtering, but the filter value is not yet determined. When the view is eventually called, it is also provided with data used to complete the contextual filters.
Relationships
You can use Relationships to make connections from your view results to other entities. This is commonly done through entity reference fields. By making these connections you expose additional fields and information to views.
Exposed Form
Advanced settings for a view's exposed filters.
Other
Machine name- The machine name for this specific displayAdministrative comment- Leave comments for admins related to this particular view or displayUse AJAX- Turns on AJAX processing for filters and paginationHide attachments in summary- Hide attachments when displaying argument summaryContextual links- Whether not to show contextual menu for this viewUse aggregation- Aggregate results togetherQuery settings- Advanced database optionsCaching- View cache settingsCSS class- Add CSS classes to your view
Configuration Management
According to the Drupal Configuration API Overview:
The configuration API provides a central place for modules to store configuration data. This data can be simple configuration like your site name, or more complex information managed with configuration entities, such as views and content types.
Configuration is a place to store information that you would want to synchronize from development to production. This information is often created during site building and is not typically generated by regular users during normal site operation.
Configuration management in D8 works similar to how Features module did in D7, but now ships out as part of core.
By default configuration data is stored in the
config database table. The configuration management system built into core allows you to import and export these configuration settings across multiple environments and formats.Exporting Configurations
Exporting Full Site Configurations
- Make a configuration change to your system, such as the name of your site.
- Navigate to
Configuration->Development->Configuration Synchronization->Export - Click
Export
- Your browser will download an exported file configuration tarball (e.g.
config-localhost-8888-2017-04-01-04-10.tar.gz)
Exporting Single Items
- Make a configuration change to your system, such as the name of your site.
- Navigate to
Configuration->Development->Configuration Synchronization->Export->Single item - Select the type and name of the config item you wish to export.

- You can now copy and paste this configuration elsewhere for future reference.
Viewing Configuration Changes
- Make a configuration change to your system for something that was previously exported, such as the name of your site.
- The
Activecolumn indicates the current setting in your site. - The
Stagedcolumn indicates the value from the previous exportation.
Importing Configurations
Importing Full Site Configurations
- Obtain a previous export tarball (See Exporting Full Site Configuration above)
- Navigate to
Configuration->Development->Configuration Synchronization->Import - Click
Import
- After reviewing your changes, click
Import All.
Importing Single Items
- Obtain YAML from a previous export.
- Navigate to
Configuration->Development->Configuration Synchronization->Import->Single item - Select the type and name of the config item you wish to import and press
Import
- Click
Confirm
Drush
View configuration settings using drush:
drush config-get system.site
drush config-get system.site name
drush config-get system.site mail
# or
drush cget system.site
drush cget system.site name
drush cget system.site mail
Set configuration settings using drush:
drush config-set system.site name 'My Company Website'
drush config-set system.site mail 'joe.rodgers@mycompany.com'
# or
drush cset system.site name 'My Company Website'
drush cset system.site mail 'joe.rodgers@mycompany.com'
To export configurations using drush:
drush config-export
# or
drush cex
^ This is similar to regenerating features in D7.
To import configurations using drush:
drush config-import
# or
drush cim
^ This is similar to reverting features in D7.
Configuration Storage
You can alter the storage location of your configuration in your
settings.php file (or comparable file in your system):<?php
/**
* Location of the site configuration files.
*
* The $config_directories array specifies the location of file system
* directories used for configuration data. On install, the "sync" directory is
* created. This is used for configuration imports. The "active" directory is
* not created by default since the default storage for active configuration is
* the database rather than the file system. (This can be changed. See "Active
* configuration settings" below).
*
* The default location for the "sync" directory is inside a randomly-named
* directory in the public files path. The setting below allows you to override
* the "sync" location.
*
* If you use files for the "active" configuration, you can tell the
* Configuration system where this directory is located by adding an entry with
* array key CONFIG_ACTIVE_DIRECTORY.
*
* Example:
* @code
* $config_directories = array(
* CONFIG_SYNC_DIRECTORY => '/directory/outside/webroot',
* );
* @endcode
*/
Multilingual
The Drupal 8 Multilingual Initiative focused on making multilingual support an integral part of core functionality. You now have the option of selecting your default language right during the installation process.
When you select a language other than English, Drupal will automatically enable the necessary multilingual modules (i.e. Language Module and Interface Translation Module), and download the latest translations from localize.drupal.org.
Where Drupal 7 required a very large number of modules to handle distinct aspects of multilingual support, Drupal 8 has most of these features wrapped into just 4 modules to help create a better user experience:
- Language Module
- Interface Translation Module
- Content Translation Module
- Configuration Translation Module
Language Module
(machine name:
language)The base module needed for any non-English or multi-lingual site. Allows users to configure languages and how page languages are chosen, and apply languages to content.
This module provides a lot of functionality out of the box:
Support for many languages (and always improving)
Language support is always improving. You can keep track and contribute to the localization of Drupal at localize.drupal.org.
To manage language support go to
Configuration -> Regional and Language -> LanguagesEverything can have a language
Drupal 8 has made all content easily translatable. This includes nodes, users, views, blocks, menus and many other entity-based components.
To specify language options for specific content types: 
Structure -> Content Types -> (SOME CONTENT TYPE) -> Edit -> Language Settings 
To specify language options for specific blocks: 
Structure -> Block Layout -> (SOME BLOCK) -> Configure -> Language 
To specify language options for specific menus: 
Structure -> Menus -> (SOME MENU) -> Edit Menu -> Menu Language 
Two special languages
- Language Not Specified (
const LANGUAGE_NOT_SPECIFIED = 'und') - Used when multilingual options are available, but unused for a particular piece of content. This is comparable toLANGUAGE_NONEin Drupal 7. - Language Not Applicable (
const LANGUAGE_NOT_APPLICABLE = 'zxx') - Used when language options do not apply to a particular piece of content (e.g. an image)
Language negotiation
There are multiple methods to detect which language should be used. You can opt to use as many methods as you want to evaluate a user's language preference.
The options are available, from Enable Language Negotiation:
- URL - Determine the language from the URL (Path prefix or Domain).
- Session - Determine the language from a request/session parameter.
- User - Follow the user's language preference.
- Browser - Determine the language from the browser's language settings.
- Default language - Use the default site language (English).
If multiple methods are selected, Drupal will attempt methods based on their sort order and fallback to the next method if it cannot determine the language based on a particular method.
To change methods and the fallback order go to
Configuration -> Regional and Language -> Languages -> Language Detection and SelectionConfigurable Browser Language Detection
Browsers use different language codes to refer to the same languages. For example
zh-tw, zh-hk and zh-mo may all refer to Chinese Traditional.
Drupal will prepopulate this list based on common browser settings, but this list can be customized at 
Configuration -> Regional and Language -> Languages -> Language Detection and Selection -> Browser -> Configure 
Transliteration
The core/component transliteration classes do basic character-by-character transliteration using a database of generic character transliterations and language-specific overrides, which is OK for basic uses such as creating legal file names and machine names, but not good for transliterating prose (which would require consideration of context, capitalization, etc.).
Interface Translation Module
(machine name:
locale)When enabled, the core Interface Translation ("Locale" in versions before Drupal 8) module allows you to present your Drupal site in a language other than the default (English).You can use it to set up a multilingual web site or to replace the elements of the interface text with text which has been customized for your site. Whenever the Interface Translation module encounters text, it tries to translate it into the currently selected language. If a translation is not available, the string is remembered, so you can look up untranslated strings easily.
To translate specific UI strings go to:
Configuration -> Regional and Language -> Languages -> User Interface Translation and then selecting your language and specifying translation values for each particular string.
To configure your UI translation settings go to:
Configuration -> Regional and Language -> Languages -> User Interface Translation -> Settings
From here you can either configure automatic update language synchronization from localize.drupal.org, or click the
Check Updates Now link, to pull down the latest translation strings for your UI.Content Translation Module
(machine name:
content_translation)Allows users to translate content entities. Allows you to translate your site content, including pages, taxonomy terms, blocks, etc., into different languages.
Default translation settings
Check the "Translatable" checkbox next to each item you want to translate.
Translating a node
While viewing a node of a content type with translation enabled, you should now see a 
Translate tab. 
Configuration Translation Module
(machine name:
config_translation)Provides a translation interface for configuration. Allows you to translate text that is part of the configuration, such as field labels, the text used in Views, etc.
To translate configuration settings go to 
Configuration -> Regional and Language -> Configuration translation. 
Find a configuration setting you wish to translate and click the 
Translate button. (Note: If you see a button that says Listinstead of Translate) this means you're in a parent group and must click through to get to more specific configuration settings. 
When you click 
Translate on a particular item, you should see the option to either add or edit an existing translation. 
See Configuration Management for more information on managing configurations in Drupal.
Web Services
The RESTful Web Services API is new in Drupal 8. Expose entities as REST resources either to build a decoupled Drupal site, to let a native mobile iOS/Android app talk consume/feed a Drupal site, or to integrate with some web service.
Modules
The following Web Services modules are available in core:
- HAL - Serializes entities using Hypertext Application Language.
- HTTP Basic Authentication - Provides the HTTP Basic authentication provider based on Drupal user names and passwords.
- RESTful Web Services - Enables Web Services
- Serialization - Serializes data via xml/json.
REST Request Fundamentals
Safe HTTP Methods (read-only):
GET- Request data from a URIHEAD- Retrieve headers from a URIOPTIONS- Request available communication optionsTRACE- Echoes back request sent to server
Unsafe HTTP Methods (write)
CONNECT- Opens a raw connection to a host through a proxy chainDELETE- Requests that a server delete the resource at URIPATCH- Request changes on a URIPOST- Submit data to a URIPUT- Request submitted data be stored under a URI (currently not supported)
All unsafe methods require
X-CSRF-Token request header, which can be retrieved at /rest/session/token.Serialization Formats
- Always specify the
?_formatquery argument, e.g.http://example.com/node/1?_format=json- When sending a request body containing data in that format, specify the
Content-Typerequest header. This is the case forPOSTandPATCH.
Authentication
basic- The quickest way to get started is to use basic HTTP Authentication. Enable the Basic Auth module found in core, then send your drupal username and password using HTTP Authorization Headerscookie- Use the cookie granted to an authenticated user.
You can also use third-party modules to provide support for other authentication such as OAuth.
REST Configuration
Note: These instructions are for Drupal 8.2 and later. See RESTful Web Services API overview for information on configuring Drupal 8.0 & 8.1.
Configuration Methods
Configurations are managed with YAML but can setup via REST UI module.
Each REST resource has a\Drupal\rest\RestResourceConfigInterfaceconfig entity that corresponds to a@RestResourceplugin. Without such a config entity, the REST resource plugin will not be available for use.There are two methods for configuring resources:
granularity: method: Set serialization formats and authentication per HTTP method.granularity: resource: Set serialization formats and authentication per resource.
Examples:
...
granularity: method
configuration:
GET:
supported_formats:
- json
supported_auth:
- basic_auth
- cookie
...
...
granularity: resource
configuration:
methods:
- GET
...
formats:
- json
...
authentication:
- basic_auth
...
Examples
Using lessons learned in 2.7 - Configuration Management, import the following configuration, specifying
REST resource configuration as the configuration type:id: entity.node
plugin_id: 'entity:node'
granularity: resource
configuration:
methods:
- GET
- POST
- PATCH
- DELETE
formats:
- json
- hal_json
- xml
authentication:
- basic_auth
- cookie
The above configuration supports
GET/POST/PATCH/DELETE requests.
Since this creates a generic endpoint, this data can now be consumed by any number of languages, frameworks and applications. The following examples illustrate a few different options:
GET
Assuming you have a node previously setup with
nid of 1, you can test this by navigating to /node/1?_format=json in your browser. If setup correctly, you should see your node represented by JSON instead of HTML.
For more detailed examples, see GET for reading content entities example.
POST
x_csrf_token=$(curl --silent http://localhost:8888/rest/session/token)
curl --include \
--request POST \
--user admin:password \
--header 'Content-type: application/hal+json' \
--header "X-CSRF-Token: $x_csrf_token" \
http://localhost:8888/entity/node?_format=hal_json \
--data-binary '{"_links":{"type":{"href":"http://localhost:8888/rest/type/node/article"}},"title":[{"value":"My Node Title"}],"type":[{"target_id":"article"}]}'
Notes:
- This example requires the HAL module
- For security reasons it is considered bad practice to type passwords directly into your terminal. More secure methods of authentication should be considered.
For more detailed examples, see POST for creating content entities example.
PATCH
function getCsrfToken(callback) {
jQuery
.get(Drupal.url('rest/session/token'))
.done(function (data) {
var csrfToken = data;
callback(csrfToken);
});
}
function patchNode(csrfToken, node) {
jQuery.ajax({
url: 'http://localhost:8888/node/1?_format=hal_json',
method: 'PATCH',
headers: {
'Content-Type': 'application/hal+json',
'X-CSRF-Token': csrfToken
},
data: JSON.stringify(node),
success: function (node) {
console.log(node);
}
});
}
var newNode = {
_links: {
type: {
href: 'http://localhost:8888/rest/type/node/article'
}
},
type: {
target_id: 'article'
},
title: {
value: 'This is my brand new title'
}
};
getCsrfToken(function (csrfToken) {
patchNode(csrfToken, newNode);
});
Notes:
- This example requires the HAL module
- This example assumed cookie-based authentication, which means you need to be running under the same domain name.
For more detailed examples, see PATCH for updating content entities example.
DELETE
<?php
$response = \Drupal::httpClient()
->delete('http://localhost:8888/node/1?_format=json', [
'auth' => ['admin', 'password'],
'body' => '',
'headers' => [
'X-CSRF-Token' => $x_csrf_token
],
]);
?>
Notes:
- This example assumes you already have the
$x_csrf_tokenvalue to the value from/rest/session/token.
For more detailed examples, see DELETE for deleting content entities example
Exposing Views via Web Services
To expose a view via Web Services:
- Edit your view.
- Under
Displaysclick+ Addand selectREST export.
- Under
Path Settingsset a path for your export.
- You can adjust various settings in regards to format and fields to display as you would with any other view.
- Once you are finished, save your view
- Navigate to the path specified above in your browser. If everything went as expected, you should see your via in your specified format:

Front End Development (Theming)
Creating Themes and Subthemes
In Drupal 8 you can create base themes and subthemes. A base theme provides some set of predefined styles and functionality that a frontend developer can base a subtheme on. Any theme can be used as a base theme, even if it is a subtheme of some other theme.
Core Themes
Drupal 8 comes with five preloaded themes, located in
core/themes/.- Stable: Default base theme for all other themes unless otherwise specified. It is a minimalist theme, that only introduces essential CSS and functionality.
- Classy: Base theme that comes prepackaged with "sensible" default markup and css classes.
- Bartik: Based on
Classy. The default frontend Drupal theme. It is simple and responsive. - Seven: Based on
Classy. The default admin Drupal theme. - Stark: Is not based on any other theme. It is intentionally styleless to demonstrate default Drupal HTML, CSS and Javacript from core and contrib modules.
Choosing a Base Theme
Choosing a base theme is a big decision when creating a new Drupal theme as it lays the framework for the way you will be building your frontend. From a D8 perspective,
Stable and Classy are the two standard base themes provided out of the box, although you could technically use Bartik, Seven and Stark as a base theme if you really wanted to.
The reason Drupal 8 provides two base themes is to appeal to two different groups of developers:
- "Sensible 2/3" developers who want sensible markup and default classes to apply CSS with minimal overrides.
- "Clean 1/3" developers who want a minimalist theme that doesn't place unnecessary markup and css upon themers.
As a compromise,
Stable was established for the minimalists, and Classy was for those wanting sensible markup and classes.
See Results of Drupalcon Austin's Consensus Banana for more information about that decision.
But these are only two out of a theoretically infinite number of base themes you can choose from, including a custom base theme that is shared by all of your different projects.
You can also opt out of using a base theme (see
Stark theme), but just recognize that by doing so you are no longer guaranteeing backwards compatibility when core functionality changes.File Structure
Custom and third-party themes should be installed in
/themes/{themename}.
Inside each theme it is recommended to have
css, js and images directories.
{themename}.info.yml
Drupal automatically searches the themes directory looking for
{themename}.info.yml. This file provides information about your theme to Drupal.
For example -
substable.info.yml:name: Substable
type: theme
description: 'A stable subtheme'
core: 8.x
libraries:
- substable/global-styling
- substable/global-scripts
base theme: stable
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Theme Keys
Here is a list of available theme keys from Defining a theme with an .info.yml file:
- name (required) - The human-readable name. This will appear on the "Appearance" page where the theme is activated.
- type (required) - Indicates the type of extension, i.e., "module", "theme", or "profile". For themes this should always be set to "theme".
- description (optional) - The description, displayed on the "Appearance" page.
- package (optional) - Specifies a "package" that allows you to group themes together.
- core (required) - Specifies the version of Drupal core that the theme is compatible with.
- php (optional) - The minimum version of PHP required. Defaults to value of
DRUPAL_MINIMUM_PHPconstant.- version (optional) - Specifies a version. For themes hosted on drupal.org, the version number will be filled in by the packaging script. Do not specify it manually, but leave out the version line entirely.
- libraries (optional) - A list of libraries (which can contain both CSS and JavaScript assets) to add to all pages where the theme is active.
- libraries-override (optional) - A collection of libraries and assets to override.
- base theme (recommended) - A theme can inherit the resources from another theme by specifying it as a base theme. It is recommended to use classy or stable (stable is the default if the key is not supplied) – this makes it easier for your theme to inherit future changes in core theming.
- hidden (optional) - Indicates whether or not to hide the theme from the "Appearance" page so that it cannot be enabled/disabled via the UI.
- engine (optional) - The theme engine. Defaults to "twig".
- screenshot (optional) - The path to screenshot relative to the theme's .info.yml file. Screenshots should be 588 pixels wide and 438 pixels high, though they are displayed at a smaller size. By default, Drupal will look for a file named "screenshot.png" in the root of your theme folder and use that as the theme image on the "Appearance" page.
- regions (optional) - A list of theme regions. (Note that region keys are not preceded by a dash.) A content region is required. Read more about adding regions to a theme.
- regions_hidden (optional) - A list of inherited regions to remove.
- features (optional) - A list of features to expose on the theme "Settings" page.
- stylesheets-remove (deprecated) - A list of stylesheets from other modules or themes to remove from all pages where the theme is active. Each value must be a full path relative to the docroot to resolve ambiguity when more than one file with the same name exists. In cases where the file is part of a library that belongs to a module or theme, a token in the form
@module_or_theme_namecan be used in place of the full path. Note that when using the token the value must be quoted because"@"is a reserved indicator in YAML. Note: This key is deprecated and will be removed in Drupal 9. In most caseslibraries-overrideshould be used.- ckeditor_stylesheets (optional) - A list of stylesheets to add to the CKEditor frame.
{themename}.libraries.yml
If you wish to include Javascript and CSS in your theme, you can do so by creating libraries in
{themename}.libraries.yml.
For example -
substable.libaries.yml:global-styling:
version: 1.x
css:
theme:
css/style.css: {}
css/print.css: { media: print }
global-scripts:
version: 1.x
js:
js/substable.js: {}
dependencies:
- core/jquery
Libraries also need to be included in the
{themename}.info.yml file. See substable.info.yml example above.
See the Javascript/jQuery section for more information about Javascript and attaching libraries to a subset of pages.
Breakpoint Module
The
breakpoints module allows you to predefine breakpoints for use in your responsive design. Breakpoints are defined in a {themename}.breakpoints.yml file.
Here is an example from the bootstrap theme:
bootstrap.screen-xs-max:
label: screen-xs-max
mediaQuery: 'all and (max-width: 767px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-min:
label: screen-sm-min
mediaQuery: 'all and (min-width: 768px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-sm-max:
label: screen-sm-max
mediaQuery: 'all and (max-width: 991px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-min:
label: screen-md-min
mediaQuery: 'all and (min-width: 992px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-md-max:
label: screen-md-max
mediaQuery: 'all and (max-width: 1199px)'
weight: 1
multipliers:
- 1x
bootstrap.screen-lg-min:
label: screen-lg-min
mediaQuery: 'all and (min-width: 1200px)'
weight: 1
multipliers:
- 1x
Please note that inputting your CSS breakpoints into yourbreakpoints.ymlfile is only necessary when Drupal needs to interact with the breakpoints as in the case of the Responsive Images module.
Breakpoint Keys
- label - A human readable label for the breakpoint.
- mediaQuery - Media query text proper, e.g. 'all and (min-width: 851px)'.
- weight - Positional weight (order) for the breakpoint.
- multipliers - Supported pixel resolution multipliers.
Breakpoint Groups
Breakpoints can be organized into groups. Modules and themes should use groups to separate out breakpoints that are meant to be used for different purposes, such as breakpoints for layouts or breakpoints for image sizing.
yourtheme.group1.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group1
yourtheme.group1.narrow:
label: narrow
mediaQuery: '(min-width: 560px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group1.wide:
label: wide
mediaQuery: '(min-width: 851px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group1
yourtheme.group2.mobile:
label: narrow
mediaQuery: ''
weight: 0
multipliers:
- 1x
group: yourtheme.group2
yourtheme.group2.narrower:
label: narrow
mediaQuery: '(min-width: 400px)'
weight: 0
multipliers:
- 1x
- 2x
group: yourtheme.group2
yourtheme.group2.wider:
label: wide
mediaQuery: '(min-width: 1001px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
You can also add breakpoints to breakpoint groups defined by other modules or themes, but you must use the full name.
yourmodule.yourtheme.group2.superwide
label: superwide
mediaQuery: '(min-width: 1501px)'
weight: 1
multipliers:
- 1x
- 2x
group: yourtheme.group2
Adding Regions to a Theme
All regions should be declared in the theme info file. The keys match the machine name and the values match the label for each available region.
For example:
regions:
header: Header
content: Content
sidebar_left: 'Sidebar - Left'
sidebar_right: 'Sidebar - Right'
footer: Footer
Then each region can be referenced in your
page.html.twig file:<div class="container">
{% if page.header %}
<div class="row">
<div class="header col-xs-12">
{{ page.header }}
</div>
</div>
{% endif %}
<div class="row">
{% if page.sidebar_left %}
<div class="sidebar-left col-xs-2">
{{ page.sidebar_left }}
</div>
{% endif %}
{% if page.sidebar_left and page.sidebar_right %}
<div class="content col-xs-8">
{{ page.content }}
</div>
{% elseif page.sidebar_left or page.sidebar_right %}
<div class="content col-xs-10">
{{ page.content }}
</div>
{% else %}
<div class="content col-xs-12">
{{ page.content }}
</div>
{% endif %}
{% if page.sidebar_right %}
<div class="sidebar-right col-xs-2">
{{ page.sidebar_right }}
</div>
{% endif %}
</div>
{% if page.footer %}
<div class="row">
<div class="footer col-xs-12">
{{ page.footer }}
</div>
</div>
{% endif %}
</div>
Default regions
If you declare any regions in your theme, even just one, all the default regions will no longer be applied and you assume responsibility for declaring any and all regions you want to use.
Theming Concepts
Drupal 8 introduced a new theming layer that helps reduce complexity for designers and frontend developers. The Mobile Initiative focused on making Drupal mobile-friendly right out of the box by making all themes responsive and implementing numerous frontend performance improvements. The Drupal HTML5 Initiative brought HTML 5 into core and allows for increased frontend functionality and improved accessibility.
Another major change is the introduction of Twig as the default templating engine. See Twig Syntax and Twig Templates for more information about using Twig.
Theme Configuration
All available themes can be found in the
Appearance page.
You can change the default frontend theme by clicking
Set as default next to the theme you wish to activate.
You can change the default admin theme by change the
Administration theme dropdown value and clicking the save button.
If a theme hasn't been installed yet, you will need to install to enable it.
To do so, just click
Install or Install and set as default for the theme you wish to enable.
Default themes can also be set in your
system.theme.yml configuration file.
For example:
admin: seven
default: bartik
Additional theme settings can be set by clicking
Settings next to the theme you wish to change.Twig Syntax
From Twig in Drupal 8:
Twig is a template engine for PHP and it is part of the Symfony2 framework.In Drupal 8 Twig replaces PHPTemplate as the default templating engine. One of the results of this change is that all of the theme_* functions and PHPTemplate based*.tpl.phpfiles have been replaced by*.html.twigtemplate files.
Printing Variables and Functions
Twig uses
{{ }} syntax to output data.{{ 3 }}will output the integer3.{{ 'xyz' }}will output the stringxyz{{ myvar }}will output the variablemyvar{{ someFunction }}will output the results ofsomeFunction(){{ someFunction(foo, bar) }}will out put the results ofsomeFunction(foo, bar)
Arrays and Objects
Array items and object properties/methods can be accessed using a dot (
.):{{ foo.0 }}
{{ foo.bar }}
{{ foo.method }}
{{ foo.method(baz) }}
This allows themers to not worry about variable types, and just output the data.
Array items can also be accessed using the subscript syntax (
[]):{{ foo[0] }}
{{ foo['bar'] }}
For convenience's sakefoo.bardoes the following things on the PHP layer:
- check if
foois an array andbara valid element; if not, and iffoois an object, check thatbaris a valid property;- if not, and if
foois an object, check thatbaris a valid method (even ifbaris the constructor - use__construct()instead);- if not, and if
foois an object, check thatgetBaris a valid method;- if not, and if
foois an object, check thatisBaris a valid method;- if not, and if
foois an object, check thathasBaris a valid method;- if not, return a
nullvalue.foo['bar']on the other hand only works with PHP arrays:
- check if
foois an array andbara valid element;- if not, return a
nullvalue.
If you need access a dynamic attribute:
{{ attribute(foo, 'data-foo') }}
Executing Statements:
Twig uses
{% %} syntax to execute statements.Setting Variables:
{% set x = 123 %}
{% set name = 'Name: !name'|t('!name', list.name) %}
Conditionally Outputting a Region:
{% if message %}
<div class="message">{{ message }}</div>
{% endif %}
Looping:
<ul>
{% for item in list %}
<li>{{ item.title }}: ${{item.price}}</li>
{% endfor %}
</ul>
Commenting
Twig uses
{# #} syntax or comments.{# Comments go inside these brackets. #}
You can also do multiline comments:
{#
This comment spans
multiple lines.
#}
A notable use for this is the twig file DocBlock. For example:
{#
/**
* @file
* Default theme implementation for a region.
*
* Available variables:
* - content: The content for this region, typically blocks.
* - attributes: Remaining HTML attributes for the element, including:
* - class: HTML classes that can be used to style contextually through CSS.
*
* @see template_preprocess_region()
*
* @ingroup themeable
*/
#}
Filters
Filters can be used to modify variables and expressions.
{{ "Some String"|t }}
Here are some common Drupal-specific filters:
trans/t: Runs variable through Drupalt()function. (Note: Do not pass variables through the translation filter as this is a potential security vulnerability.)placeholder: Escapes content to HTML and passes throughdrupal_placeholder(), which emphasizes text (i.e.<em>foo</em>).clean_class: Prepares a string for use as a class name.clean_id: Prepares a string for use as an id.format_date: Prepares a timestamp for use as a formatted date.raw: Marks value as being safe which means no escaping will take place. This should be avoided if possible.render: Wrapper for therender()function.safe_join: Joins several strings together with a specified separator (e.g.{{ foo|safe_join(':') }})without: Duplicates an array, excluding specified keys (e.g.{{ foo|without('bar', 'baz') }})
Twig {% trans %} tag
The Twig {% trans %} block will translate the text using tokens with t() or format_plural() if the {% plural ... %} switch has been declared in the tag:
<p class="submitted">
{% trans %}
Submitted by {{ author.name }} on {{ node.date }}
{% endtrans %}
</p>
With the
{% plural ... %} switch:{% set count = comments|length %}
{% trans %}
{{ count }} comment was deleted successfully.
{% plural count %}
{{ count }} comments were deleted successfully.
{% endtrans %}
If filtering the tokens inside the {% trans %} block does not work, create a token outside of the block to minimize operations inside.
{% set date = node.created|format_date('medium') %}
{% trans %}
Node was created on {{ date }}.
{% endtrans %}
Macros
Macros are comparable with functions in regular programming languages. They are useful to put often used HTML idioms into reusable elements to not repeat yourself.
Here is a small example of a macro that renders a form element:
{% macro input(name, value, type, size) %}
<input type="{{ type|default('text') }}" name="{{ name }}" value="{{ value|e }}" size="{{ size|default(20) }}" />
{% endmacro %}
Macros differ from native PHP functions in a few ways:
- Default argument values are defined by using the default filter in the macro body;
- Arguments of a macro are always optional.
- If extra positional arguments are passed to a macro, they end up in the special
varargsvariable as a list of values. But as with PHP functions, macros don't have access to the current template variables.
Overriding Twig Templates
Drupal allows you to override all of the templates that are used to produce HTML markup so that you can fully control the markup that is being output within a custom theme. There are templates for each page element ranging from the high level HTML to small fields.
Twig Debug Mode
To enable
Twig Debug Mode:- If
sites/default/services.ymlexists proceed to next step. Otherwise copysites/default/default.services.ymltosites/default/services.yml. - Edit
sites/default/services.yml. - Under
twig.configsection, setdebug: true. - Clear cache either by clicking
Clear all cacheson/admin/config/development/performanceor runningdrush cron the command line.
Once enabled you can use
dump() to output all available variables or output contents of a particular variables:All variables:
{{ dump() }}
Contents of `foo`:
{{ dump(foo) }}
Theme Hook Suggestions
When Twig debug mode is enabled, Drupal will suggest a few possible ways to override the markup and preprocessor for particular content blocks. This will be shown in the page HTML as comments.
For example:
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--substable-content.html.twig
* block--system-main-block.html.twig
* block--system.html.twig
x block.html.twig
-->
If you wish you make your own recommendations, you hook into the preprocessor for this particular element and make your own additional suggestions.
<?php
/**
* Implements hook_theme_suggestions_block_alter() for block templates.
*/
function substable_theme_suggestions_block_alter(array &$suggestions, array $variables) {
$suggestions[] = 'block__substable';
$suggestions[] = 'block__substable__' . $variables['elements']['#id'];
}
?>
If you clear your cache and look again at the comments you should see the new suggestion in the list.
<!-- THEME DEBUG -->
<!-- THEME HOOK: 'block' -->
<!-- FILE NAME SUGGESTIONS:
* block--substable--substable-content.html.twig
* block--substable.html.twig
* block--substable-content.html.twig
* block--system-main-block.html.twig
* block--system.html.twig
x block.html.twig
-->
Now you can create
templates/block--substable.html.twig or block--substable--substable-content.html.twig, to override core block behavior.
The earlier a file name is in the file name suggestions above, the higher priority it will have. So by pushing to the end of the suggestions array, we are setting our template suggestions to have the highest possible priority.
Make sure you clear your cache after creating any new template files.
Including Twig Templates
The include statement includes a template and returns the rendered content of that file into the current namespace:{% include 'header.html' %} Body {% include 'footer.html' %}Included templates have access to the variables of the active context.You can add additional variables by passing them after the with keyword:{# template.html will have access to the variables from the current context and the additional ones provided #} {% include 'template.html' with {'foo': 'bar'} %} {% set vars = {'foo': 'bar'} %} {% include 'template.html' with vars %}You can disable access to the context by appending the only keyword:{# only the foo variable will be accessible #} {% include 'template.html' with {'foo': 'bar'} only %} {# no variables will be accessible #} {% include 'template.html' only %}
Extending Twig Templates
Note that since the child template doesn't define the footer block, the value from the parent template is used instead.The extends tag can be used to extend a template from another one. Let's define a base template, base.html, which defines a simple HTML skeleton document:<!DOCTYPE html> <html> <head> {% block head %} <link rel="stylesheet" href="style.css" /> <title>{% block title %}{% endblock %} - My Webpage</title> {% endblock %} </head> <body> <div id="content">{% block content %}{% endblock %}</div> <div id="footer"> {% block footer %} © Copyright 2011 by <a href="http://domain.invalid/">you</a>. {% endblock %} </div> </body> </html>In this example, the block tags define four blocks that child templates can fill in.All the block tag does is to tell the template engine that a child template may override those portions of the template.A child template might look like this:{% extends "base.html" %} {% block title %}Index{% endblock %} {% block head %} {{ parent() }} <style type="text/css"> .important { color: #336699; } </style> {% endblock %} {% block content %} <h1>Index</h1> <p class="important"> Welcome on my awesome homepage. </p> {% endblock %}The extends tag is the key here. It tells the template engine that this template "extends" another template. When the template system evaluates this template, first it locates the parent. The extends tag should be the first tag in the template.
Preprocessors
The Drupal 8 preprocessor layer sits directly between the data and the template layers. It should be used for preparing variables to be used by the template, but not perform any of the actual rendering, as that should be handled by Twig instead.
Preprocessing for template files
From Theme system overview:
If the theme implementation is a template file, several functions are called before the template file is invoked to modify the variables that are passed to the template. These make up the "preprocessing" phase, and are executed (if they exist), in the following order (note that in the following list,HOOKindicates the hook being called or a less specific hook. For example, if'#theme' => 'node__article'is called, hook isnode__articleandnode.MODULEindicates a module name,THEMEindicates a theme name, andENGINEindicates a theme engine name). Modules, themes, and theme engines can provide these functions to modify how the data is preprocessed, before it is passed to the theme template:
template_preprocess(&$variables, $hook): Creates a default set of variables for all theme hooks with template implementations. Provided by Drupal Core.template_preprocess_HOOK(&$variables): Should be implemented by the module that registers the theme hook, to set up default variables.MODULE_preprocess(&$variables, $hook):hook_preprocess()is invoked on all implementing modules.MODULE_preprocess_HOOK(&$variables):hook_preprocess_HOOK()is invoked on all implementing modules, so that modules that didn't define the theme hook can alter the variables.ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to set necessary variables for all theme hooks with template implementations.ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set necessary variables for the particular theme hook.THEME_preprocess(&$variables, $hook): Allows the theme to set necessary variables for all theme hooks with template implementations.THEME_preprocess_HOOK(&$variables): Allows the theme to set necessary variables specific to the particular theme hook.
CSS Creation
In a notable change from Drupal 7, CSS class creation has been moved out of preprocessors and directly into templates themselves. To better illustrate, see the following example from CSS classes being moved from preprocess to Twig templates:
The Old Approach
<?php
function template_preprocess_field(&$variables, $hook) {
// ...
$variables['attributes']['class'] = array(
'field',
'field-' . $variables['entity_type_css'] . '--' . $variables['field_name_css'],
'field-name-' . $variables['field_name_css'],
'field-type-' . $variables['field_type_css'],
'field-label-' . $element['#label_display'],
);
// ...
}
?>
<div{{ attributes }}>
{% if not label_hidden %}
<div class="field-label{% if title_attributes.class %} {{ title_attributes.class }}{% endif %}"{{ title_attributes|without('class') }}>{{ label }}: </div>
{% endif %}
<div class="field-items"{{ content_attributes }}>
{% for delta, item in items %}
<div class="field-item"{{ item_attributes[delta] }}>{{ item }}</div>
{% endfor %}
</div>
</div>
The New Approach
<?php
function template_preprocess_field(&$variables, $hook) {
// ...
$variables['entity_type'] = $element['#entity_type'];
$variables['field_name'] = $element['#field_name'];
$variables['field_type'] = $element['#field_type'];
$variables['label_display'] = $element['#label_display'];
// ...
}
?>
{%
set classes = [
'field',
'field-' ~ entity_type|clean_class ~ '--' ~ field_name|clean_class,
'field-name-' ~ field_name|clean_class,
'field-type-' ~ field_type|clean_class,
'field-label-' ~ label_display|clean_class,
label_display == 'inline' ? 'clearfix',
]
%}
{%
set title_classes = [
'field-label',
label_display == 'visually_hidden' ? 'visually-hidden'
]
%}
<div{{ attributes.addClass(classes) }}>
{% if not label_hidden %}
<div{{ title_attributes.addClass(title_classes) }}>{{ label }}: </div>
{% endif %}
<div{{ content_attributes.addClass('field-items') }}>
{% for delta, item in items %}
<div{{ item_attributes[delta].addClass('field-item') }}>{{ item }}</div>
{% endfor %}
</div>
</div>
Back end development (coding)
https://github.com/WidgetsBurritos/d8-studyguide/blob/master/4-back-end-development/README.md
Ref: https://github.com/WidgetsBurritos/d8-studyguide


















































