Mar 11 2019
Mar 11

DrupalCon Seattle is about a month away, and we're putting the finishing touches on this year's plans. Drupal's biggest annual conference affords us the opportunity to support the project, share our expertise, and connect with our colleagues from far and wide. We love DrupalCon. Here's what we've got in store this year.

Our Booth & Swag

Come by the Chromatic booth, #516 in the exhibit hall, to pick up some free Chromatic swag. No kidding, our t-shirts are the softest/coolest and we've got an awesome new vintage design this year:

And we made some kick-ass stickers for this year's conference too:

Our Sessions

Introduction to Drupal 8 Migrations - Clare Ming

Migrations can be intimidating but with Migrate modules now in core, it’s easier than ever to upgrade or migrate legacy applications to Drupal 8. Let's demystify the process by taking a closer look at how to get started from the ground level.

In this session we’ll cover:

  • A brief overview of the Migrate APIs for importing content to Drupal 8, including Migrate Drupal's capabilities to move content from a Drupal source.
  • Understanding your migration pathway.
  • Getting your site ready for migrated content.
  • Sample migration scripts and configuration files for migrating nodes and field mapping.
  • Consideration of media entities, file attachments, and other dependencies.
  • Using Migrate Drupal UI and Migrate Tools for managing migrations.

For those new to Drupal, this session will introduce the basic concepts and framework for setting up your Drupal 8 migration path successfully.

Time: 04/10/2019 / 11:45 - 12:15
Room: 609 | Level 6

Configuration Management: A True Life Story - Nathan Dentzau

Long gone are the days of copying databases, creating a custom module, or creating features to push new functionality to your Drupal Website. Those days and arcane methods are a thing of the past with Drupal 8. Why or how you ask? Read on my friend, read on!

Managing configuration in Drupal 8 has become much easier with the introduction of configuration management. In this talk, we will review “good practices” Oomph and Chromatic have established for configuration management, what tools we use on all of our Drupal 8 projects and how to use them. We will also discuss how configuration management ties into a Continuous Integration pipeline using Github and Travis-CI.

We will discuss the following list of modules:

  • Configuration Manager
  • Configuration Split
  • Configuration Read-only mode
  • Configuration Installer

What you can expect to learn from this talk:

  • Automating configuration management in a Continuous Integration pipeline
  • How to export and import configuration in Drupal 8
  • How to manage configuration in version control
  • How to manage configuration for multiple environments
  • How to install a new instance of Drupal with a set of existing configuration

This talk is for all skill levels and aims to make everyone’s life easier through the magic of Drupal Configuration Management. We look forward to sharing our experience with you and answering any questions you may have.

Time: 04/10/2019 / 12:30 - 13:00
Room: 612 | Level 6

Saving the world from bad websites. - Dave Look

"Saving the world from bad websites." This is our compelling saga at Chromatic. We've spent years growing and evolving as a team and it has taken time for us to land on this phrase as our compelling saga. In this talk, we'll explore the idea of a compelling saga for an agency, what it is, and why it's important. This concept comes from a book titled "High Altitude Leadership" where the author explores leadership principles learned from mountaineering expeditions. We'll discover how these same leadership principles can be applied to our industry.

We will cover:

  • What a compelling saga is and why you should have one for your Agency.
  • How these change and evolve as your agency grows.
  • The cultural impact of all team members being able to articulate the compelling saga.
  • How buy-in or lack of can mean life or death of your agency.

Time: 04/10/2019 / 13:00 - 13:30
Room: 6C | Level 6

Preprocessing Paragraphs: A Beginner's Guide - Larry Walangitan

Paragraphs is a powerful and popular contributed module for creating dynamic pages in Drupal 8. Preprocessing allows us easily to create and alter render arrays to generate tailored markup for any paragraphs type.

In this session you will learn about:

  • Getting started with preprocessing paragraphs and structuring your preprocessing methods.
  • Creating custom render arrays and overriding twig templates.
  • Referencing nested entities and pulling data into paragraph twig templates.
  • How to debug your preprocessing and twig files using contributed modules or composer packages without running out of memory.

You'll leave this session ready to preprocess paragraphs and have a plan of action to reference when debugging any issues. This session is perfect for site-builders or back/front-end devs that are new to preprocessing in Drupal 8 and Twig.

Time: 04/10/2019 / 16:00 - 16:30
Room: 608 | Level 6

If you're coming to the conference, we'd love to meet you. Come say "hello", grab some swag, and tell us how you use Drupal....oh, and if you're looking for a job, our booth is a great place to make an impression on us!

Mar 06 2018
Mar 06

We’ll be attending and presenting at this year’s MidCamp in Chicago. If you’re also going to be in there, be sure to check out our sessions:

Taming Twig

with Larry Walangitan – Friday, March 9th 11:00am-12:00pm

Twig is a wonderful tool to build templates for your Drupal 8 themes. It can be easy to pick up, but certain problems can leave you frustrated and unsure of what to do. Don't fret, we'll be talking through some straightforward solutions to most of the problems that you'll encounter.

