I recently built my first site with Drupal 8, off of the public beta1. One thing I found very quickly was that online learning resources for Drupal 8—as compared to Drupal 7—were essentially non-existent. Most of the tools that I normally reach for—drupal.org issue queues, stack exchange, tech blog tutorials, and youtube tutorials—simply haven't built up a good stock of Drupal 8 answers yet. To make matters worse, what little knowledge I could find was often hopelessly out of date by the time I encountered it.
This is, of course, nobody's fault. D8 is moving quickly, and needs to keep moving quickly in order to get a release out in a timely manner. It's impossible to document such a moving target, and the people most able to write such documentation are hard at work building the actual Drupal core.
Without the ability to Google my Drupal 8 questions, I had to figure out things by intuition, and by analogy with other components. I figured out the theme structure by inspecting the source of Bartik, and I figured out how to create new modules largely from looking at the core Comment module. Slowly, through trial and lots and lots and lots of error, I found answers to all of my questions. Those answers follow.
-
Where do I download a base theme for Drupal 8?
As of this writing, you don't. It's true that there are a few themes that have tried to keep pace with Drupal 8 in the pre-beta phase. These are admirable efforts, but none have kept up with the rapid pace of D8 developement.
I tried my normal go-to, Adaptive Theme, but the D8 version was unusable, and threw tons of fatal errors as soon as I installed it. I took a look at Zen, but the D8 version hadn't been updated in a year, and its own release notes called it "completely broken." Bootstrap offered a similar caution on their project page.
I'm sure circumstances will improve, but as of today, if you want to theme your D8 site, you're going to have to work from scratch. But I promise it's really not so scary.
-
How do I create a new theme in Drupal 8?
Here's the folder structure of my custom theme.
The only file that absolutely must exist in order for your theme work is theme_name.info.yml. As you might have guessed, this is equivalent to the old theme_name.info that we used in D6 and D7. Of course, a theme with just an info file doesn't do very much—enabling a theme with just an info file is essentially the same thing as enabling Stark (still shipping with D8 by the way). Here's my info file, you can probably intuit most of what it does:
name: 'matt'
type: theme
description: 'My first custom drupal 8 theme'
stylesheets:
all:
- css/styles.css
js:
js/modernizr.custom.04204.js: {}
regions:
header: 'Header'
messages: 'Messages'
navigation: 'Navigation'
sidebar: 'Sidebar'
sidebar_two: 'Sidebar Two'
content: 'Main content'
footer: 'Footer'
features:
- favicon
- logo
version: 8.0.x
core: 8.x
A side note here that I won't dwell on: you'll probably find YML pretty hard to read for the first little while. I still haven't gotten all the way used to it, but it's gotten a lot better in just a few weeks. I also find that liberal use of code folding in Sublime Text makes YML a lot easier to digest.
The other files that you'll almost definitely want are theme_name.theme, a php file, equivalent to the template.php and used mostly for preprocessor functions, and page.html.twig, equivalent to page.tpl.php in D7.
-
How do I declare a new template file in my Drupal 8 theme?
No real changes here from Drupal 7, other than the fact that php templating is gone, and replaced with Twig templating. Just like Drupal 7, you can instantiate new template files in the root of your custom theme folder simply by giving them the same name as one of the template files in core.
Like Drupal 7, you can limit the scope of your template file by giving it a specific name, according to that element's "theme suggestions." (The new documentation is no longer calling these "theme hook suggestions.") So for instance, you can create a node.html.twig which will apply to all nodes, and then a node--article.html.twig which will apply only to nodes or the type article. Note that the available theme suggestions is vastly imporoved in D8, giving you out-of-the-box ability to target by content type, view mode, and a wide variety of other conditions. Improved theme suggestions is one of my favorite new features in D8.
-
How do I find out what template files I can use?
The easiest thing to do here is to just turn on twig debug mode. This is by far my favorite new feature of D8. When turned on, you get an output like:
You can also accomplish a pretty much identical thing by implementing a new API hook added for D8, hook_theme_suggestions_alter.
-
How do I turn on twig debug mode?
D8 ships with a new file called services.yml. I'm honestly still learning how to use it, but the gist is that is contains global configuration for php services. See instructions on drupal.org. You'll find the file at sites/default/services.yml. Here's my services.yml
parameters:
twig.config:
# Twig debugging:
#
# When debugging is enabled:
# - The markup of each Twig template is surrounded by HTML comments that
# contain theming information, such as template file name suggestions.
# - Note that this debugging markup will cause automated tests that directly
# check rendered HTML to fail. When running automated tests, 'twig_debug'
# should be set to FALSE.
# - The dump() function can be used in Twig templates to output information
# about template variables.
# - Twig templates are automatically recompiled whenever the source code
# changes (see twig_auto_reload below).
#
# For more information about debugging Twig templates, see
# http://drupal.org/node/1906392.
#
# Not recommended in production environments
# @default false
debug: true
# Twig auto-reload:
#
# Automatically recompile Twig templates whenever the source code changes.
# If you don't provide a value for twig_auto_reload, it will be determined
# based on the value of twig_debug.
#
# Not recommended in production environments
# @default null
auto_reload: true
# Twig cache:
#
# By default, Twig templates will be compiled and stored in the filesystem
# to increase performance. Disabling the Twig cache will recompile the
# templates from source each time they are used. In most cases the
# twig_auto_reload setting above should be enabled rather than disabling the
# Twig cache.
#
# Not recommended in production environments
# @default true
cache: false
factory.keyvalue:
{}
# Default key/value storage service to use.
# @default keyvalue.database
#default: keyvalue.database
# Collection-specific overrides.
#state: keyvalue.database
factory.keyvalue.expirable:
{}
# Default key/value expirable storage service to use.
# @default keyvalue.database.expirable
#default: keyvalue.database.expirable
-
Why do I have to clear cache after every change in my template file?
You have to set auto_reload to true in services.yml (see #6 above, note lines 30 and 41 of the code sample).
-
I did set twig auto_reload to true, why do I still have to clear cache all the time to see my Twig changes?
Some elements have an additional layer of caching. I ran into this trying to edit the 'submitted by' information in node.html.twig. To disable this during developement, do the following:
Then, in settings.php, uncomment these lines:
-
How do I preprocess my template files?
It's about the same as D7 actually.
Note that, like D7, only the base hook can be used for preprocessing templates. So if you declare node--article--teaser.html.twig you cannot declare hook_preprocess_node__article__teaser, but instead must use hook_preprocess_node and then add conditional logic inside to limit the scope of your preprocessing.
-
Why am I unable to save services.yml?
That's a great question, I have no idea. I was unable to save this file regardless of file permissions or ownership, using Sublime Text or PHP Storm.
I didn't encounter this problem with any other D8 file, and it is no longer reproducing for me in D8 beta2. I was ultimately able to save using Atom. ::shrug::
-
Where is jQuery?
jQuery is still shipping with D8 (version 2.1.0 by the way!), but it is not injected into the page by default.
-
How do I enable jQuery in Drupal 8?
It's pretty easy actually. In your_theme_name.theme:
<?php
/**
* Add jquery
*/
function matt_page_alter(&$page) {
$page['#attached']['library'][] = 'core/jquery';
}
-
How do I add my own custom Javascript in Drupal 8?
This took me a while to figure out. I wanted to add a custom version of the Modernizr library. Though a version of Modernizr ships with D8, I wanted a different version. Here's how I attached it:
-
-
Save your custom script in themes/theme_name/js/script_name.js. Technically this can be any path.
-
Declare your script in themes/theme_name/theme_name.libraries.yml:
matt-corescripts:
version: VERSION
js:
js/modernizr.custom.04204.js: {}
Line 4 is just the path to the javascript file. I'm not sure what line 2 ("version: VERSION") is all about, but I'm being literal here, you actually write the word version in all caps like that. I guess there's a way to allow for multiple versions of the same library, though I'm not sure how to do it.
-
In theme_name.theme, do this:
<?php
/**
* Add custom scripts
*/
function matt_page_alter(&$page) {
$page['#attached']['library'][] = 'matt/matt-corescripts';
}
Note that "matt" on line 7 is just the name of the theme, and "matt-corescripts" is the name I chose on line 1 of matt.libraries.yml
Here's an overview of the way these files are connected:
more info here
-
How do I add external CSS libraries? (e.g. google fonts)
I'm pretty sure there's a more native way to do this, but the only solution I could find was to do it in html.html.twig. Note line 7.
<!DOCTYPE html>
<html{{ html_attributes }}>
<head>
{{ page.head }}
<title>{{ head_title }}</title>
{{ page.styles }}
<link href='http://fonts.googleapis.com/css?family=Open+Sans' rel='stylesheet' type='text/css'>
{{ page.scripts }}
</head>
<body{{ attributes }}>
<a href="#main-content" class="visually-hidden focusable skip-link">
{{ 'Skip to main content'|t }}
</a>
{{ page_top }}
{{ page.content }}
{{ page_bottom }}
{{ page.scripts('footer') }}
</body>
</html>
-
How do I disable commenting on articles?
Comments on nodes are now fields, and thus controlled with field settings.
Or, better yet, just delete the field:
-
How do I change the submitted by information?
This is one of the first things I do on any drupal site build. I can't stand the format "Posted by admin on 2013-02-03 24:32:34". This has been mercifully moved into node.html.twig for D8:
Just copy this file into your custom theme and edit as needed.
-
Why can't I disable modules in Drupal 8?
Technically, D8 has dropped the distinction between "disable" and "uninstall" but that's fairly academic. Let's not dwell on that. As it turns out, these check boxes serve no purpose other than to confuse you—I assume they'll be removed in the full release of D8. To uninstall a module, simply navigate to admin/modules/uninstall
-
How do I create a custom module in Drupal 8?
Creating a bare-bones, "hello world" type module is about the same in Drupal 8 as it was in 7. You only need two files your_module.info.yml and your_module.module. I'm told that the .module is actually optional now, but I've yet to figure out how to produce a functioning module without it, so I'm not sure if that's true.
name: Matthew
description: A simple hello world module.
core: 8.x
package: Custom
type: module
<?php
/**
* @file
* Code for the matthew.module.
*/
function matthew_page_alter(&$page) {
drupal_set_message('Hello world');
}
My first Drupal 8 module
-
What the hell happened to all the fonts on the node add page?
I have no idea. I think this happened after I disabled CKeditor. The following screen shot is definitely not how the node add page looks out of the box:
I never solved this, but I also never reproduced it. Once I reproduce it, I'll open an issue thread on drupal.org, but for now I don't really have anything to report.
-
How do I version my configuration with git?
You've probably heard a lot about the configuration managent initiative over then last few years. You probably also heard recently that active configuration is now stored in the database by default. In the end, this turns out to be a pretty trivial change to the overall architectue of CMI as far as most users are concerned, because the only CMI files that you meaningfully interact with are still stored in code.
If you're familiar with the Features module from D7, the new Config module is exactly the same paridigm. The upshot is that, this is how you export your configuration:
drush @yoursite.local config-export
git add -f sites/default/files/config_wNOLcmycPFZCrXJ9wis9dCdSR4lpYILdBsFxSWuK5Hzhcr-irILQ0u25dfasd9sdfsadWaUDwMg
git commit -m 'Exporting configuration to code.'
git push origin master
drush @yoursite.production config-import
CMI is alive and well
One last thought, that confused the hell out of me initially: the "config" directory comes with two subfolders, "active" and "staging". In the default configuration, only "staging" will ever be used, and "active" will remain empty forever.
Of course this language "default configuration" implies that there's some other not default strategy in which the "active" directory would be used. I haven't figured out how to do that yet, but I'm reasonably sure it would be done in services.yml.
Note also that .gitignore is still shipping with Drupal core, but it's now called example.gitignore. The idea is that you copy example.gitignore to your git root, which would be above the drupal root, and then rename it ".gitignore" so that you're not modding core. For my first build, I just made my git root and my Drupal root the same directory, and renamed this file in place.
-
How do I deploy this thing?
To deploy this to my server on Digital Ocean, I did the following:
-
Exported my database from my local with Sequel Pro.
-
Imported my database to production with Sequel Pro.
-
SFTPed my code to production with Cyberduck.
-
SSHed to production and edited my database credentials with Nano.
-
While SSH'ed to production, edited services.yml to match its default, production ready state.
-
Ran drush @matt.production cr
-
Navigated to my new site in Chrome. It works!
-
Navigated to the performance settings page in the Drupal UI, enabled caching, CSS aggregation, and javascript aggregation.
One important note, if you're server is currently running php 5.3 or less, you're going to have to upgrade to 5.4 or greater.
-
How do I upgrade to php 5.4?
Of course, the upgrade procedure is going to vary wildly with OS, but for me, I was running OS x locally, and Ubuntu on the server.
Mac OS x
On my local (Mac OS X 10.8.5) I installed php 5.4 with homebrew and then pointed my httpd.conf file to point at the new 5.4 binary provided by homebrew:
then I restarted apache with the command sudo apachectl restart
Ubuntu
I found this answer here.
sudo add-apt-repository ppa:ondrej/php5-oldstable
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install php-pear php5-cli php5-common php5-curl php5-dev php5-gd php5-mcrypt php5-mysql php5-pgsql php5-xdebug
-
Why am I getting a white screen of death in production?
Tons of possible reasons, but for me all I needed to do after importing my database was clear the cache with drush one time. I couldn't access any page (including the performance settings page with the "clear cache" button) until this was done.
-
Why is `drush cc all` not working?
It's `drush cr` now. Stands for 'cache rebuild.' Also, you're gonna need to upgrade to Drush 7, more on that below.
-
Why isn't drush working at all with Drupal 8?
You need to upgrade to Drush 7.
-
How do I upgrade to Drush 7?
You need to install Composer to install drush. So do this:
-
OK so I upgraded to php 5.4, installed composer, installed drush 7, and then ran `drush cr` in production now what?
Now your site is ready. Enjoy :-)
-
How do I integrate with Varnish?
Much like Drupal 7, Varnish configuration is more or less out-of-the-box.
Note that this page is trying to guide you toward using Varnish without really saying it. If you don't plan on running varnish, you'll probably want to check off "Use internal page cache".
One thing I always do when working on a site for which I'm the only logged-in user is omit the "vary cookie" in settings.php.
This bumps your varnish hit rate to just about 100%. In D7 it also broke user login. In D8, as far as I can tell, user login works even without the vary cookie, so there might be no downside here.