Not on Our Watch: an Introduction to Application Performance Monitoring

with Clare Ming – Saturday, March 11th 4:00-5:00pm

Take the mystery out of your application’s performance and squash small problems before they balloon into bigger messes by monitoring your site’s resources and runtime with an option that fits your needs. From free, open-source tools to full-on enterprise solutions, there's something for everyone no matter what your size and budget.

Chromatic is also a proud sponsor of this great Drupal event.

Aug 24 2017
Aug 24

We’re happy to announce today that we’ve released our popular Drupal Coding Standards guide as a free series on Drupalize.me! By opening up these how-to posts to our friends at Drupalize.me, we hope that even more folks will be able to learn from our experience and ultimately, understand the right ways to code for Drupal.

The folks at Drupalize.me provide the best Drupal training materials on the web, so we were more than happy to oblige them when they asked if they could release our Coding Standards guide, carefully crafted by our very own Alanna Burke, as a free series on their platform. This is the spirit of Drupal and open source.

Aug 21 2017
Aug 21

I recently ran into a situation where I needed to link directly to a Drupal page for which there was no explicit route specified in a routing YML file. In this case, I was trying to link to the entity creation page for a media entity, at media/add/image. Technically, I could’ve used Url::fromUri(), but this is not best practice. The documentation page for the Url::fromUri() method is clear about this:

This method is for generating URLs for URIs that:

-- do not have Drupal routes: both external URLs and unrouted local URIs like base:robots.txt

-- do have a Drupal route but have a custom scheme to simplify linking. Currently, there is only the entity: scheme (This allows URIs of the form entity:{entity_type}/{entity_id}. For example: entity:node/1 resolves to the entity.node.canonical route with a node parameter of 1.)

For URLs that have Drupal routes (that is, most pages generated by Drupal), use Url::fromRoute().

The correct way is to use the Url::fromRoute() method, but first we need to find the route name. It makes perfect sense that there wouldn’t be an explicit route in a routing.yml file because there can be any number of entity types on a Drupal site. Thus, there must be a dynamic means of handling routing in these types of situations. But how do we use this method when we don’t know the route name?

After exploring the node and entity modules, I began to wrap my head around how these modules provide dynamic routes. In short, the key bits can be found in: core/lib/Drupal/Core/Entity/Routing/DefaultHtmlRouteProvider.php. This class implements EntityRouteProviderInterface and has a getRoutes() method, which does the following:

Returns a route collection or an array of routes keyed by name, like route_callbacks inside 'routing.yml' files.

Here’s the code:

 /**
  * {@inheritdoc}
  */
 public function getRoutes(EntityTypeInterface $entity_type) {
   $collection = new RouteCollection();

   $entity_type_id = $entity_type->id();

   if ($add_page_route = $this->getAddPageRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.add_page", $add_page_route);
   }

   if ($add_form_route = $this->getAddFormRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.add_form", $add_form_route);
   }

   if ($canonical_route = $this->getCanonicalRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.canonical", $canonical_route);
   }

   if ($edit_route = $this->getEditFormRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.edit_form", $edit_route);
   }

   if ($delete_route = $this->getDeleteFormRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.delete_form", $delete_route);
   }

   if ($collection_route = $this->getCollectionRoute($entity_type)) {
     $collection->add("entity.{$entity_type_id}.collection", $collection_route);
   }

   return $collection;
 }

That explains how these modules implement dynamic routes. We can now use the above to begin figuring out the route name for our example path: media/add/image.

In the case of Drupal entities, the route name is a machine name, which is constructed of three pieces:

Name of module providing the route (entity) Entity bundle ID (media) Route name (canonical, edit_form, add_form, etc.)

Thus, the route name we need is entity.media.add_form.

In my case, I was using the media module (which is moving into core in 8.4) with a custom bundle type of "image". So I also needed to pass that along to fromRoute(), like so:

Url::fromRoute('entity.media.add_form', ['media_bundle' => 'image']);

This gave me a Drupal\Core\Url object. I then used its toString() method to get the path directly.

$some_url = Url::fromRoute('entity.media.add_form', ['media_bundle' => 'image'])->toString();
var_dump($some_url);

This will output:

string(16) "/media/add/image"

I was then able to use the path string to create my link:

'#description' => $this->t('New images can be <a href="https://chromatichq.com/blog/how-link-dynamic-routes-drupal-8/@add_media">added here</a>.', [
  '@add_media' => Url::fromRoute('entity.media.add_form', ['media_bundle' => 'image'])->toString(),
]),

Using route names as opposed to paths is not only best practice, but provides consistent means for developers to link to pages throughout Drupal. Beyond that, route names are more stable, as paths are more likely to change. Hopefully, this post helps others who want to properly link to dynamic routes in Drupal 8. It certainly had me confused.

Nov 14 2016
Nov 14

Teaser Image for ShouldIUpgradetoDrupal8.com

We find that there's still uncertainty out there around upgrading to Drupal 8. The natural answer in the Drupal community is, "Yes, of course go with Drupal 8!" but in the world of tight deadlines and tighter budgets, the answer isn't so clear. Enter ShouldIUpgradetoDrupal8.com, an interactive tool we built to help the community answer that very question.

We aren't yet recommending Drupal 8 to every one of our clients since there's simply too many variables from project to project to do so. ShouldIUpgradetoDrupal8.com aims to help users understand whether their project is a good fit for Drupal 8 by analyzing some of those variables. So take a spin through our 10 question survey and find out whether Drupal 8 is the best choice for your next project. You'll have your answer in less than a minute.

And if you're curious, of course we built it on Drupal 8!

Update 11/15/2016 - Following some great feedback, we've tweaked the scoring to provide better results. Thanks to everyone who sent in their thoughts!

Oct 24 2016
Oct 24

There are a handful of tutorials out there that explain how to use Drupal 8's responsive image and breakpoint modules. However, from what I could find, none of them address how to instruct Drupal to output simple <img> tags that leverage srcset instead of using the <picture> element. Using srcset can be preferable in many circumstances and as such, knowing how to use it in Drupal 8 will be good for most developers to understand. Since I was so confused on how to make this work, I thought it would be worth sharing.

Why srcset over <picture>?

Others have done a much better job explaining the "why" of this approach, namely Chris Coyier and Jason Grigsby. Read those posts for the full picture (heh) but suffice to say, if you're only needing to change the resolution of an image at different viewport sizes/densities, you should use srcset instead of the <picture> element. If you need images that vary more specifically (i.e. different croppings, styles, etc.) then you should use the <picture> element. The reason srcset is preferred, is that it allows the browser to make informed decisions about which version of the image to serve, whereas the <picture> element explicitly tells the browser which images to use and when via media queries. Browsers know way more about our end users than we (developers) can ever know, so why not let them make the hard decisions?

In short:

  • Use srcset for different image sizes/densities across breakpoints.
  • Use <picture> when you need separate art direction/crops across breakpoints.

Convincing Drupal to Use srcset

Drupal's UI for responsive images is confusing and (maybe) rightfully so. Responsive images are confusing. As a rule, Drupal tries really hard to not make assumptions about what the user needs. While I understand why we (the Drupal community) built core this way, this can lead to interfaces that even seasoned professionals have a hard time understanding. In this case, it wasn't clear to me how (or if) I could instruct Drupal that I just wanted an <img> element with srcset and sizes, not a full <picture> element. Each method I tried produced a <picture> element.

Responsive Image Interface

After some digging, I found the core issue where this development and discussion occurred. After skimming that thread and poking around the accepted patch, I knew that what I wanted was possible, but I still couldn't grok how to configure things in Drupal to get the desired output.

Further digging revealed that the default template responsible is called: responsive-image.html.twig. Here is the full file that ships with the Stable base theme:

{#
/**
 * @file
 * Theme override of a responsive image.
 *
 * Available variables:
 * - sources: The attributes of the <source> tags for this <picture> tag.
 * - img_element: The controlling image, with the fallback image in srcset.
 * - output_image_tag: Whether or not to output an <img> tag instead of a
 *   <picture> tag.
 *
 * @see template_preprocess()
 * @see template_preprocess_responsive_image()
 */
#}
{% if output_image_tag %}
  {{ img_element }}
{% else %}
  <picture>
    {% if sources %}
      {#
      Internet Explorer 9 doesn't recognise source elements that are wrapped in
      picture tags. See http://scottjehl.github.io/picturefill/#ie9
      #}
      <!--[if IE 9]><video style="display: none;"><![endif]-->
      {% for source_attributes in sources %}
        <source{{ source_attributes }}/>
      {% endfor %}
      <!--[if IE 9]></video><![endif]-->
    {% endif %}
    {# The controlling image, with the fallback image in srcset. #}
    {{ img_element }}
  </picture>
{% endif %}


The key in this template is the output_image_tag boolean. When true, the template renders an <img> tag instead of the <picture> tag. Inline documentation within the responsive_image module's template_preprocess_responsive_image() function explains that this output_image_tag variable is true when:

There is only one source tag with an empty media attribute. This means we can output an image tag with the srcset attribute instead of a picture tag.

In this context, Drupal is basically saying: if the user hasn't setup multiple breakpoints for this style AND there isn't any specific media query attached. Or in other words, the user doesn't want the theme to determine the images served but wants to put that onus on the browser via srcset.

Solution

If your use-case is to of the "resolution-switching" variety, here is how you get the desired output (no picture element) within Drupal:

  1. Skip creating specific breakpoints in your theme, they aren't needed with this approach.
  2. Setup your different image styles at admin/config/media/image-styles. Usually something like, Author Small, Author Medium and Author Large.
  3. Create a responsive image style at admin/config/media/responsive-image-style. Make sure the Responsive Image module is enabled first. Screenshot of responsive image style creation interface
  4. Ensure "Responsive Image" is selected for the "Breakpoint group".
  5. Choose a suitable "Fallback image style". Click "Save". The following screen is where the secret sauce is.
  6. Under the "1x Viewport Sizing []" fieldset, Select "Select multiple image styles and use the sizes attribute."
  7. Select each of Image styles you'd like to use.
  8. Adjust the Sizes value as needed. The default here 100vw is hard-coded for a good reason, it's a pretty sane default and works well in most situations. Customize this is you want even finer control. More on Sizes. Screenshot of an example Resposive Image Style
  9. Adjust your content type (or other entity) to use your new responsive image style either by altering the display formatter or handling programmatically. Adjust Entity Screenshot
  10. Verify results!

For a thorough explanation of how all of the bits of the Responsive Image module work, see the documentation at admin/help/responsive_image with the _Help module enabled._

You should see something like this for the output of that image field now (formatted for readability):

<img 
  property="schema:image" 
  srcset="/sites/default/files/styles/max_325x325/public/2016-10/utah.jpg 325w, /sites/default/files/styles/max_650x650/public/2016-10/utah.jpg 650w, /sites/default/files/styles/max_1300x1300/public/2016-10/utah.jpg 1300w, /sites/default/files/styles/max_2600x2600/public/2016-10/utah.jpg 2600w"
  sizes="100vw"
  src="https://chromatichq.com/sites/default/files/styles/max_650x650/public/2016-10/utah.jpg" 
  alt="Ogden, Utah Panorama" 
  typeof="foaf:Image"
>

We now have an <img> element with a srcset attribute containing paths to each of our image styles, a sizes attribute and a fallback src attribute which points to our fallback image style.

Now our browser will automatically determine which image to serve up based on the client's viewport size, pixel density, etc. Also, if the client's browser doesn't yet support srcset, it will simply fall back to the value set in the src attribute.

Screencast demonstration of responsive images loading as the viewport changes.

Armed with this knowledge, you can configure your Drupal sites to leverage the power of srcset and allow the browsers of the world to do the hard work of determining which image style to serve to your users.

Sep 26 2016
Sep 26

If you're going to be at DrupalCon Dublin this week and let's be honest, if you're reading this post, you probably are...our very own Larry Walangitan (@walangitan) will be presenting on Twig templates in Drupal 8. If you're looking to gain a thorough understanding of Twig in Drupal 8, Larry has you covered.

From Larry's session page:

Drupal 8’s theming engine is now powered by Twig, but how do we turn over a new leaf after years spent using PHPTemplate to drive our themes? It’s time to take the plunge and discover how easy it is to start working with Twig today. Let’s put Twig under the microscope and compare what’s new and what’s stayed the same! ... You'll leave this session prepared to start working with Twig templates in Drupal 8.

Larry's session starts at 5pm IST tomorrow, September 27th in the Ecocem Room.

More on Larry's session here:

Jul 22 2016
Jul 22

The more I work with Drupal 8, the more I realize how much has changed for developers in the Drupal community. While the transition to a modern, object-oriented system is what's best for the longevity of the platform, it certainly doesn't come without challenges. As someone who doesn't come from an OOP background, I've found the transition difficult at times. In many cases, I know exactly what I want to do, just not how to do it the "Drupal 8 way". On top of this, tutorials and blog posts on D8 are all over the map in terms of accuracy. Many posts written during D8's development cycle are no longer applicable because of API changes, etc.

Below is a list of snippets that might be helpful to site builders or developers more familiar with D7 hooks and procedural. It might also be useful to OOP folks who are new to Drupal in general. My goal below is to add to and update these snippets over time.

Routes & Links

Determine the Current Drupal Route

Need to know what the current Drupal route is or need to run some logic against the current route? You can get the current route like so:

$route = \Drupal::routeMatch()->getRouteName();

To some, the \Drupal::routeMatch() syntax might look foreign (it did to me). Here's a rundown of what's happening here:

First, \Drupal. This is calling the global Drupal class, which, in Drupal 8, is a bridge between procedural and OO methods of writing Drupal code. The following comes from the documentation:

This class acts as a unified global accessor to arbitrary services within the system in order to ease the transition from procedural code to injected OO code.

Right. Moving on to ::routeMatch(). Here we're using the routeMatch() method which "Retrieves the currently active route match object." Simple enough. But what is "::" all about? This StackOverflow answer helped me to understand what that's all about.

From there, the getRouteName() method returns the current route name as a string. Here are some example routes: entity.node.canonical, view.frontpage and node.type_add.

Is this the Front Page Route?

Need to check if the current route is the front page route? There's a service and method for that:

// Is the current route/path the front page?
if ($is_front = \Drupal::service('path.matcher')->isFrontPage()) {}

Here we're calling the path.matcher service (defined in /core/core.services.yml) and using the isFrontPage() method. For more on services, check out the "Services and Dependency Injection Container" documentation on api.drupal.org which helped me understand how all of these bits work together and the why of their structure.

Get the Requested Path

Need to know what the current page's requested path was, as opposed to the route? You can do this:

$current_uri = \Drupal::request()->getRequestUri();

Redirect to a Specific Route

Need to redirect to a specific page? In Drupal 7, you would likely handle this with drupal_goto() in your page callback function. In Drupal 8, you can use RedirectResponse() for that. Here is the relevant changelog.

Here are some examples, borrowed heavily from said changelog. First, in procedural PHP:

use Symfony\Component\HttpFoundation\RedirectResponse;

function my_redirect() {
  return new RedirectResponse(\Drupal::url('user.page'));
}

Here is how you would use a Drupal 8 controller to accomplish the same thing:

use Drupal\Core\Controller\ControllerBase;

class MyControllerClass extends ControllerBase {

  public function foo() {
    //...
    return $this->redirect('user.page');
  }
}

Links on the Fly

Drupal 7 and prior relied heavily on the l() function. (In fact, I would wager this was my most used function over the years. In Drupal 8, if you need to create links on the fly, utilize the Link class

$link = \Drupal\Core\Link::fromTextAndUrl($text, $url);

Working with Entities

Query Database for Entities

If you need to query the database for some nodes (or any other entity) you should use the entityQuery service. The syntax should be pretty familiar to most D7 developers who have used EntityFieldQuery:

// Query for some entities with the entity query service.
$query = \Drupal::entityQuery('node')
  ->condition('status', 1)
  ->condition('type', 'article')
  ->range(0, 10)
  ->sort('created', 'DESC');

$nids = $query->execute();

Loading Entities

If you need to load the actual entities, you can do so a number of ways:

While the following will technically work in Drupal 8:

$node = entity_load_multiple('node', $nids);

This method has been deprecated in Drupal 8 and will be removed before Drupal 9, in favor of methods overriding Entity::loadMultiple(). To future-proof your code, you would do something like the following:

$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple($nids);

Here's how you would do similar for a single node:

$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);

Here are a few other entity snippets that might be useful:

// Link to an entity using the entity's link method.
$author_link = $user->toLink();

// Do the same thing, but customize the link text.
$author_link = $user->toLink('Some Custom Text');

// Given a node object, here's how to determine its type:
$type = $node->getType();

// To get the full user entity of the node's author:
$author = $node->getOwner();

// To get the raw ID of the author of a node:
$author_id = $node->getOwnerId();

Image Styles

Need to whip up an image using a particular image style on the fly? This will work for that:

// Create an instance of an image using a specific image style, given a path to a file.
$style = \Drupal\image\Entity\ImageStyle::load('yourStyle_image');
$img_path = $user->field_profile_some_image->entity->getFileUri();
$img_style_url = $style->buildUrl($img_path);

That's it for now. I intend to keep this post updated as we learn more and more about the new world of Drupal 8. If you have a snippet worth sharing, drop us a line via Twitter and we’ll add it to this post (with credit of course).

Jul 22 2016
Jul 22

DrupalCon New Orleans is nearly here and Chromatic will be attending in full force! Here's the rundown of what you need to know:

Learn About Render Arrays from Gus Childs

Gus will be presenting his session on Drupal 8 render arrays on Tuesday at 1pm in the Blackmesh Room (267-268): Aha! Understanding and Using Render Arrays in Drupal 8. If you're ever been confused by render arrays or just want to learn the best practices for how you're supposed to use them, be sure not to miss this session. Gus happens to be an awesome presenter to boot!

Schedule or Attend a BoF in the Chromatic Room

We're once again sponsoring a Birds of a Feather room. BoFs are a great way for folks to get together and discuss interesting topics in a more informal setting. There's already some great BoFs scheduled for the Chromatic room, including one on Drupal VM and Local Development from the well-known geerlingguy. We have a couple BoFs of our own too:

If you have a great idea for a BoF, schedule one for the Chromatic room!

Connect with Us at one of the Summits

In addition to attending the conference proper, we're once again sending our leadership to the Business Summit, as well as sending a couple of folks to the Media & Publishing Summit.

Grab Some Swag

Every year, DrupalCon attendees rave about how awesome and comfortable our t-shirts are. That's because we don't believe in making swag that we ourselves wouldn't love to wear. This year is no different. For NOLA, we've made a limited run of some special vintage baseball tees, printed on 3/4 sleeve American Apparel 50/50 cotton. These shirts are our best yet and we want to give you one for FREE!

See you in New Orleans!

Jul 22 2016
Jul 22

There are many different ways to handle offsite database backups for your Drupal sites. From host provider automations to contrib modules like Backup and Migrate and everywhere in between. This week, I was looking to automate this process on a Drupal 8 site. Since Backup and Migrate is being rewritten from the ground up for Drupal 8, I decided to whip up a custom shell script using Drush.

I knew I wanted my backups to not only be automated, but to be uploaded somewhere offsite. Since we already had access to an S3 account, I decided to use that as my offsite location. After doing a bit of Googling, I discovered s3cmd, a rather nifty command line tool for interacting with Amazon S3. From their README.md:

S3cmd (s3cmd) is a free command line tool and client for uploading, retrieving and managing data in Amazon S3 and other cloud storage service providers that use the S3 protocol, such as Google Cloud Storage or DreamHost DreamObjects. It is best suited for power users who are familiar with command line programs. It is also ideal for batch scripts and automated backup to S3, triggered from cron, etc.

It works like a charm and basically does all of the heavy lifting needed to interact with S3 files. After installing and setting it up on my Drupal 8 project's server, I was able to easily upload a file like so: s3cmd put someDatabase.sql.gz s3://myBucket/someDatabase.sql.gz.

With that bit sorted, it was really just a matter of tying it together with Drush's sql-dump command. Here's the script I ended up with:

  
    # Switch to the docroot.
    cd /var/www/yourProject/docroot/

    # Backup the database.
    drush sql-dump --gzip --result-file=/home/yourJenkinsUser/db-backups/yourProject-`date +%F-%T`.sql.gz

    # Switch to the backups directory.
    cd /home/yourJenkinsUser/db-backups/

    # Store the recently created db's filename as a variable.
    database=$(ls -t | head -n1)

    # Upload to Amazon S3, using s3cmd (https://github.com/s3tools/s3cmd).
    s3cmd put $database s3://yourBucketName/$database

    # Delete databases older than 10 days.
    find /home/yourJenkinsUser/db-backups/ -mtime +10 -type f -delete
  

With the script working, I created a simple Jenkins job to run it nightly, (with Slack notifications of course) and voilà: automated offsite database backups with Jenkins and Drush!

Jul 11 2016
Jul 11

We recently launched our first Drupal 8 site--actually it’s this very site that you’re reading! While this wasn’t our first time using or developing for Drupal 8, it was our first full site build and launch on the new platform. As such, it was the first time we needed to handle Drupal 8 code deployments. While I’ve previously covered the benefits of using Jenkins, this post will take you through the steps to create a proper Drupal 8 deployment and how to integrate GitHub and Slack along the way. In other words, you’ll see our current recipe for deploying code automatically, consistently and transparently.

First Things First: Some Assumptions

This post assumes you already have a Jenkins server up and running with the following plugins installed:

If you don’t yet have these things ready to go, getting a Jenkins server setup is well documented here. As is how to install Jenkins plugins. For us, we typically use a Linode instance running Ubuntu LTS for our Jenkins servers. This post also assumes that the external environment you’re trying to deploy to already has Drush for Drupal 8 installed.

Example Deployment Script with Drush

Before we dive into setting up the Jenkins job to facilitate code deployments, I’d like to take a look at what exactly we’re trying to automate or delegate to our good friend Jenkins. At the heart of virtually any of our Drupal deployments (be them Drupal 7, 8 or otherwise) is a simple bash script that executes Drush command in succession. At a macro level, this typically means doing the following, regardless of version:

  1. SSH to the server
  2. Change directory to repository docroot
  3. Pull down latest code on the master branch
  4. Clear Drush cache
  5. Run database updates
  6. Update production configuration
  7. Clear Drupal caches

In Drupal 7, where we relied heavily on Features to deploy configuration, we would typically do something like this:

    
        echo ""
        echo "Switching to project docroot."
        cd /var/www/drupal-7-project/docroot
        echo ""
        echo "Pulling down latest code."
        git pull origin master
        echo ""
        echo "Clearing drush cache"
        drush cc drush
        echo ""
        echo "Run database updates."
        drush updb -y
        echo ""
        echo "Reverting features modules."
        drush fra -y
        echo ""
        echo "Clearing caches."
        echo ""
        drush cc all
        echo ""
        echo "Deployment complete."
    

In Drupal 8, we have the magical unicorn that is the Configuration Management System, so our deployments scripts now look something like this:

If you’re familiar with creating Jenkins jobs already and are just looking for a Drupal 8 deploy script, these next lines are for you.

    
        echo ""
        echo "Switching to project docroot."
        cd /var/www/chromatichq.com/docroot
        echo ""
        echo "Pulling down the latest code."
        git pull origin master
        echo ""
        echo "Clearing drush caches."
        drush cache-clear drush
        echo ""
        echo "Running database updates."
        drush updb -y
        echo ""
        echo "Importing configuration."
        drush config-import -y
        echo ""
        echo "Clearing caches."
        drush cr
        echo ""
        echo "Deployment complete."
    

Seriously, configuration management in Drupal 8 is amazing. Hat tip to all of those who worked on it. Bravo.

Another notable difference is that with Drupal 8, clearing caches uses the cache-rebuild Drush command or drush cr for short. drush cc all has been deprecated. R.I.P. little buddy. ⚰

If you have a site that needs to be put into "Maintenance mode" during deployments, you can handle that in Drupal 8 with drush sset system.maintenance_mode 1 to enable and drush sset system.maintenance_mode 0 to disable.

Creating our Jenkins Slave & Job

Now that we’ve covered what it is we want Jenkins to handle automatically for us, let’s quickly run down the punch list of things we want to accomplish with our deployment before we dive into the actual how-to:

  1. Automatically kickoff our deployment script when merges to the master branch occur in GitHub
  2. Run our deployment script from above (deploys latest code, imports config, clears caches, etc.)
  3. Report deployment results back to Slack (success, failure, etc.)

Create Your Jenkins Slave

For Jenkins to orchestrate anything on a remote box, it first needs to know about said box. In Jenkins parlance, this is known as a "node". In our case, since we’re connecting to a remote machine, we’ll use a “Dumb Slave”. Navigate to Manage Jenkins > Manage Nodes > New Node

Creating a Jenkins node

At Chromatic our naming convention matches whatever we’ve named the machine in Ansible. For the purposes of this article, you can just name this something that makes sense to you. Example:** Drupal-Prod-01**

Creating a Jenkins node

As part of the creation of this node, you’ll need to specify the Host and the Credentials Jenkins should use to access the box remotely. If you don’t yet have credentials added to Jenkins, you can do so at Jenkins > Credentials > Global credentials (unrestricted). From there things are pretty self-explanatory.

Setup the Basics for our Jenkins Job

Now that we have a way for Jenkins to target a specific server (our slave node) we can start building our deployment job from scratch. Start by navigating to: Jenkins > New Item > Freestyle Project.

Creating a freestyle project screenshot

From there press "OK" and move on to setting up some basic information about your job, including Project Name, Description and the URL to your GitHub repository. Pro tip: take the time to add as much detail here, especially in the Description field as you can. You’ll thank yourself later when you have loads of jobs.

Basic job information screenshot

Configure Slack Notification Settings (optional)

Assuming you’re interested in tying your deployment status messages to Slack and you’ve installed the Slack Notification Plugin, the next step is to tell Jenkins how/where to report to Slack. You do this under the Slack Notifications options area. As far as notifications go, we prefer to use only the "Notify Failure", “Notify Success” and “Notify Back To Normal” options. This is the right mix of useful information without becoming noisy. To allow Jenkins to connect to your Slack channels, you’ll need to follow these steps for adding a Jenkins integration. Then just fill in your Slack domain, the integration token from Slack and the channel you’d like to post to. These settings are hidden under “Advanced…”.

Slack notifiation settings

Configure Where this Job Can Run

This is where we instruct Jenkins on which nodes the job is allowed to run. In this case, we’ll limit our job to the slave we created in step one: Drupal-8-Prod-01. This ensures that the job can’t run, even accidentally, on any other nodes that Jenkins knows about. Jenkins allows this to be one node, multiple nodes, or a group.

Restricting where the job can run settings screenshot

Configure GitHub Repository Integration

Under "Source Code Management" we’ll specify our version control system, where are repository lives, the credentials used to access the repo and the branches to “listen” to. In our example, the settings look like this:

Version control settings screenshot

Here we’re using a jenkins system user on our servers that has read access on our GitHub repositories. You’ll want to configure credentials that make sense for your architecture. Our "Branch Specifier" (*/master) tells Jenkins to look for changes on the master branch or any remote name by using the wildcard, “*”.

Configure Your Build Triggers

This is where the rubber meets the road in terms automation. At Chromatic, we typically opt for smaller, more frequent deployments instead of larger releases where there is a higher probability of regressions. Since we rely heavily on the GitHub pull request model, we often have many merges to master on any given day of development for an active project. So we configure our deployments to coincide with these merges. The following setup (provided via the GitHub Jenkins Plugin) allows us to automate this by selecting "Build when a change is pushed to GitHub".

Building the job automatically

Setup Your Deployment Script

Here’s where we’ll implement the example deployment script I wrote about earlier in the post. This is the meat and potatoes of our job, or simply put, this is what Jenkins is going to do now that it finally knows how/when to do it.

Under "Build" choose “Add build step” and select “Execute shell”. Depending on your installed plugins, your list of options might vary.

Adding the shell execution step

Then add your deployment script to the textarea that Jenkins exposed to you. If you want somewhere to start, here is a gist of my job from above. When you’ve added your script it should look something like this:

Creating the deployment script

Last Step! Enable Slack Notifications

Although earlier in the job we configured our Slack integration, we still need to tell Jenkins to send any/all notifications back to Slack when a build is complete. You do this sort of thing under the "Add post-build action" menu. Select “Slack Notifications” and you’re good to go.

Adding Slack Notifications

Our deployment job for Drupal 8 is now complete! Click "Save" and you should be able to start testing your deployments. To test the job itself, you can simply press “Build Now” on the following screen OR you can test your GitHub integration by making any change on the master branch (or whichever branch you configured). With the setup I’ve covered here, Jenkins will respond automatically to merges and hot-fix style commits to master. That is to say, when a PR is merged or when someone commits directly to master. Of course no one on your team would ever commit directly to master, would they?!

Pointing out the build now button

Wrapping Up

Assuming everything is setup properly, you should now have a robust automatic deployment system for your Drupal 8 project! Having your deployments automated in this way keeps them consistent and adds transparency to your entire team.

Jul 11 2016
Jul 11

The more I work with Drupal 8, the more I realize how much has changed for developers in the Drupal community. While the transition to a modern, object-oriented system is what's best for the longevity of the platform, it certainly doesn't come without challenges. As someone who doesn't come from an OOP background, I've found the transition difficult at times. In many cases, I know exactly what I want to do, just not how to do it the "Drupal 8 way". On top of this, tutorials and blog posts on D8 are all over the map in terms of accuracy. Many posts written during D8's development cycle are no longer applicable because of API changes, etc.

Below is a list of snippets that might be helpful to site builders or developers more familiar with D7 hooks and procedural. It might also be useful to OOP folks who are new to Drupal in general. My goal below is to add to and update these snippets over time.

Routes & Links

Determine the Current Drupal Route

Need to know what the current Drupal route is or need to run some logic against the current route? You can get the current route like so:

$route = \Drupal::routeMatch()->getRouteName();

To some, the \Drupal::routeMatch() syntax might look foreign (it did to me). Here's a rundown of what's happening here:

First, \Drupal. This is calling the global Drupal class, which, in Drupal 8, is a bridge between procedural and OO methods of writing Drupal code. The following comes from the documentation:

This class acts as a unified global accessor to arbitrary services within the system in order to ease the transition from procedural code to injected OO code.

Right. Moving on to ::routeMatch(). Here we're using the routeMatch() method which "Retrieves the currently active route match object." Simple enough. But what is "::" all about? This StackOverflow answer helped me to understand what that's all about.

From there, the getRouteName() method returns the current route name as a string. Here are some example routes: entity.node.canonical, view.frontpage and node.type_add.

Is this the Front Page Route?

Need to check if the current route is the front page route? There's a service and method for that:

// Is the current route/path the front page?
if ($is_front = \Drupal::service('path.matcher')->isFrontPage()) {}

Here we're calling the path.matcher service (defined in /core/core.services.yml) and using the isFrontPage() method. For more on services, check out the "Services and Dependency Injection Container" documentation on api.drupal.org which helped me understand how all of these bits work together and the why of their structure.

Get the Requested Path

Need to know what the current page's requested path was, as opposed to the route? You can do this:

$current_uri = \Drupal::request()->getRequestUri();

Redirect to a Specific Route

Need to redirect to a specific page? In Drupal 7, you would likely handle this with drupal_goto() in your page callback function. In Drupal 8, you can use RedirectResponse() for that. Here is the relevant changelog.

Here are some examples, borrowed heavily from said changelog. First, in procedural PHP:

use Symfony\Component\HttpFoundation\RedirectResponse;

function my_redirect() {
  return new RedirectResponse(\Drupal::url('user.page'));
}

Here is how you would use a Drupal 8 controller to accomplish the same thing:

use Drupal\Core\Controller\ControllerBase;

class MyControllerClass extends ControllerBase {

  public function foo() {
    //...
    return $this->redirect('user.page');
  }
}

Links on the Fly

Drupal 7 and prior relied heavily on the l() function. (In fact, I would wager this was my most used function over the years. In Drupal 8, if you need to create links on the fly, utilize the Link class

$link = \Drupal\Core\Link::fromTextAndUrl($text, $url);

Working with Entities

Query Database for Entities

If you need to query the database for some nodes (or any other entity) you should use the entityQuery service. The syntax should be pretty familiar to most D7 developers who have used EntityFieldQuery:

// Query for some entities with the entity query service.
$query = \Drupal::entityQuery('node')
  ->condition('status', 1)
  ->condition('type', 'article')
  ->range(0, 10)
  ->sort('created', 'DESC');

$nids = $query->execute();

Loading Entities

If you need to load the actual entities, you can do so a number of ways:

While the following will technically work in Drupal 8:

$node = entity_load_multiple('node', $nids);

This method has been deprecated in Drupal 8 and will be removed before Drupal 9, in favor of methods overriding Entity::loadMultiple(). To future-proof your code, you would do something like the following:

$nodes = \Drupal::entityTypeManager()->getStorage('node')->loadMultiple($nids);


Here's how you would do similar for a single node:

$node = \Drupal::entityTypeManager()->getStorage('node')->load($nid);

Here are a few other entity snippets that might be useful:

// Link to an entity using the entity's link method.
$author_link = $user->toLink();

// Do the same thing, but customize the link text.
$author_link = $user->toLink('Some Custom Text');

// Given a node object, here's how to determine its type:
$type = $node->getType();

// To get the full user entity of the node's author:
$author = $node->getOwner();

// To get the raw ID of the author of a node:
$author_id = $node->getOwnerId();


Image Styles

Need to whip up an image using a particular image style on the fly? This will work for that:

// Create an instance of an image using a specific image style, given a path to a file.
$style = \Drupal\image\Entity\ImageStyle::load('yourStyle_image');
$img_path = $user->field_profile_some_image->entity->getFileUri();
$img_style_url = $style->buildUrl($img_path);

That's it for now. I intend to keep this post updated as we learn more and more about the new world of Drupal 8. If you have a snippet worth sharing, drop us a line via Twitter and we’ll add it to this post (with credit of course).

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web