Jun 23 2017
Jun 23

I'm experimenting with Drupal 8 and some its new features like migration and configuration management. A reset script is a convenient timesaver and many people have shared their techniques for doing so. Having benefited from other's generosity I wanted to return the favour by sharing my current work-in-progress.

This script:

  • Leaves the codebase as-is
  • Deletes and reinstalls the database
  • Deletes the 'files' directory
  • Deletes the specified configuration management directory
  • Enables additional modules, as required
  • Deletes settings.php and allows Drupal install to recreate
  • Updates the new settings.php $config_directories['sync'] entry
  • Adds a settings-migrate.php include to settings.php

I call the script via Drush with an entry in drushrc.php:

$options['shell-aliases']['428-reset'] = '!sh /Users/dale/.drush/sha-scripts/g428-reset.sh';

The script is evolving as I learn more about Drupal 8 and refine my workflow. Comments and suggestions are welcome.

drupal-reset.sh:

#!/bin/bash

# Reinstall a Drupal instance to reset it back to a know state.
# A file base and Drush alias must already be configured.

DRUSH8='/Users/dale/bin/drush8/vendor/bin/drush'
DRUPALDIR='/Users/dale/Sites/group428'
CONFIGDIR='sites/default/group42config/sync'
DRUSHID='@g428'
SITE_NAME='Group 428'
ACCOUNT='admin'
PASS='staring-password'
EMAIL='no-reply@group42.ca'
DB_URL='mysql://group428:group428@localhost/group428'

# Nuke the database
$DRUSH8 $DRUSHID sql-drop --yes

# Nuke the filebase
echo "Resetting files"
chmod -R u+w $DRUPALDIR/*
rm $DRUPALDIR/sites/default/settings.php
rm -r $DRUPALDIR/sites/default/files
rm -r $DRUPALDIR/$CONFIGDIR

# Fresh Drupal install
cd $DRUPALDIR
$DRUSH8 site-install standard --db-url=$DB_URL --site-name=$SITE_NAME --account-name=$ACCOUNT --account-pass=$PASS --account-mail=$EMAIL --yes

# Base configuration
$DRUSH8 $DRUSHID en admin_toolbar,admin_toolbar_tools --yes

# Allow upcoming changes to settings.php
chmod u+w $DRUPALDIR/sites/default
chmod u+w $DRUPALDIR/sites/default/settings.php

# Configuration Management
sed -i '' "/config\_directories\['sync'\]/d" $DRUPALDIR/sites/default/settings.php
echo "\$config_directories['sync'] = '$CONFIGDIR';" >> $DRUPALDIR/sites/default/settings.php

# Migrate
echo "\ninclude 'settings-migrate.php';" >> $DRUPALDIR/sites/default/settings.php
$DRUSH8 $DRUSHID en migrate,migrate_drupal,migrate_plus,migrate_tools,migrate_upgrade --yes

# Login
$DRUSH8 $DRUSHID uli

Jun 22 2017
Jun 22

This summer, LevelTen brought back the Web & Drupal Developer Internship program and we've brought on 3 up and coming developer interns! In today's post, Anima Bajracharya, and her research assignment with of Drupal Travel websites:

After researching some of the case studies of Travel sites created in Drupal, I found out that Drupal can help businesses across any industry to create rich digital experiences. It is no surprise that more than one million sites trust Drupal today. With benefits such as scalability, free modules, responsive design, flexible APIs and one of the largest open source communities; it has become one of the popular Content Management System (CMS).

If you are already using Drupal or planning to use Drupal as CMS for your Travel sites, here are two examples of why travel businesses are using it or maybe you can plan another vacation trip.

1.Let’s go to Fiji!!! ----Fiji.travel

http://www.fiji.travel/

The site had to move to Drupal because of the outdated and poorly coordinated collection in the tourism industry. So, the new site created in Drupal helps the users (old/new) with the treasure of information and planning tool that makes the vacation to Fiji a dream come true. In short, the site is user-friendly, responsive, interactive, and multilingual.

Users can view their itinerary on a map which is great to discover other places nearby. Similarly, the map shows the destination, what makes you happy, and the types of activity available which are perfect for making a variety of plans while in Fiji.

The key benefit for the industry like tourism is that a set of dashboard pages are created that allow site administrators to check live results on site activity and filter any dates historically. This helps the tourism businesses to track how many new users are coming into the site, how people are saving on their trips and how their trips are being created which is running and growing every year.

2. Cruise?-----princess.com

http://www.princess.com/ships-and-experience/onboard-experience/activities/princess-at-sea/

I found this site very interesting because the website (princess.com) is not created in Drupal, but the entire Princess cruise app (Princess@Sea) used in the ship is built on Drupal. Princess@Sea is the industry’s first passenger facing digital experience platform for Princess Cruise and it lets the passengers access information onboard in the ships. It serves to the passengers via wifi which let them access the ships’ schedule of events, stateroom account, itinerary, instant messaging, and personalized cruise planner. It is one of the most interesting and popular hub to the passengers. It makes passengers’ life easier and convenient.

Hopefully, this will give you some fresh ideas of how Drupal can change your business and how it can save your time, money and customers.

Jun 22 2017
Jun 22

On June 28, 2017 at 12:00 PDT/20:00 BST, The Drupal Association will host a one-hour virtual board meeting for the public to attend. It will be followed by an executive session, which is a private session for the board members.  We invite the public to join our board meeting via zoom or you can dial in with the following information:

Board Meeting Agenda

The Board Meeting Agenda includes:

  • An Executive Update covering the following topics and speakers

    • Community Discussions update from Whitney Hess

    • DrupalCon Baltimore Wrap

    • DrupalCon RFP update

    • Marketing Initiative / Review of Drupal.org privacy policy

    • Drupal.org Infrastructure RFP Update

  • Financial Update from Summit CPA

  • Q&A with the Drupal Association board

  • Q&A with the community attendees

  • The Board votes to approve Jan - April 2017 financial statements

After the meeting, we will post a blog that shares more details about the meeting and we wil post the board materials and meeting minutes here.

Executive Session Agenda

While the The Executive Session is a private meeting amongst board members, we want to provide insight into what the agenda topics will be.

  • The Governance Committee will provide an update and recommendation on how the Drupal Association can continue to support the community as they determine how to evolve community governance.

  • The Nominating Committee will provide an update on the progress with identifying new board member candidates for the three seats that expire in November 2017. Learn more about the Drupal Association board here.

We hope you can join us to learn more about Drupal Association operations and to have your questions answered by the Drupal Association Board and staff.

Jun 22 2017
Jun 22

This is part 2 of my summary from the Lead Developer UK conference. If you want to refresh your memory about what happened on Day 1 you can skip back for part 1, or alternatively continue reading about my highlights from the second day of this outstanding conference.

Kevin GoldsmithFail Fast, Fail Smart, Succeed started day two with the recommendation that we shouldn’t punish failure but we should make sure that we learn from our mistakes. Nothing can be more harmful than a culture that prevents talking about failure. Instead, when we learn to talk about our mistakes, others and ourselves will be able to get better much faster. I liked Kevin’s recommendation about creating a shared repository for the team to collect learnings they have made along the way.

Mathias MeyerBuilding and Scaling a Distributed and Inclusive Team gave some valuable insights into his experience at Travis CI. Having the team distributed across continents creates challenges such as when cultural mentalities differ, i.e. some would expect more direct communication while others are used to talk less directly about issues (remember ask vs. guess cultures from part 1?).

I liked the idea of setting up a lot of decision making processes asynchronously via github pull requests, so that team members can contribute at their individual pace. Also, Travis is using special incident response channels for teams on Slack where they collaborate on important tasks in a timely manner.

Randall KoutnikImplementers, Solvers, and Finders: Rethinking the Developer Career Path encouraged the audience to think beyond the classical categories of Junior, Regular and Senior developers. At a first stage, an implementer would give a solution specification and make it happen.

To level up, developers would become solvers that come up with their own solutions to given problems and in the latest stage, they would find their own problems. Think about providing context like a problem space or a given product and you delegate more responsibility to that person so she will need to find possible problems herself. 

Carly RobinsonMentoring Junior Engineers @ Slack HQ shared her personal career path and how she was mentored as a junior. Small startups often struggle with the task of providing the necessary mentorship for their juniors, so it was great to see such a success story. Carly mentioned that for her mentorship is a relationship and you need to establish a good foundation upfront between the mentor and the mentee. Setting goals, tracking progress and acknowledging success are important tools for successful mentorship.

Similarly, being aware of your own emotions is important when reviewing another person’s work. Your initial reaction might be “This is dumb, I know how to fix this.” Instead, by being able to step back when having that reaction and reframing it into something like “Why did that person do that thing?” may allow you to reflect and discover the underlying issues and help come to a solution more collaboratively. 

Overall, I got back from the Lead Developer conference with a lot of inspiration. It’s great to see that so many successful leaders talk about the same topics and mention that it’s worthwhile focusing on problems I face and try to tackle them everyday. For me, growing leadership skills is a continuous effort that takes a lot of self reflection and discipline. It might be easy to agree that points like “giving positive feedback” is the right thing to do, but implementing it into one self’s daily practice takes effort and practice.

Slides of all talks mentioned above and more can be found on the conference website. I’d like to thank the whole organizing team for setting-up an incredible line-up and making sure the code of conduct doesn’t feel like something added as a afterthought, but ensuring diversity & inclusion was something that was really to the core of the Lead Developer conference. Next year’s events will happen in Austin, New York and London.

Jun 22 2017
Jun 22

As part of the Drupal Association Board's duty, board members met in April and approved the Q4 2016 financial statements. Now, we are able to share them with the community to provide transparency and clarity. You can find the financial statements here, which include the Income Statement and Balance Sheet for each month. Our cash balances are located on the balance sheet, located in the Asset section (first part of the balance sheet) called "cash and cash equivalents.

In this blog post, we will answer the following questions:

  1. How did we perform financially this quarter?

  2. How did we perform financially through the end of 2016?

  3. How can we perform better in 2017?

Setting Performance Metrics

To answer #1 and #2, we need to know what success looks like. As they say, if you can’t measure it, you can’t manage it. The Drupal Association works with a virtual CFO firm called Summit CPA, who creates our monthly financial reports as well as sets our financial KPIs, making sure we are working towards goals that ensure the Drupal Association’s sustainability.

Since the Drupal Association’s cash reserves were depleted due to investments in Drupal.org improvements especially to support Drupal 8’s release, Summit recommends that we rebuild our cash reserves and achieve a cash reserve KPI of 15%-30% of estimated twelve-month revenue. Since Drupal’s revenue and expenditures drastically fluctuate from month to month due to DrupalCon’s large cash outlay, a cash reserve goal closer to 30% is the ideal goal.

To rebuild our cash reserves, we need to create an operating profit to fill the reserve. To do this, Summit recommends that our second KPI is to achieve a Net Income Margin of 10%.

Q4 2016 Performance

Since Q4 2016 is near the beginning of our financial turnaround, we will see improvements with both KPIs over time. It is also important to note that Q4 is historically when our cash is lowest. It is the period of time that is between DrupalCon Europe, which operated at a loss, and DrupalCon North America, which rebuilds our cash since it is a profitable event.

Below is our KPI progress in Q4 2016.

KPI

GOAL

OCTOBER

NOVEMBER

DECEMBER

CASH RESERVE

15-30%

11%

9%

8%

NET INCOME MARGIN %

10%

1%

1%

0%

2016 End of Year Performance

2016 was a challenging year financially as we drastically reduced costs by laying off 40% of our staff and eliminating our Portland office. While these corrections were difficult, they set the organization on a sustainable path.

While we continued to remain cash positive by the end of 2016 (see Cash Flow chart below), we operated at a loss, which was anticipated. In positive news, we reduced the losses by about $145,000 (see Forecast vs Actual table below).

Chart: Cash Flow

2016 Cash Flow

(*This chart shows the Drupal Association’s cash flow. It uses actual data from January 2015 to December 2016 and uses forecasted data from January 2017 to April 2017. )

Table: 2016 Actual vs Forecast

2016 Actuals vs forecast

Areas of focus in 2017

With these 2016 improvements in place, 2017 is positioned to be a healthier year financially for the Drupal Association. To ensure a stronger year, we conducted a margin analysis of our programs to see where we need to focus.

From this study, we found several areas to focus in 2017 that create value for the community while also improving our financial health. Areas of focus include:

  • Make DrupalCon Europe a financially sustainable event that continues to provide value

  • Grow DrupalCon North America attendance through improved marketing and attracting more end users with customer content such as industry summits and case studies.

  • Create more value for Supporting Partners to grow participation and create a program for End Users to join.

  • Improve the Drupal adoption journey off of the Drupal.org front page by including content from Drupal businesses that provide value for the visitors and branding or leads for the Drupal businesses who provide the content.

  • Identify ways to reduce costs associated with Drupal.org by studying the sites and services the Drupal Association provides to see if we can reduce associated costs.

We are hard at work making the above improvements and starting to see encouraging results. Starting with our 2017 quarterly updates, we will provide more clarity into our financial portfolio and how each program performed.

Jun 22 2017
Jun 22

Our aim is to add enough detailed information to each of the Drupal error messages that Drupal developers will be able to fix their own problems. This exercise will take some time to complete, at the last count we had almost 700 error messages in the system.

If your site is suffering from this error message please contact us and ask us to expedite the solution to this error and we will do our best to add a solution as soon as possible.

Jun 22 2017
Jun 22

Last time, we gathered together DrupalCon Baltimore sessions about DevOps. Before that, we explored the area of Front End, Site Building, Drupal Showcase, Coding and Development, Project Management and Case Studies. And that was not our last stop. This time, we looked at sessions that were presented in the area of PHP.

Advanced debugging techniques from Patrick Allaert

This session was not about Xdebug. It was about tools that let you know what’s really happening in your PHP code. Tools like the phpdbg debugger, process tracing tools like strace, ltrace, the Linux inotify mechanism, tcpdump/wireshark for network analysis or MySQL Proxy for real-time SQL debugging and monitoring.

[embedded content]

 

Bending Behat's Benefits by Steve Persch from Pantheon

This session covered some of the good, bad, and ugly ways Pantheon uses Behat. Behat is a tool for having better conversations with your team about expectations for the software being built.

[embedded content]

 

Dependency Injection in PHP and Drupal by Hussain Abbas from Axelerant

In this session, attendees learned what Dependency Injection is and how it helps them structure their programs better. They learned some very basic concepts like constructor injection with analogies and examples and then moved on to see how it is done in real life.

[embedded content]

 

Development Workflow Tools for Open-Source PHP Libraries by Greg Anderson from Pantheon

In this session, the author looked at how attendees could get the most out of GitHub source code repository, Packagist package manager for Composer, Travis CI continuous integration service, Coveralls code coverage service, Scrutinizer static analysis service, Box2 phar builder, Sami api documentation generator, ReadTheDocs online documentation reader service, Composer scripts and projects for running local tests and builds. After mastering these tools, attendees should be able to quickly set up a new PHP library project and use it in their Drupal modules.

[embedded content]

 

Hacking Your Way to Better Security by Colin O'Dell from Unleashed Technologies

This session presented common security vulnerabilities. Namely, how they are exploited and how to protect against them. The author explored several of the OWASP Top 10 attack vectors like SQL injection, XSS, CSRF, and others. Each topic was approached from the perspective of an attacker to see how these vulnerabilities can be detected and exploited using several realistic examples. Moreover, he then applied this knowledge to see how web applications can be secured against such vulnerabilities.

[embedded content]

 

Improving Code Quality with Static Analysis by Joseph Purcell from Digital Bridge Solutions

In this session, the author looked at how to use static analysis on a project to identify incorrect code using Code Climate as an example. The main thing for this session was an understanding of static analysis and how to tie its automation into the development cycle of a project to improve code quality.

[embedded content]

 

Plugins, Composer and PHP7 OH MY! by Kris Vanderwater from Acquia

In this session, attendees dug into some serious PHP & plugin-theory, because the author discussed the benefits of adopting the new language features and compared Drupal 8's plugins with the new system.

[embedded content]

 

Realtime PHP using websockets by Jeff Kolesnikowicz from CodePoets

This session discussed some use cases for websockets as well as strategies for implementing websockets into your PHP application. It looked at the most popular websocket protocols and specifically an overview of the WAMP protocol and the PHP Ratchet library. Additionally, the talk was also about WAMPv2 and Thruway. In the end, everybody had a better sense of what websockets are, how they work, and how to use them in your application.

[embedded content]

 

Jun 21 2017
Jun 21

by David Snopek on June 21, 2017 - 5:50pm

Today, there were Critical security releases for Drupal 7 & 8:

https://www.drupal.org/SA-CORE-2017-003

We received a couple e-mails asking if it affected Drupal 6, so I decided to post this short article to say:

Happily, Drupal 6 is not affected! :-)

Of the 3 vulnerabilities in that SA, the two Drupal 8 ones don't apply to Drupal 6: it doesn't have REST or YAML support.

We did extensive testing to see if the Drupal 7 one applied to Drupal 6, including, testing the 'upload' module (in Drupal 6 core) and with the contrib 'filefield' and 'webform' modules and couldn't reproduce the vulnerability.

(FYI, since we access to the private Drupal security queue, we did our testing several months ago :-))

So, if you still use Drupal 6, you don't need to worry about a core update today!

Jun 21 2017
Jun 21

by David Snopek on June 21, 2017 - 3:35pm

As you may know, Drupal 6 has reached End-of-Life (EOL) which means the Drupal Security Team is no longer doing Security Advisories or working on security patches for Drupal 6 core or contrib modules - but the Drupal 6 LTS vendors are and we're one of them!

Today, there is a Moderately Critical security release for the Search 404 module to fix an Cross Site Scripting (XSS) vulnerability.

From the security advisory for Drupal 7:

The Search 404 module enables you to redirect 404 pages to a search page on the site for the keywords in the url that was not found.

The module did not filter administrator-provided text before displaying it to the user on the 404 page creating a Cross Site Scripting (XSS) vulnerability.

This vulnerability is mitigated by the fact that an attacker must have a role with the permission "administer search".

Here you can download the Drupal 6 patch.

If you have a Drupal 6 site using the Site Verify module, we recommend you update immediately.

If you'd like all your Drupal 6 modules to receive security updates and have the fixes deployed the same day they're released, please check out our D6LTS plans.

Note: if you use the myDropWizard module (totally free!), you'll be alerted to these and any future security updates, and will be able to use drush to install them (even though they won't necessarily have a release on Drupal.org).

Jun 21 2017
Jun 21


Embedding media assets (images, videos, related content, etc) in a WYSIWYG text area is a long-standing need that has been challenging in Drupal sites for a while. In Drupal 7, numerous solutions addressed the problem with different (and sometimes competing) approaches. 


Drupal 8 core comes with basic support for embedding images out-of-the-box, but we all know that “ambitious digital experiences” nowadays need to go far beyond that and provide editors with a powerful tool capable of handling any type of media asset, including remote ones such as a relevant Tweet or Facebook post.
 

This is where the powerful combination of Entity Embed + URL Embed comes into play. Predicated on, and extending the foundation established by Drupal core, these two modules were designed to be a standardized solution for embedding any entity or remote URL content in a WYSIWYG editor in Drupal 8.

In this article, you will find:

  • What Drupal 8 core offers out-of-the-box for embedding images inside rich text
  • How to create a WYSIWYG embed button with the Entity Embed module (with some common pitfalls you may encounter along the way)
  • How to embed remote media assets with the URL Embed module (again, with some common pitfalls!)
  • Additional resources on how to extend and integrate your embedding solutions with other tools from the Media ecosystem.

Drupal 8 core embedding

Drupal 8 has made a big step from Drupal 7 and included the CKEditor WYSIWYG library in core. It also comes with an easy-to-use tool to embed local images in your text.

Core image embed

But what if the content you want to embed is not an image?

I am sure you have come across something like this before:

Embedding example 1 Embedding example 2

These are all examples of non-image media assets that needed to be embedded as well. So how can we extend Drupal 8 core’s ability to embed these pieces of content in a rich-text area? 

Enter the Entity Embed module.

The Entity Embed module allows any Drupal entity to be embedded within a text area using a WYSIWYG editor.

 The module doesn't care what you embed, as long as that piece of content is stored in Drupal as a standard entity. In other words, you can embed nodes, taxonomy terms, comments, users, profiles, forms, media entities, etc. all in the same way and using a standard workflow.

In order to limit the length of this article, we will be working only with entities provided by Drupal core, but you should definitely try the Media Entity module, which can take your embedding capabilities to a whole new level (more on this at the end of this article).

Basic installation and configuration

Create an embed button

After downloading and installing the Entity Embed module and its dependencies, navigate to 

Configuration -> Content Authoring -> Text editor embed buttons

or go directly to /admin/config/content/embed and click “Add embed button”

Add embed button

You will see that there is already a button on this page called “Node,” which was automatically created upon installation. For the purposes of the example, we will create another button to embed nodes, but you can obviously use and modify the provided one on your site if you wish.

As an example, we’ll create a button to embed a node into another node, simulating a “Related article” scenario in a news article.

Button config

The config options you will find on this page are:

  • Label: Give your button a human-readable name and adjust its machine name if needed
  • Embed type: If you only have the Entity Embed module enabled, “Entity” is your only option here. When you install other modules that also extend the Embed framework, other options will be available.
  • Entity type: Choose here the type of the entity you will be embedding with this button. In our case, we choose “Content” in order to be able to embed nodes.
  • Content type: We can optionally filter the entity bundles (aka “Content types” for nodes) that the user will be allowed to choose from. In our case we only want “Articles”.
  • Allowed Entity Embed Display plugins: Choose here the display plugins that will be available when embedding the entity. This means that when an editor chooses an entity to embed, they will be asked how this entity should be displayed, and the options the user sees will be restricted to the selections you make here. In our case, we only want the editor to be able to choose between a simple “Label” pointing to the content, or a “Teaser” visualization of the node (which uses the teaser viewmode). More on this later.
  • Entity browser: In our example, we won’t be using any, but you should definitely try the integration of Entity Embed with Entity Browser, making the selection of the embedded entities much easier!
  • Button icon: You can optionally upload a custom icon to be shown on the button. If left empty, the letter “E” will be used.

Once we’ve created our button, it’s time to add it to the WYSIWYG toolbar.

Entity Embed: WYSIWYG configuration

Navigate to:

Configuration -> Content authoring -> Text formats and editors

or go directly to /admin/config/content/formats and click “configure” on the format you want to add the button to. In our example, we are going to add it to the “Basic HTML” text format.

Step 1: Place the button in the active toolbar

Step 1 place the button

Step 2: Mark the checkbox “Display embedded entities”

Step 2 enable the filter

Step 3: Make sure the special tags are whitelisted

If you are also using the filter “Limit allowed HTML tags and correct faulty HTML” (which you should), it’s important to make sure that the tags used by this module are allowed by this filter. Scroll down a little bit and verify that the tags:

<drupal-entity data-entity-type data-entity-uuid data-entity-embed-display data-entity-embed-display-settings data-align data-caption data-embed-button>

are listed in the “Allowed HTML tags” text area.

Step 3 whitelist tags

If you are using a recent version of the module, this should be automatically populated as soon as you click on “Display embedded entities”, but it doesn’t hurt to verify it was done correctly.

Common pitfall

If you are embedding images and you want to use “Alt” and “Title” attributes, you probably want to fine-tune the allowed tags to be something like:
<drupal-entity data-entity-type data-entity-uuid data-entity-embed-display data-entity-embed-display-settings data-align data-caption data-embed-button alt title>

Instead of the default value provided.

Only local images error

Common pitfall

If you have the filter “Restrict images to this site” active (which comes activated by default in Drupal core), you will probably want to reorder the filters so that “Display embedded entities” comes after the filter “Restrict images to this site”. If you don’t do this, when you embed some image entities you may end up with something like:

All set, ready to embed some entities! 

Your editors can now navigate to any content form that uses the “Basic HTML” text format and start using the button!

Videos require iframe browser support. Entity displays

However, for an entity without custom viewmodes, you won’t have the “Full” (or “default”) viewmode available anymore. There is still some discussion happening about how to ensure the best user experience for this issue, if you want to know more about it or jump in and help, you can find more information herehere and here.

Common pitfall

After this issue got in, the module slightly changed the way it manages the display plugins for viewing the embedded entity. As a result, the entity_reference formatter (“Rendered entity”) that many people are used to from other contexts is not available right away, and instead all non-default viewmodes of the entity type are shown directly as display options. 

Quick and easy solution for remote embedding with URL Embed


A sister-module of Entity Embed, the URL Embed module allows content editors to quickly embed any piece of remote content that implements the oEmbed protocol. 


Nice tech terms, but in practice what does that mean? It means that any content from one of the sites below (but not limited to these) can be embedded:

  • Deviantart
  • Facebook
  • Flickr
  • Hulu
  • IFTTT
  • Instagram
  • National Film Board of Canada
  • Noembed
  • Podbean
  • Revision3
  • Scribd
  • SlideShare
  • SmugMug
  • SoundCloud
  • Spotify
  • TED
  • Twitter
  • Ustream
  • Viddler
  • Vimeo
  • YouTube

Under the hood, the module leverages the awesome Embed open-source library to fetch the content from the remote sites, and uses the same base framework as Entity Embed to create embed buttons for this type of content. As a result, the site builder has a very similar workflow when configuring the WYSIWYG tools, which can then be used by the content editor in a very intuitive way. Let’s see how all that works.

Install the module and create a URL Embed button

As usual, the first step is to enable the module itself, along with all its dependencies.

URL Embed library error

Common pitfall

This module depends on the external Embed library. If you are using Composer to download the Drupal module (which you should), Composer will do all the necessary work to fetch the dependencies for you. You can also install only the library itself using Composer if you want. To do that just run "composer require embed/embed". Failing to correctly install the library will prevent the module from being enabled, with an error message such as:

Once successfully enabled, the “Embed button” concept here is exactly the same as in the previous example, so all we need is to go back to /admin/config/content/embed .

URL Embed button

The module already creates a new button for us, intended for embedding remote content. URL buttons have no specific configuration except for name, type and icon, so we’ll skip the button configuration part.

URL Embed: WYSIWYG Configuration

Similarly to what we did with the Entity button, we need to follow the same steps here to enable the URL Embed button on a given text format:

  • Step 1: Place the button in the active toolbar
  • Step 2: Mark the checkbox “Display embedded URLs”
  • Step 3: Make sure the special tags are whitelisted. (Note that here the tags won’t be automatically populated, you need to manually introduce <drupal-url data-*> to the “Allowed HTML tags” text area.)
  • Step 4: (Optional) If you want, you can also mark the checkbox “Convert URLs to URL embeds”, which will automatically convert URLs from the text into embedded objects. If you do this though, make sure you reorder the filters so that “Display embedded URLs” is placed after the filter “Convert URLs to URL embeds”

 All done, go embed some remote content!

Videos require iframe browser support.

Common pitfall

Please bear in mind that while the Embed library can deal with many remote websites, it won’t do magic with providers that don’t implement the oEmbed protocol in a consistent way! Currently the module will only render the content of providers that return something inside the code property. If you are trying to embed some remote content that is not appearing correctly on your site, you can troubleshoot it by going to the URL: https://oscarotero.com/embed3/demo and trying the same URL there. If there is no content inside the code property, this URL unfortunately can’t be embedded in Drupal using URL Embed. Once this issue is complete, this will be less of an issue because the validation will prevent the user from entering an invalid URL.

Get even more by integrating with other Media solutions

There are at least two important ways you can extend the solutions indicated here, to achieve an even more powerful or easy-to-use editorial experience. Those approaches will be discussed in detail in upcoming articles, but you can have a brief idea about them below, in case you want to start learning about them right away.

Allow content to be selected through Entity Browsers


In the previous example, the content being embedded (in this case a referenced node) was selected by the editor using an autocomplete field. This is a very basic solution, available out-of-the-box for any referenced entity in Drupal core, but it does not provide the ultimate user experience we would expect from a modern CMS. The good news: it’s an easy fix. Plug any Entity Browser you may have on your site to any embed button you have created. 

Going over the configuration of Entity Browsers is beyond the scope of this article, but you can read more at the official documentation, or directly by giving it a try, using one of the pre-packaged modules like File Entity Browser, Content Browser or Media Entity Browser.

Common pitfall

If you are using an Entity Browser to select the content to be embedded, make sure your browser is configured to have a display plugin of type “iFrame.” The Embed options already appear in a modal window, so selecting an Entity Browser that is configured to be shown in a modal window won’t work.

Use the Media Entity module to deal (also) with remote media assets

The URL Embed module is a handy solution to allow your site editors to embed remote media assets in a quick-and-easy way, but what if:

  • you want to standardize your workflow for managing local and remote media assets?
  • you want to have a way to re-use content that was already embedded in other pieces of content?
  • etc.

A possible alternative that would solve all those needs is to standardize how Drupal sees all your media assets. The Media Entity approach means that you can “wrap” both local and remote media assets in a special “media" entity type, and as a result, the Entity Embed could be used with any type of asset, once all of them are Drupal entities regardless of their real storage.

In Conclusion

Hopefully, you find this a useful tutorial. I can strongly recommend this “Media Entity” approach, because it is being partly moved into Drupal core, which will result in an even stronger foundation for how Drupal sites will handle media assets in the near future.

Acknowledgements

Thanks to Seth Brown, David Burns and Dave Reid for their help with this article.

Other articles in this series

Image credit: Daian Gan

Jun 21 2017
Jun 21

One day you might wake up with the next big idea that will shake the world in the most ungentle way. You decide to build an app, because you’ll have full access to all features of the device that you want your solution to work on. But then it dawns on you: you will actually need to build multiple apps in completely different languages while finding a way for them to serve the same content...

Then you start to realise that you won’t be able to step into the shoes of the greats, because web technology is holding you back. Fortunately, Drupal 8 and React Native are here to save your day - and your dream!

In this blog post you'll read how you can leverage Drupal 8 to serve as the back-end for your React Native app. 

First, however, a quick definition of what these technologies are:

  • Drupal is an open source content management system based on PHP.
  • React Native is a framework to build native apps using JavaScript and React.

If you want to read more about Drupal 8 or React Native, you're invited to check the sources at the bottom of this article.
 

Why React Native?

There are a myriad of front-end technologies available to you these days. The most popular ones are Angular and React. Both technologies allow you to build apps, but there is a big difference in how the apps will be built.

The advantage of employing React Native is that it lets you build an app using JavaScript, while converting the JavaScript into native code. In contrast, Angular or Ionic allow you to create a hybrid app, which basically is a website that gets embedded in a web view. Although the benefit here is that you're able to access the native features of a device.

In this case, we prefer React Native, because we want to build iOS and Android applications that run natively.
 

Headless Drupal

One of the big buzzwords that's been doing the rounds in the Drupal community lately is 'Headless'. A headless Drupal is actually a Drupal application where the front-end is not served by Drupal, but by a different technology.

You still get the benefits of a top notch and extremely flexible content management system, but you also get the benefits of your chosen front-end technology.

In this example, you'll discover how to set up a native iOS and Android application that gets its data from a Drupal website. To access the information, users will have to log in to the app, which allows the app to serve content tailored to the preferences of the user. Crucial in the current individualized digital world.

 

Drupal 8 - React Native Android & iOS

So this already brings us to our first hurdle. Because we are using a native application, authenticating users through cookies or sessions is not possible. So we are going to show you how to prepare your React Native application and your Drupal site to accept authenticated requests.
 

The architecture

The architecture consists of a vanilla Drupal 8 version and a React Native project with Redux.

The implemented flow is as following:

  1. A user gets the login screen presented on the app.
  2. The user fills in his credentials in the form
  3. The app posts the credentials to the endpoint in Drupal
  4. Drupal validates the credentials and logs the user in
  5. Drupal responds with a token based on the current user
  6. The app stores the token for future use
  7. The app now uses the token for all other requests the app makes to the Drupal REST API.
     

Creating an endpoint in Drupal

First we had to choose our authentication method. In this example, we opted to authenticate using a JWT or JSON web token, because there already is a great contributed module available for it on Drupal.org (https://www.drupal.org/project/jwt).

This module provides an authentication service that you can use with the REST module that is now in Drupal 8 core. This authentication service will read the token that is passed in the headers of the request and will determine the current user from it. All subsequent functionality in Drupal will then use that user to determine if it has permission to access the requested resources. This authentication service works for all subsequent requests, but not for the original request to get the JWT.

The original endpoint the JWT module provides, already expects the user to be logged in before it can serve the token. You could use the ready available basic authentication service, but we preferred to build our own as an example.
 

Authentication with JSON post

Instead of passing along the username and password in the headers of the request like the basic authentication service expects, we will send the username and password in the body of our request formatted as JSON.

Our authentication class implements the AuthenticationProviderInterface and is announced in json_web_token.services.yml as follows:

services:
 authentication.json_web_token:
   class: Drupal\json_web_token\Authentication\Provider\JsonAuthenticationProvider
   arguments: ['@config.factory', '@user.auth', '@flood', '@entity.manager']
   tags:
     - { name: authentication_provider, provider_id: 'json_authentication_provider', priority: 100 }

The interface states that we have to implement two methods, applies and authenticate:

public function applies(Request $request) {
 
 $content = json_decode($request->getContent());
 
 return isset($content->username, $content->password) && !empty($content->username) && !empty($content->password);
}

Here we define when the authenticator should be applied. So our requirement is that the JSON that is posted contains a username and password. In all other cases this authenticator can be skipped. Every authenticator service you define will always be called by Drupal. Therefore, it is very important that you define your conditions for applying the authentication service.

public function authenticate(Request $request) {
 $flood_config = $this->configFactory->get('user.flood');
 $content = json_decode($request->getContent());
 
 $username = $content->username;
 $password = $content->password;
 // Flood protection: this is very similar to the user login form code.
 // @see \Drupal\user\Form\UserLoginForm::validateAuthentication()
 // Do not allow any login from the current user's IP if the limit has been
 // reached. Default is 50 failed attempts allowed in one hour. This is
 // independent of the per-user limit to catch attempts from one IP to log
 // in to many different user accounts.  We have a reasonably high limit
 // since there may be only one apparent IP for all users at an institution.
 if ($this->flood->isAllowed(json_authentication_provider.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) {
   $accounts = $this->entityManager->getStorage('user')
     ->loadByProperties(array('name' => $username, 'status' => 1));
   $account = reset($accounts);
   if ($account) {
     if ($flood_config->get('uid_only')) {
       // Register flood events based on the uid only, so they apply for any
       // IP address. This is the most secure option.
       $identifier = $account->id();
     }
     else {
       // The default identifier is a combination of uid and IP address. This
       // is less secure but more resistant to denial-of-service attacks that
       // could lock out all users with public user names.
       $identifier = $account->id() . '-' . $request->getClientIP();
     }
     // Don't allow login if the limit for this user has been reached.
     // Default is to allow 5 failed attempts every 6 hours.
     if ($this->flood->isAllowed('json_authentication_provider.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) {
       $uid = $this->userAuth->authenticate($username, $password);
       if ($uid) {
         $this->flood->clear('json_authentication_provider.failed_login_user', $identifier);
         return $this->entityManager->getStorage('user')->load($uid);
       }
       else {
         // Register a per-user failed login event.
         $this->flood->register('json_authentication_provider.failed_login_user', $flood_config->get('user_window'), $identifier);
       }
     }
   }
 }
 
 // Always register an IP-based failed login event.
 $this->flood->register('json_authentication_provider.failed_login_ip', $flood_config->get('ip_window'));
 return [];
}

Here we mostly reimplemented the authentication functionality of the basic authorization service, with the difference that we read the data from a JSON format. This code logs the user into the Drupal application. All the extra code is flood protection.

Getting the JWT token

To get the JWT token we leveraged the REST module, and created a new rest resource plugin. We could have used the endpoint the module already provides, but we prefer to create all our endpoints with a version in it. We defined the plugin with the following annotation:

/**
* Provides a resource to get a JWT token.
*
* @RestResource(
*   id = "token_rest_resource",
*   label = @Translation("Token rest resource"),
*   uri_paths = {
*     "canonical" = "/api/v1/token",
*     "https://www.drupal.org/link-relations/create" = "/api/v1/token"
*   }
* )
*/

The uri_paths are the most important part of this annotation. By setting both the canonical and the weird looking Drupal.org keys, we are able to set a fully custom path for our endpoint. That allows us to set the version of our API in the URI like this: /api/v1/token. This way we can easily roll out new versions of our API and clearly communicate about deprecating older versions.

Our class extends the ResourceBase class provided by the REST module. We only implemented a post method in our class, as we only want this endpoint to handle posts.

public function post() {
 
 if($this->currentUser->isAnonymous()){
   $data['message'] = $this->t("Login failed. If you don't have an account register. If you forgot your credentials please reset your password.");
 }else{
   $data['message'] = $this->t('Login succeeded');
   $data['token'] = $this->generateToken();
 }
 
 return new ResourceResponse($data);
}
 
/**
* Generates a new JWT.
*/
protected function generateToken() {
 $token = new JsonWebToken();
 $event = new JwtAuthIssuerEvent($token);
 $this->eventDispatcher->dispatch(JwtAuthIssuerEvents::GENERATE, $event);
 $jwt = $event->getToken();
 
 return $this->transcoder->encode($jwt, array());
}

The generateToken method is a custom method where we leverage the JWT module to get us a token that we can return. 
 
We do not return a JSON object directly. We return a response in the form of an array. This is a very handy feature of the REST module, because you can choose the formats of your endpoint using the interface in Drupal. So you could easily return any other supported format like xml, JSON or hal_json. For this example, we chose hal_json. 

Drupal has some built-in security measures for non-safe methods. The only safe methods are HEAD, GET, OPTIONS and TRACE. We are implementing a non-safe method, so we have to take into account the following things:

  • When the app does a post it also needs to send a X-CSRF-Token in the header to avoid cross site request forgery. This token can be gotten from /session/token endpoint.
  • In case of a POST we also need to set the Content-type request header to “application/hal+json” on top of the query parameter “_format=hal_json”.

Putting things together

The only thing left is to enable our endpoint through the interface that the rest modules provides on /admin/config/services/rest.

Drupal 8 & React Native - REST resources - Drupal blog

As you can see, we’ve configured our token endpoint with our custom json_authentication_provider service and it is available in hal_json and json formats.

Calling the endpoint in our React Native application

The login component

Our login component contain two input fields and a button.

<Item rounded style={styles.inputGrp}>
   <Icon name="person"/>
   <Input
       placeholder="Username"
       onChangeText={username => this.setState({username})}
       placeholderTextColor="#FFF"
       style={styles.input}
   />
</Item>
 
<Item rounded style={styles.inputGrp}>
   <Icon name="unlock"/>
   <Input
       placeholder="Password"
       secureTextEntry
       placeholderTextColor="#FFF"
       onChangeText={password => this.setState({password})}
       style={styles.input}
   />
</Item>
 
<Button
   rounded primary block large
   style={styles.loginBtn}
   onPress={() => this.login({
       username: this.state.username,
       password: this.state.password
   })}
>
   <Text style={Platform.OS === 'android' ? {
       fontSize: 16,
       textAlign: 'center',
       top: -5
   } : {fontSize: 16, fontWeight: '900'}}>Get Started</Text>
</Button>

When we click the login button we trigger the login action that is defined in our bindActions function.

function bindActions(dispatch) {
   return {
       login: (username, password) => dispatch(login(username, password)),
   };
}

The login action is defined in our auth.js:

import type { Action } from './types';
import axios from 'react-native-axios';
 
export const LOGIN = 'LOGIN';
 
export function login(username, password):Action {
 
   var jwt = '';
  
   var endpoint = "https://example.com/api/v1/token?_format=hal_json";
  
   return {
       type: LOGIN,
       payload: axios({
           method: 'post',
           url: endpoint,
           data:  {
               username: username,
               password: password,
               jwt: jwt,
           },
           headers: {
               'Content-Type':'application/hal+json',
               'X-CSRF-Token':'V5GBdzli7IvPCuRjMqvlEC4CeSeXgufl4Jx3hngZYRw'
           }
       })
   }
}

In this example, we set the X-CSRF-token fixed to keep it simple. Normally you would get this first. We’ve also used the react-native-axios package to handle our post. This action will return a promise. If you use the promise and thunk middleware in your Redux Store you can set up your reducer in the following way.

import type { Action } from '../actions/types';
import { LOGIN_PENDING, LOGOUT} from '../actions/auth';
import { REHYDRATE } from 'redux-persist/constants';
 
export type State = {
   fetching: boolean,
   isLoggedIn: boolean,
   username:string,
   password:string,
   jwt: string,
   error: boolean,
}
 
const initialState = {
   fetching: false,
   username: '',
   password: '',
   error: null,
}
 
export default function (state:State = initialState, action:Action): State {
 
   switch (action.type) {
 
       case "LOGIN_PENDING":
           return {...state, fetching: true}
 
       case "LOGIN_REJECTED":
           return {...state, fetching: false, error: action.payload}
 
       case "LOGIN_FULFILLED":
 
           return {...state, fetching: false, isLoggedIn: true, jwt:action.payload.data.token}
 
       case "REHYDRATE":
           var incoming = action.payload.myReducer
           if (incoming) return {...state, ...incoming, specialKey: processSpecial(incoming.specialKey)}
           return state
 
       default:
           return state;
   }
}

The reducer will be able to act on the different action types of the promise:

  • LOGIN_PENDING: Allows you to change the state of your component so you could implement a loader while it is trying to get the token.
  • LOGIN_REJECTED: When the attempt fails you could give a notification why it failed.
  • LOGIN_FULFILLED: When the attempt succeeds you have the token and set the state to logged in.

So once we had implemented all of this, we had an iOS and Android app that actually used a Drupal 8 site as it main content store.

Following this example, you should be all set up to deliver tailored content to your users on whichever platform they may be.

The purpose of this article was to demonstrate how effective Drupal 8 can be as a source for your upcoming iOS or Android application.
 

Useful resources:

More articles by our Dropsolid Technical Leads, strategist and marketeers? Check them out here.

Jun 20 2017
Jun 20

In a previous post, we saw the Drupal 8's new policies for versioning, support and maintenance for its minor and major versions. This policy has evolved somewhat since the last DrupalCon Baltimore conference in April 2017. And this evolution of Drupal's strategy deserves a little attention because it can bring new light to those who hesitate to migrate their site on Drupal 8. Or those who are wondering about the relevance of launching their web project on Drupal 8.

Since drupal 7 is maintained until the release of Drupal 9, the issue of waiting for Drupal 9 release can be legitimate, especially since the technological break between Drupal 7 and Drupal 8 has been consistent, we can say, with a re-writing from scratch of a very large part of its source code (~ 80%), but also at the same time a reduction of its technical debt.

And uncertainty hangs up to now on the height of the march that would be between Drupal 8 and Drupal 9. Let's face this uncertainty.

A maintenance of Drupal 8 until 2019?

The publication of the Drupal 8 road map has apparently misled some readers somewhat stunned. Indeed, the schedule published on the cycle of releases on drupal.org can sometimes be misinterpreted. So much so that now the online version of this schedule has a watermark Example only.

drupal release cycle

This diagram explains the principle of the publication cycle of the minor versions of Drupal 8, and the maintenance principles of Drupal 8 from the moment Drupal 9 will be released. This diagram does not indicate that Drupal 9 will be published 4 and a half years after the release of Drupal 8, in 2019. Note the 8.n.x of the last minor version.

And yet I could see these categorical assertions circulating:

  • Maintenance of Drupal 8 is scheduled until 2019
  • Drupal 8 will receive security maintenance only from 2020 to 2021

And this with the support of a somewhat adapted scheme (no doubt that it was misunderstood), with the addition of the years on the abscissa axis.

False release cycle drupal 8Schema modified (and skewed) of the release cycle of Drupal's major and minor versions.

To date nobody knows if the Drupal 8.4.x version will be the last minor version of Drupal 8, with the launch of Drupal 9 in 2018. In fact we are already talking about versions 8.5.x and 8.6.x currently and new additions in Drupal 8 core, whether it's the publishing process, content versioning, redesigned media management, JsonAPI integration, and so on.

No. The end of the Drupal 8 maintenance is not scheduled for 2019. In fact, to be clear, nobody knows. You can also have a Drupal 8.6.x version as the latest LTS minor version as a Drupal 8.14.x LTS version in 2022.

And if anyone dares to say otherwise to this day, then he has a vision of the future out of the ordinary, and would do well to play the Lotto right away.

Will Drupal 9 be a technological break with Drupal 8?

Drupal 8 was a real technological breakthrough. And it is understandable that some reluctance is expressed if the effort required to migrate a Drupal 8 project on the future Drupal 9 version is as important as that between Drupal 7 and Drupal 8. Given this uncertainty, we can understand that many sites on Drupal 7 can wait for Drupal 9 version, in case...

Instead of two migrations, which are not trivial for complex sites (and still it depends on the project, some Drupal 7 sites can be migrated in a few days at most), I prefer to make only one.

This is logical and understandable.

But since DrupalCon Baltimore last April, Dries Buytaert has clarified this policy on the next major versions of Drupal (see Making Drupal upgrades easy forever) and lifted this uncertainty and fear.

Migrating from Drupal 8 to Drupal 9 will be as easy as migrating from a minor version of Drupal 8 to another. In fact Drupal 9 will be neither more nor less than a new Drupal 8 lightened of all its API which will have been deprecated during its different minor versions. An image is better than all speeches.

Migration Drupal 9

The consequences of this policy with regard to the future Drupal 9 are multiple

  • For those who use Drupal 8 core, the migration to Drupal 9 will be instantaneous. In fact it will be just as simple as a minor version change.
  • The Drupal 8 contrib modules will be ~90-95% compatible with Drupal 9, or even 100% if the maintainers maintains their modules regularly and replace the deprecated functions by the new introduced APIs
  • The custom modules, developed to measure, will be compatible with Drupal 9 as well as the contrib modules

One could almost say that Drupal 9 will be the continuity of Drupal 8 with a consolidated API, refined, and purified but also with all the functional richness, at the click, introduced with all the additions that are released with the Drupal 8.x minor versions.

In fact, if we were to try to guess the date of the maintenance end of Drupal 8 today, we would just as well try to find a needle in a haystack. And even if it was found, the good deal! Drupal 9 would be an additional minor version, just a little more special. With all the ecosystem contributed modules preserved and compatible.

In other words, the compatibility of the modules is now guaranteed on the major ascending versions.

And this is very good news. No ?

Jun 20 2017
Jun 20

We teamed up with Acquia to present “A Decoupled Drupal Story: Powdr Gives Developers Ultimate Flexibility To Build Best CX Possible.” The webinar aired in June but you can view the recording here anytime.

[embedded content]

As the internet and web-connected devices continue to evolve, so do the needs to develop and render content. Given today’s rate of change, organizations are using decoupled architecture to build applications - giving them flexibility to accommodate any device or experience.

In this session, we’ll cover Powdr, a ski resort holding company. To give its developers the freedom to use the right front-end tools needed for any given use case, Powdr built its 17 ski resort websites on one decoupled Drupal platform. Join Elevated Third, Hoorooh Digital and Acquia to learn:

  • How a custom Drupal 8 solution cut implementation time in half vs Drupal 7

  • The ease in which Drupal 8’s internal REST API can be extended to fit a client's needs

  • The details of handling non-Drupal application routing on Acquia's servers

 

If you are considering a decoupled Drupal implementation, let’s talk.

Jun 20 2017
Jun 20

I'm working on a large, complex migration from Drupal 7 to Drupal 8 right now. One thing I noticed is that the migrate modules pollute the database with an unreal number of tables which allow migrations to be re-run, etc. Well if you don't need that, here's how to remove these tables. Currently the migrate modules don't clean up after themselves. Put this in a custom module or PHP script that has bootstrapped Drupal. Note this code only works in Drupal 8. Shown is a .install file for a custom module. If you uninstall the custom module, it will run the cleanup:

/**
 * Implements hook_uninstall().
 *
 * Removes stale migration configs during uninstall.
 */
function MY_MODULE_uninstall() {

  // Clean up database pollution
  $tables_to_cleanup = [
    'migrate_message_',
    'migrate_map_',
  ];

  $query = db_query('show tables;');
  $schema = $query->fetchAll();
  
  foreach ($schema as $table_name) {
    $table_name = (Array) $table_name;
    $table_name = reset($table_name);
    foreach($tables_to_cleanup as $table_to_cleanup) {
      if(strpos($table_name, $table_to_cleanup) !== false) {
        db_drop_table($table_name);
      }
    }
  }

  // Clean up old migrate configuration
  $query = db_select('config', 'c')
    ->fields('c', array('name'))
    ->condition('name', db_like('migrate_plus.') . '%', 'LIKE')
    ->execute();

  $config_names = $query->fetchAll();

  // Delete each config using configFactory.
  foreach ($config_names as $config_name) {
    \Drupal::configFactory()->getEditable($config_name->name)->delete();
  }
}
Jun 20 2017
Jun 20

The Denver Business Journal’s annual “Best Places to Work” awards wrapped up with Elevated Third landing the top spot in the “Workplace Wellness” category for small companies. The category recognizes Denver employers with an outstanding commitment to employee well-being.

 As a business practice, committing to employee wellness means that everyone is operating at their highest capacity. When our minds are fresh to focus on the task at hand, we can crank out the best work possible.

 Striking the ideal work-life balance is central to our culture. Where some agencies expect employees to work nights and weekends at the drop of a hat, we are committed to respecting employees’ time beyond the office and staying true to a 40 hour work week.

 We believe that when employees feel valued beyond the output of their work, the workplace is a more positive and productive environment.

Outside of the office, the Elevated Third team is covered with 3 weeks of Paid Time Off, a subsidized gym membership, a $1,500 Health Reimbursement Account (HRA), and an RTD ecopass. 

In the office, we are surrounded by a work environment that stimulates creativity and keeps spirits high. Office dogs can be found roaming the hallways, the kitchen is stocked with goodies of a (mostly) healthy variety, and our location on the top floor of the Denver Masonic Building provides plenty of sunlight and the occasional summer breeze.

We are incredibly proud to be recognized among Denver’s best places to work. Joining our fellow recipients, we believe this commitment to workplace wellness makes Denver a better place to live, work, and do business.

 

Interested in joining the team? Have a look at our open positions

Jun 20 2017
Jun 20

The Denver Business Journal’s annual “Best Places to Work” awards wrapped up with Elevated Third landing the top spot in the “Workplace Wellness” category for small companies. The category recognizes Denver employers with an outstanding commitment to employee well-being.

 As a business practice, committing to employee wellness means that everyone is operating at their highest capacity. When our minds are fresh to focus on the task at hand, we can crank out the best work possible.

 Striking the ideal work-life balance is central to our culture. Where some agencies expect employees to work nights and weekends at the drop of a hat, we are committed to respecting employees’ time beyond the office and staying true to a 40 hour work week.

 We believe that when employees feel valued beyond the output of their work, the workplace is a more positive and productive environment.

Outside of the office, the Elevated Third team is covered with 3 weeks of Paid Time Off, a subsidized gym membership, a $1,500 Health Reimbursement Account (HRA), and an RTD ecopass. 

In the office, we are surrounded by a work environment that stimulates creativity and keeps spirits high. Office dogs can be found roaming the hallways, the kitchen is stocked with goodies of a (mostly) healthy variety, and our location on the top floor of the Denver Masonic Building provides plenty of sunlight and the occasional summer breeze.

We are incredibly proud to be recognized among Denver’s best places to work. Joining our fellow recipients, we believe this commitment to workplace wellness makes Denver a better place to live, work, and do business.

 

Interested in joining the team? Have a look at our open positions

Jun 20 2017
Jun 20

In Drupal, many a time we come across a situation where we want to hide certain URL part from end users.

To achieve this we often use Drupal modules like Pathauto to hide node IDs, taxonomy IDs from URL and replacing them with some patterns (eg. Titles).

The above scenario can not be achieved for Drupal commerce checkout flow(URLs) as the Drupal modules like PathAuto do not support this. To achieve this in Drupal 7 we often used one of the following ways mentioned below:

In Drupal 8, At the point of writing this blog Commerce checkout paths module is yet to be ported and URL bounding hooks have been replaced by a certain way which will help us to achieve e-commerce security by hiding sensitive information from URL.

Let’s demonstrate how to achieve e-commerce security in Drupal Commerce module by the following method: 

  • Create a custom module. In my case, I will be creating a module name Example.

  • Create a example.info.yml file.

  • Create a example.services.yml file. In this file, we will be creating tagged service with tags ‘path_processor_outbound’ and ‘path_processor_inbound’. This tags will help Drupal to call this service automatically which defines the purpose of tagged services. In our case, I have created below services.yml file. 

  • Please note that we have used other namespace like 'Drupal\Core\Render\BubbleableMetadata’ and 'Symfony\Component\HttpFoundation\Request’ which are required by our interface functions.

  • In the class definition the functions:

    • processOutbound is provided by OutboundPathProcessorInterface  interface and this function behaves exactly same as hook_url_outbound_alter of Drupal 7.

    • processInbound is provided by InboundPathProcessorInterface  interface and this function behaves exactly same as hook_url_inbound_alter of Drupal 7.

So, we are ready with our module and file structure. Now in Drupal commerce, there are various checkout steps where Order ID can be seen in the URLs. Our goal is to hide this Order ID from the end user. 

Let’s understand how the Order ID encryption/decryption process will work. 

Step - 1:  Let’s say user will come to the checkout page. This checkout page URL will be pass to Drupal.

Step - 2:  Drupal will find all the tagged services in it’s database and will come across our path processor service called example.path_processor_example.

Step - 3:  This service class will receive the path URL in the $path variable of the processOutbound function. This function will help us in encrypting/hiding our order id.

Screen Shot 2017-06-13 at 7.10.22 PM.png

Please note,

  • We can use any of the encryption algorithm/business rules to encrypt our order ID in the $path variable and return it as the function output.

  • Example, The URL '/checkout/123/order_information’  will become ‘/checkout/###/order_information’.

  • The ‘###’ is the encrypted hash.

Step - 4: As the URL '/checkout/123/order_information’  has become ‘/checkout/###/order_information’, the service will also execute it’s inbound function where we can decrypt/unhide the ‘###’ and find out it’s original value(Order ID).

Screen Shot 2017-06-13 at 7.09.51 PM.png

So, this is how we can use interfaces ‘OutboundPathProcessorInterface' & ‘InboundPathProcessorInterface’ along with their functions ‘processOutbound' & ‘processInbound’ to encrypt/decrypt the URL in checkout process of Drupal Commerce module.

Hope this helps you, Please feel free to reach out to me in the case of any queries and improvements.

Jun 20 2017
Jun 20

Yesterday, Acquia open sourced Reservoir, a new distribution designed for building headless Drupal instances.  The Reservoir team provided a composer project command for setting up a Reservoir instance easily, but it doesn't bundle a VM.  Fortunately, making BLT work with Reservoir isn't difficult.  There are, though, a few steps to be aware of.

To get started, run the composer project to build a new BLT instance.

composer create-project --no-interaction acquia/blt-project MY_PROJECT

Once that completes, you need to add reservoir and (optionally) remove the lightning distro

composer require acquia/reservoir

composer remove acquia/lightning

Next, update the blt/project.yml file.  The key changes you'll want to make here (beyond setting a new project prefix, etc) are a) changing the distro from ligthning to reservoir and b) removing views_ui from the modules:enable list for local environments.*  An excerpt of my git diff for this file looks like...

profile:
-    name: lightning
+    name: reservoir
local:
-    enable: [dblog, devel, seckit, views_ui]
+    enable: [dblog, devel, seckit]

Once that's done, continue with the BLT setup process from Step 4 (assuming you want to use Drupal VM. Step 5 otherwise).

* If you don't remove views_ui, the world won't explode or anything, but when you run blt setup you'll get errors reported like the ones below:

blt > setup:toggle-modules:
    [drush] dblog is already enabled.                                                   [ok]
    [drush] The following extensions will be enabled: devel, seckit, views_ui, views
    [drush] Do you really want to continue? (y/n): y
    [drush] Argument 1 passed to                                                     [error]
    [drush] Drupal\Core\Config\Entity\ConfigEntityBase::calculatePluginDependencies()
    [drush] must implement interface
    [drush] Drupal\Component\Plugin\PluginInspectionInterface, null given, called
    [drush] in /var/www/mrpink/docroot/core/modules/views/src/Entity/View.php on
    [drush] line 281 and defined PluginDependencyTrait.php:29
    [drush] E_RECOVERABLE_ERROR encountered; aborting. To ignore recoverable         [error]
    [drush] errors, run again with --no-halt-on-error
    [drush] Drush command terminated abnormally due to an unrecoverable error.       [error]
[phingcall] /Users/barrett.smith/Desktop/mrpink/./vendor/acquia/blt/phing/tasks/setup.xml:370:8: /Users/barrett.smith/Desktop/mrpink/./vendor/acquia/blt/phing/tasks/setup.xml:374:12: /Users/barrett.smith/Desktop/mrpink/./vendor/acquia/blt/phing/tasks/setup.xml:377:69: Drush exited with code 255
[phingcall] /Users/barrett.smith/Desktop/mrpink/./vendor/acquia/blt/phing/tasks/setup.xml:350:45: Execution of the target buildfile failed. Aborting.

BUILD FAILED/Users/barrett.smith/Desktop/mrpink/./vendor/acquia/blt/phing/tasks/local-sync.xml:12:30: Execution of the target buildfile failed. Aborting.
; 2 minutes  37.24 seconds

Jun 20 2017
Jun 20

This guest blog post is from Drupal Moldova's Association (not affiliated with Drupal Association). Get a glimpse of what is happening in Moldova's community and how you can get involved.

Drupal Moldova Association’s mission is to promote Drupal CMS and Open Source technologies in Moldova, and to grow and sustain the local community by organising Events, Camps, Schools, Drupal meetups and various Drupal and Open Source related trainings, and by establishing partnerships with Companies, the Government, and NGO’s.

Come and share your expertise in Moldova at our events! We're looking for international speakers to speak about Drupal and open source.

Among DMA’s (short for Drupal Moldova Association) numerous commitments, the following are of special importance:

  • to gather the community around Drupal and Open Source technologies;

  • to train students and professionals who want to learn and work with Drupal;

  • to organise events to keep the community engaged and motivated to improve, learn, and share experience;

  • to make sure Drupal is accessible to everyone by offering scholarships to those who can't afford our programs;

  • to elaborate a well defined program that helps students learn Drupal, acquire enough knowledge to get accepted for internships by IT companies, and be able to build Drupal powered websites;  

  • to assist new IT companies in establishing a local office, promote themselves, collaborate with other companies, and connect with the local Drupal community by giving them the opportunity to support our projects.

Over the last 5 years, we have been dedicated to achieving our goals! DMA have organized over 20 projects and events, including Drupal Global Training Days, Drupal Schools, and the regional DrupalCamp -- Moldcamp. Our projects have gathered over 700 local and international participants and speakers, and more than 15 International Companies that have supported us during these years (FFW, Adyax, IP Group, Intellix, Endava and many others).

Moldova is rich in great developers and people driven to take initiative and to grow and place the country on the world map. We are aiming to go beyond our limits and have a bigger impact in the year (‘17-’18), therefore we have created a yearly plan that contains projects similar to those we have done in the past years, as well as new and exciting ones:

  • Drupal School (3 step program), starting with Drupal School 8 plus PHP (step 1):  Drupal School is an educational program - split into 2 months, 25 courses of different levels (Beginner, Intermediate, Advanced).Drupal School aims to introduce people to Drupal 8 and PHP, and help them become Drupal professionals;

School of Drupal 8 group photo from Facebook

  • Moldcamp 2017: Sep - Oct 2017. A regional DrupalCamp that gathers around 150 Drupal professionals, enthusiasts, beginners and any-Drupal-related-folk in one place for knowledge-sharing, presentations, networking, etc. We will announce the event soon and allow speaker registration. Please follow us and don’t miss out on the opportunity;

Mold Camp speaker at blackboard

Mold Camp attendees at table

Global Training Day presenter

  • Drupal Meetups: These are organized each month and they allow our community to be active and share knowledge.

  • Tech Pizza: - Jun, Aug, Oct, Dec. A bi-monthly event, where the ICT community can gather in a casual and an informal environment around a pizza and  soda and discuss the latest IT trends and news. The core of this event is a speaker / invitee from abroad with a domain of expertise;

  • Moldova Open Source Conference: March 2018. It is a regional conference for over 200 participants that aims to gather all the Open Source Communities (Wordpress, Laravel, Ruby on Rails, JavaScript, etc.) under one roof, where they will attend sessions that enhance the expertise of existing experts in various Open Source technologies and allow them to mix their technologies into new ideas.

The proposed program “Drupal and Open Source in Moldova 2017 - 2018” is made possible through the support of USAID and the Swedish Government. Thanks to these organizations we can focus on the quality of our projects make sure they happen as planned. Also, we have a very important partnership with Tekwill / Tekwill Academy, which helps us even more in our quests.

School of Drupal 8 + PHP promotional page

We start with School of Drupal 8 plus PHP program, which will be held on 19th of June 2017. So far we have 3 sponsors--IPGroup, Adyax and Intellix--and two trainers.

We, The DMA, believe in pushing the limits! Our long term goal is to build and maintain big an active Open Source community by attracting more local and International participants to our Projects and Events, and continuously improve our sessions. This will make our presence felt in the global Drupal and Open Source communities and markets. Find us on Twitter @drupalmoldova, or on our Facebook page. If you are interested in speaking in Moldova, contact us at info@drupalmoldova.org.

Jun 20 2017
Jun 20
One of the more interesting products to hit the spotlight at this year's Percona Live Open Source Database conference was ProxySQL.This open source MySQL proxy server has been around for a couple of years now and keeps adding more features. The current release (1.3.6) has the usual features that you would expect from a proxy server, like load balancing and failover support, but ProxySQL also has database specific features like a query cache and query routing.
Jun 20 2017
Jun 20

DrupalCon Vienna will be taking place end of September this year. The site building track is about letting Drupal do the hard work without needing to write code. By assembling the right modules and configurations we can create rich and complex features, without worrying about reinventing the wheel and write complex logic and code.

Sounds great, right? As excited as I am for helping to put together the program for the site building track, I would like to share a few session ideas, which might be worth submitting. If you have never submitted a session for DrupalCon, this might be a good opportunity to give it a try:  

Showcases will let others learn from how you built your last exciting Drupal 8 project. Talking points can include which approaches you took, lessons you learnt from working on the project, and what fellow site builders should know when tackling similar problems.

Module presentations are a great way to explain and highlight best practice solutions. How do you choose from the various competing site building tools available to address problems like layout management, workflows or content modelling? Are the same solutions from Drupal 7 still valid, or what are the latest experiences you've had whilst building Drupal 8 sites and how could this be further developed and enhanced in the future?

Process descriptions are welcome to help us figure out how site building can best fill the gap between end users, content editors, developers, UX designers and anyone else involved in Drupal web projects. How do you involve your customers and explain site building to them? What does a developer need from a site builder and where do those practices blend? 

Outside perspectives are also welcomed to learn how problems can be solved the site builder’s way in related web technologies.

Together with Hernâni Borges de Freitas and Dustin Boeger, we are looking forward to reviewing your exciting and interesting applications. If you aren’t sure what to present, feel free to get in touch via the contact form on my Drupal.org profile or Twitter.

Thanks for submitting your session by June 28, 23:59 CEST.

Jun 20 2017
Jun 20

TL;DR: Define a schema for any bespoke configuration, it's not too hard. It's needed to make it translatable, but Drupal 8 will also validate your config against it so it's still handy on non-translatable sites. As a schema ensures your configuration is valid, your code, or Drupal itself, can trip up without one.

Recently I updated a simple configuration setting via some PHP code, and Drupal immediately threw up an obscure error. It turned out to be because the custom setting that I updated didn't have a configuration schema.

Schemas are used to instruct Drupal 8 what format every piece of a configuration object should be in. For example: text, integers, an array mapping, etc. That means they can be used to validate configuration, keeping your code and Drupal's handling of the settings robust and predictable. It also allows the configuration to be translated, but that wasn't on my radar for this particular project.

If you're aware of the variable module for Drupal 7, then you can think of configuration schemas as the equivalent of hook_variable_info(), but written in YAML.

Here's an example of the sort of thing that's needed, to go in my_module/config/schema/my_module.schema.yml:

my_module.settings:
  type: config_object
  label: 'My custom settings'
  mapping:
    message:
      type: text
      label: 'Message to display on page XYZ'
    some_setting:
      type: 'integer'
      label: 'Behave differently when this is 0, 1, or 2'

The pragmatic reality is that you may well get away fine without giving your configuration a schema. But you may also run into obscure issues like I did without one, which are very hard to understand. I could get around the problem by skipping the validation by passing the 'has_trusted_data' parameter to my $config->save() call as TRUE. Clearing caches may also resolve your problem.

But ultimately, those workarounds just plaster over the cracks. Set up a schema and you avoid those problems, and get robust validation for free. Hopefully my example YAML above shows how it can be quite simple to do.

Jun 20 2017
Jun 20

Around two years ago, when the launch of Drupal 8 was just around the corner and the main topic of concern was the status of the issue queue (the number of open issues, issue priority, etc), the Drupal community slowly started murmuring about a topic outside of technical solutions and patches. The time we spent working on Drupal 8 was certainly long, and in talking about the state of the project, contributors became stressed out and tired from the pressure that the workload and demand put on them. It started at DrupalCon Barcelona in 2015, where Mike Bell held an honest and wonderfully open keynote about Mental Health and Open Source, where he broke the silence about how psychological health affects work in open source. I was there in Barcelona when Mike stepped on stage and started telling his story, and I was deeply touched by it.

I remember sitting there and listening to him, and I couldn’t stop thinking about how brave he was for telling such a private story, and how hard it must have been for him. I realized that I had never seen anyone in the community open up this much about this topic, especially not in such a public setting.
His talk opened a door and, as a result, many people in the community started talking about their own struggles and feelings. It became clear that this was a huge concern within the community, and it was necessary to discuss these things, so that the humans behind the accounts of tireless and dedicated contributors could be revealed, appreciated, and cared for. 
 
One wonderful result of this movement towards openness was a brand new DrupalCon track. Thanks to an initiative driven by Emma Karayiannis, Being Human made its debut at DrupalCon Dublin in 2016, and was continued in Baltimore earlier this year and will take session slots at the DrupalCon in Vienna this September as well. The track was extremely well received, as it provides a great opportunity for everyone to come forward, talk about their experiences in the journey of working with others, of working with open source, and last but definitely not least, to share stories about how they overcame their personal challenges, how they make decisions, and how they take care of themselves and others.
 
In mid May, I received an email from Amanda from the emails, from the Drupal Association, and my heart stopped for a second - she asked if I was interested in being on the Track Team of Being Human as the local track chair, working with Emma Karayiannis, who is the creator of the track, and is truly someone I look up to, and Juan Olalla, who I was really happy to meet in Prague last year, and who is a great partner in crime in all this.
I was honestly surprised and felt so grateful to even be considered as a candidate for this position. So, because I personally find this topic extremely important and useful, I said yes. After organizing two Drupal camps in 2016 (Drupalaton and Drupal Iron Camp), being involved in various community activities, succeeding in my full-time job, and of course trying to live my private life, at the beginning of this year I really understood what it means to burn out, and I started to make the first steps towards recovering from that.
 
I personally believe that talking about our struggles, hearing about how others deal with theirs, and asking for help, whether it’s about personal, community-related, or team/work-related issues, is extremely important and can be very helpful for all of us. No matter if we are freelancers or work with larger teams, if we are project managers, or site builders, or developers, if we already contribute to the project, or we are just figuring out how to contribute, we are all human. 
 
The Being Human track at DrupalCon Vienna is designed to be a way of supporting each other, not from a technical or knowledge-based approach, but from a very personal perspective. We expect people from all around the world (not only from Drupal, but from outside this community as well) to share their experiences and tell their stories about various interesting and exciting topics. 
 

We are looking forward to hear:

  • advice and knowledge on successful ways of working and collaborating with others. 
  • views on how we can provide and maintain a safe, welcoming, empowering, and inclusive community for everyone. 
  • experiences with mental health issues, and how we can support ourselves, those around us, and the community at large.

Submit your session today!

Here are the talk topic keywords (if you still would like to hear more):

  • Collaboration, productivity, team management, conflict, effective communication, empathy.
  • Diversity, inclusion, culture, values, ethics, safe environment, community building, contribution, support, mentorship.
  • Mental health, physical health, impostor syndrome, burnout, work/life balance, failure, asking for help, fear, mindfulness, happiness, procrastination.

 
If you feel that you have something to say about any of these topics, or you have something new that we should include this time, I would like to ask you to submit a session proposal. 
The deadline of Call for Papers is June 28, 23:59 Vienna time (UTC+2, EST/UTC-5). Decisions about the selected sessions will be posted by August 1. 
 
Looking forward to hearing from you! If you have any questions about your ideas in mind, feel free to reach out to me via my drupal.org profile or on Twitter.
 

Jun 20 2017
tim
Jun 20

On 28th June (23:59 Vienna local time (GMT +2)) session submissions will close for DrupalCon Vienna 2017 and we're looking for more great speakers.

After volunteering on the Core Conversation track team last year, I am now helping the PHP track team find and select sessions for this year's European conference. As PHP the foundation for Drupal it's great to hear speakers talk about related trends, best practices, and tools. Since the release of Drupal 8 we have "got off the island" and started using components from other platforms and frameworks, and embraced things like Composer, PHPUnit, and PSR. These changes have made the PHP track more important than ever.

As you'll see in the track description we're looking for sessions in three main topic areas.

  • Tools - Are you a PHPStorm ninja? a debugging master? or have the perfect dev environment?
  • Libraries - We can pull in libraries with Composer, and abstract things into libraries. Can you speak to this?
  • Testing - PHPUnit is the way forward. What have you been doing with it? How do you fully test your code? 

If you have an idea for a session please submit it and I look forward to seeing you there.

Jun 20 2017
Jun 20

Last time, we gathered together DrupalCon Baltimore sessions about Front End. Before that, we explored the area of Site Building, Drupal Showcase, Coding and Development, Project Management and Case Studies. And that was not our last stop. This time, we looked at sessions that were presented in the area of DevOps.

100% Observability by Jason Yee from Datadog

In this session, the author broke down the expansive monitoring landscape into 5 categories and provided a framework to help users ensure full coverage. He also touched why these categories are important to users business and shared the top criteria to consider when evaluating the options.

[embedded content]

Automatic Drupal Updates using Visual Regression & Continuous Integration by Matt Cheney and Andrew Taylor from Pantheon

This session presented how to use a Continous Integration and Visual Regression solution to update a Drupal site. It seems easy at first, but when it goes down to updating, that's hard work, because you need to apply updates, test updates, and deploy updates.

[embedded content]

Avoid DEEP HURTING! Deployment beyond git by TEN7

In this session, the TEN7 team introduced how to augment the deployment with Ansible, laying the foundation to fully automate users' deployments with free and open source software.

[embedded content]

Basic DevOps Skills: Where to Start and How to Learn by Michelle Krejci from Pantheon Systems

This session started with some collective hand-wringing about what “devops” is and then decided that it is a set of skills and processes that are worth developing. Then, the author got into what is worth attendees' time and what is not (Continuous Integration ...).

[embedded content]

Be A Developer Experience Super Hero: Robust Dev Scripts For Peace and Joy from Dustin LeBlanc from Pantheon

This session covered a lot of rather advanced topics including containerization, continuous integration, and automated testing. Listeners must have familiarization with Docker, common PHP testing frameworks, and how continuous integration platforms work.

[embedded content]

Build & Launch Tools: Automating best practices for enterprise sites by Matthew Grasmick from Acquia

In this session, the attendees learned how to create a new BLT-powered Drupal 8 site, how to quickly spin up a Drupal VM, how to automate the local install process, how to validate their custom code (linting and sniffing), how to execute Behat and PHPUnit tests, and how to generate a sanitized deployment artifact.

[embedded content]

Captaining a container ship: Docker orchestration with Kontena by Jochen Lillich from freistil IT

In this session, the author introduced Kontena, an orchestration tool that lets you level up from plain Docker without spending days reading and banging your head on the desk.

[embedded content]

Death Star Security - Maintaining Agility and Security in Clustered Deployments by Chris Teitzel from Cellar Door Media and David Strauss from Pantheon

This session was for projects and teams of all sizes. It was an interactive time filled with lessons learned and examples from the real world. If you find yourself wiring together everything from Varnish to Apache to MySQL to Solr to backup storage (and especially if you're looking for answers better than just throwing it all behind the main firewall), then you have to know how to do the security part properly.

[embedded content]

Docksal: Better than VMs by Leonid Makarov from FFW

In this session, attendees learned more about the basics of using Docker for local development, comparing the Docker -based vs the VM-based approach, getting over the pain points that Docksal eliminates, initializing instant environments with zero configuration, getting a Drupal7 and a Drupal8 site running side by side using different stack versions, seeing how Docksal can be integrated into an existing project and the last, they saw some more advanced use case supported in Docksal (e.g. complex, production-like stacks).

[embedded content]

Implementing Full Stack Test Automation for Drupal 8 - From Unit to Acceptance Tests by Anastasios Daskalopoulos from Exove

In this sessions, the author discussed test-driven Development, unit test generation and execution in Drupal 8, functional test automation tools and acceptance test automation.

[embedded content]

Incident Command: The far side of the edge by Lisa Phillips from Fastly

In this session, Lisa Phillips from Fastly presented how Incident Command was conceived, and the protocols that were developed within Fastly to make it work. She shared a number of war stories that illustrated how Incident Command contributed to protecting Fastly as a company, its customers, and the many end users relying on the service. Examples included a major software vulnerability that affected a Linux component in common use across Fastly, as well as a large Distributed Denial of Service attack.

[embedded content]

Predictable Continuous Deployment: Value, Culture & Tools by Andrew Kucharski and Johnnie Fox from Promet Source

This session started with discussing why the company decided to make the investment and what are the benefits of being able to deploy with confidence. The authors touched on "configuration management" and talked through their lessons learned (Chef, Ansible), took the attendees through several iterations of their build scripts (briefly touching on Composer) for both D7 and D8. Moreover, they tackled "continuous integration" with Jenkins (vs. Travis CI) and other scroptis. They presented how they've managed to deploy to different target environments such as Pantheon, Acquia, AWS, Rackspace etc. In the end, they touched their journey of automated testing from Behat to the Robot framework.

[embedded content]

The future of Monitoring is now with Sensu by Howard Tyson from Zivtech

In this session, the author looked at how sensu is architected and how it removes the pain wrought by its predecessors. He reviewed writing simple plugins to monitor their own services and how everybody can connect sensu to a graphing service like graphite or influxdb and graphana to monitor the same metrics everybody are using for alerting.

[embedded content]

This is not a test: What you should know about containers by Michael Schmid from Amazee Labs

This session explained what makes containers so exciting and why they are seen as a revolution in computing, what new possibilities containers open up (for Drupal, for local Development, for automated Testing), why people are still hesitant on running containers in Production and where containers will bring us in the future.

[embedded content]

¡Viva la Revolución!- How to Start a DevOps Transformation at your Workplace by Amin Astaneh from Acquia

This presentation gave attendees an access to the tools and knowledge to start their own DevOps transformation where they work.

[embedded content]

Jun 19 2017
Jun 19

Drupal Commerce and Square

Square's pitch is pretty straightforward: accept payments anywhere, no coding required. They nailed this first through their simple phone based card readers and their slick in-store tablet interface. They also made it easy to process all major credit cards, guaranteeing deposits as soon as the next business day.

They're now rolling out their same great support for merchants online with the steady release of open APIs for eCommerce applications. With our recently released Commerce Square module for Drupal 7 and Drupal 8, you can now pitch Drupal Commerce to existing Square customers in your area.

Thus far we integrate their payment APIs for full checkout and administrative support in Commerce 1.x and 2.x. We're working with Square to integrate new APIs as they become available in pursuit of our vision to enable the turnkey creation of online stores for Square merchants using Drupal Commerce.

Among the module's primary benefits, especially when used in conjunction with Square for retail sales, are:

  • You can sell online, and in person, with all of your sales in one place. Integrating your physical and online retail operations will ultimately simplify the management of your business.
  • Accept all major cards, (including Apple Pay and Android Pay in-store) and pay one simple rate per tap, dip, or swipe. (Note: Square also offers custom rates for qualifying stores processing over $250k annually.)
  • Integration is simple and seamless for Drupal Commerce on both Drupal 7 and Drupal 8. (Look for new features to come into the D8 branch first and be backported, as additional contributed modules may be required to make up for core features that were added in Commerce 2.x.)

Square’s eCommerce API is on the bleeding edge of integration technology, making PCI compliance easy; customer credit card information never touches your website, so you don’t need to worry or complete a single checklist. Each component of the payment method form is an embedded iframe hosted on Square's server and returns a payment token identifier used to capture payment. We actually designed the Commerce 2.x checkout form to treat these types of payment methods as first class citizens, so expect the integration to just work.

Sign up for Square and get free processing on your first $5,000 in sales.

As part of our module launch effort, Square has teamed up with us to offer free processing on your first $5,000 in sales. If you or one of your customers are interested in learning more, review the offer details here and hit us up in the issue queue if you run into any problems!

Jun 19 2017
Jun 19
Decoupling Drupal can be arduous, whether you're developing a Drupal-backed front end or configuring Drupal to be an ideal content repository for decoupled applications.Adding to the challenge is the fact that there is a lack of definitive starting points, boilerplates, and best practices. But the issue isn't simply that there are so many competing approaches; it's also that there doesn't yet exist an easy starting point for non-Drupal developers who solely want to configure Drupal to be the back end for their front-end applications and get on with development.
Jun 19 2017
xjm
Jun 19

Start: 

2017-06-21 12:00 America/New_York

Organizers: 

Event type: 

Online meeting (eg. IRC meeting)

The monthly security release window for Drupal 8 and 7 core will take place on Wednesday, June 21.

This does not mean that a Drupal core security release will necessarily take place on that date for any of the Drupal 8 or 7 branches, only that you should watch for one (and be ready to update your Drupal sites in the event that the Drupal security team decides to make a release).

There will be no bug fix or stable feature release on this date. The next window for a Drupal core patch (bug fix) release for all branches is Wednesday, July 05. The next scheduled minor (feature) release for Drupal 8 will be on Wednesday, October 5.

For more information on Drupal core release windows, see the documentation on release timing and security releases, and the discussion that led to this policy being implemented.

Jun 18 2017
Jun 18
Recently I set out to make a simple instrument for running simpletest tests without having LAMP stack installed on your local environment. I needed this for two reasons:
  1. for running tests locally
  2. for running tests on CI server
I've decided to use Docker and create monolith container with Drupal and all the LAMP stuff inside and here what I've got: docker-tester.


How to use


Before running container you have to setup next ennvironment variables:
  1. KEEP_RUNNING - specify  yes  if you want to keep container running when tests will be executed. Use for debugging purposes only. Default value is  no .
  2. DRUPAL_VERSION - specific version of Drupal. Supported Drupal 7 and Drupal 8. Example:  8.3.2 .
  3. MODULES_DOWNLOAD - a list of modules to download (by Drush) separated by comma. Example:  module_name-module_version,[...] .
  4. MODULES_ENABLE a list of modules to enable (by Drush) separated by comma. Example:  module_name,[...] .
  5. SIMPLETEST_GROUPS - a list of simpletest groups to run separated by comma. Example:  Group 1,[...] .
  6. SIMPLETEST_CONCURRENCY - amount of test runners to test code in parallel. Default value is  1 .
Then you need to build an image for container:
docker build -t drupal-tester .
Next you have two options: either run container with docker-compose tool or run container manualy with docker command.
For local usage I prefere to use docker-compose because it's easier than write all the CLI docker command manualy. Just specify what module you want to test inside of docker-compose.yml file and run:
docker-compose up && docker-compose down
It will run the container, install Drupal inside of it and run tests. That's all.

For running tests on CI server I use docker command and specify all the needed environment variables manualy:

docker run -v $(pwd)/test_results:/var/www/html/test_results -v $(pwd)/custom_scripts:/var/www/html/custom_scripts -e KEEP_RUNNING=no -e DRUPAL_VERSION=8.3.2 -e MODULES_DOWNLOAD=module-version -e MODULES_ENABLE=module -e SIMPLETEST_GROUPS=module_test_group -e SIMPLETEST_CONCURRENCY=1 drupal-tester
It allows you to override environment variables and volumes that you want to mount inside of the container. So you can setup different jobs on your CI server to test different modules on different Drupal versions with the help of this one container.

When docker finished the process all test results by default will be placed into test_results directory but you can easily override this by mounting some other directory inside of a container.

Setup and customization


Sometimes you need to do something before running tests. For example override some module specific settings or setup some Drupal variables etc. You can get it done with custom *.sh scripts. Just write sh file with all needed actions/commands and put it inside custom_scripts folder. All the files inside of this directory will be executed before running tests.
Jun 17 2017
Jun 17

Since the release of Drupal 8 with a standardized way of managing translations, many sites running Drupal 7 are making a switch to Drupal 8. In Drupal 7 there are two ways to translate content:

  1. Using the content_translation module. The D7 core way of translating content, where every translation is a separate node.
  2. Using the entity_translation module. Maintains one node with a unique nid, while translations take place at the field level.

In this article we will discuss how to migrate content translations created with the content_translation module from Drupal 7 to Drupal 8. You can find our tutorial about migrating translations that use Entity Translation here.

This article would not have been possible without the help of my colleague Dave. ¡Gracias Dave!

The problem

We have a Drupal 7 database containing article nodes, which might have translations in English, Spanish and French. Some of these nodes are language-neutral, i.e. non-translatable. Our target is to migrate the Drupal 7 nodes into a Drupal 8 website, preserving the translations.

Before we start

  • Since this is an advanced migration topic, it is assumed you already know the basics of migration. If are new to migrations in Drupal 8, I recommend that you read about migrating basic data to Drupal 8 first.
  • If you'd like to run the migrations in this example yourself, see the quick-start documentation in our drupal migration i18n example repository.
  • The source website used in this example is Drupal 7.54.
  • The destination website used in this example is Drupal 8.3.x. However, an alternative solution for earlier versions is included towards the end of the article.

The module

To write the migrations, we create a module - in our case, migrate_example_i18n. There's nothing special about the module declaration, except for the dependencies:

  • migrate_plus and migrate_tools provide various features for defining and executing migrations.
  • migrate_source_csv: Will be used for demonstrating migration of translated content from non-Drupal sources in an upcoming article.
  • migrate_drupal: This module provides tools for migrating data from older versions of Drupal. It comes with Drupal 8.x core. Since this migration uses a Drupal 7 site as a source for its data, we need the migrate_drupal module.

How do translations work?

Before jumping into writing these migrations, it is important to mention that Drupal 7 and Drupal 8 translations work very differently. Here's the difference in a nutshell:

  • Drupal 7: When we translate a node, a new node is created with a different ID. This translated node has a property named tnid, which stores the ID of the original node, linking the two nodes together. For language-neutral or untranslated content, the tnid is set to 0.
  • Drupal 8: When we translate a node, no new node is created! The translation is saved in the fields of the original node, but with a different language code.

So just like we do when migrating translated content from Drupal 6 to Drupal 8, we create two migrations:

  • The example_dog_base migration will migrate the original content of each node, untranslated.
  • The example_dog_i18n migration will migrate only translations and associate them with original content created by example_dog_base.

We group the two migrations using the example_dog migration group to keep things clean and organized. Then we can execute both migrations with drush migrate-import --group=example_dog --update.

Step 1: Base migration

We start with example_dog_base to migrate all base data or non-translations. Described below are some noteworthy parameters:

Source

source:
  plugin: d7_node
  node_type: article
  key: drupal_7_content
  constants:
    uid_root: 1
    node_article: 'article'
  • plugin: Since we want to import data from a Drupal installation, we need to set the source plugin to d7_node. The d7_node source plugin is introduced by the migrate_drupal, module and it helps us read nodes from a Drupal 7 database without having to write queries manually. Since Drupal 8.3.x, this plugin supports translations created with the content_translation module. If you are using an older version of Drupal 8, then check the alternative solution provided towards the end of this article.
  • node_type: This tells the source plugin that we are interested in just one particular Drupal 7 node type, namely article.
  • key: Our Drupal 7 data doesn't come from our main Drupal 8 database - instead it comes from a secondary database connection. We choose a key to identify each such connection and we need to tell the source which such key to use. The keys themselves are defined in the $databases variable in our settings.php or settings.local.php. See the example settings.local.php file to see how it's done.
  • constants: We define some hard-coded values under this parameter.
  • translations: Notice there is no translations parameter here. The default value (false) tells the source plugin that we're only interested in migrating non-translations, i.e. content in the base language and language-neutral content.

Destination

destination:
  plugin: 'entity:node'
  • plugin: Since we want to create node entities in Drupal 8, we specify this as entity:node. That's it.
  • translations: Again we do not define the translations parameter while migrating base data. Omitting the parameter tells the destination plugin that we are interested in creating fresh nodes for each record, not translations of existing nodes.

Process

type: constants/node_article
langcode:
  plugin: default_value
  source: language
  default_value: und
uid: constants/uid_root
title: title
body: body
field_one_liner: field_one_liner
sticky: sticky
status: status
promote: promote

This is where we map the old node properties to the new node properties. Most of the properties have been assigned as is, without alteration, however, some noteworthy properties have been discussed below:

  • nid: There is no nid parameter here, because we don't care what nid each new node has in Drupal 8. Drupal can just assign a new nid to each node in the normal way.
  • type: We specify that we want to create article nodes.
  • langcode: The langcode parameter was formerly language in Drupal 7, so we rename it here. Also, if a Drupal 7 node is language-neutral, the language property will have no value. In that case,  we default to und.

This takes care of the base data. If we run this migration with drush migrate-import example_hybrid_base --update, all Drupal 7 nodes which are in base language or are language-neutral will be migrated into Drupal 8.

Step 2: Translation migration

We are halfway through now! All that's missing is migrating translations of the nodes we migrated above. To do this, we create another migration with the ID example_dog_i18n:

source:
  plugin: d7_node
  node_type: article
  translations: true
  # ...
destination:
  plugin: 'entity:node'
  translations: true
process:
  nid:
    plugin: migration
    source: tnid
    migration: example_dog_base
  langcode: language
  # ...
migration_dependencies:
  required:
    - example_dog_base
  • source:
    • translations: We set this to true to make the source plugin read only translations.
  • destination:
    • translations: We set this to true to make the destination plugin create translations for existing nodes instead of creating fresh new nodes.
  • process:
    • nid: In this case, we do care what the Drupal 8 nid is for each node. It has to match the nid for the untranslated version of this content, so that Drupal can add a translation to the correct node. This section uses the migration (migration_lookup) process plugin to figure out the right nid. It tells Drupal to check the previously-executed example_hybrid_base migration for a D6 node that has the same tnid as this D6 node. It will then then reuse the resulting nid here.
    • langcode: We define the language in which the translation should be created.
  • migration_dependencies: Since we cannot add translations to nodes that do not yet exist, we tell Drupal that this migration depends on the base migration example_dog_base. That way, the base migration will run before this migration.

That's it! We can run our translation migration with drush migrate-import example_dog_i18n --update and the translations will be imported into Drupal 8. Alternatively, we can use the migration group we defined to run both these migrations at once - the base migration will automatically be executed first and then the i18n migration. Here's how the output should look:

$ drush migrate-import --group=example_dog --update
Processed 7 items (7 created, 0 updated, 0 failed, 0 ignored) - done with 'example_dog_base'
Processed 7 items (7 created, 0 updated, 0 failed, 0 ignored) - done with 'example_dog_i18n'

You can check if everything went alright by clicking the Translate option for any translated node in Drupal 8. If everything went correctly, you should see that the node exists in the original language and has one or more translations.

Article migrated from Drupal 7 to Drupal 8Article migrated from Drupal 7 to Drupal 8

Alternate Solution for Drupal 8.2.x and Older

The example code for this article works out of the box with Drupal 8.3 or higher. However, it will not work with earlier versions of Drupal 8. For Drupal 8.2 or older, we need to use a custom source plugin (inspired by the d6_node plugin). All we have to do is use the D7NodeContnentTranslation source plugin included in the code for this example, like source: d7_node_content_translation. This custom source plugin adds support for the translations parameter, which in turn makes the migration of content translations work correctly.

Next Steps

Jun 17 2017
Jun 17

Since the release of Drupal 8 with a standardized way of managing translations, many sites running Drupal 7 are making a switch to Drupal 8. In Drupal 7 there are two ways to translate content:

  1. Using the content_translation module. The D7 core way of translating content, where every translation is a separate node.
  2. Using the entity_translation module. Maintains one node with a unique nid, while translations take place at the field level.

In this article we will discuss how to migrate content translations created with the entity_translation module from Drupal 7 to Drupal 8. You can find our tutorial about migrating translations that use Content Translation here.

This article would not have been possible without the help of my colleague Dave. Merci Dave!

The problem

We have a Drupal 7 database containing article nodes, which might have translations in English, Spanish and French. Some of these nodes are language-neutral, i.e. non-translatable. Our target is to migrate the D7 nodes into a D8 website, preserving the translations.

Before we start

  • Since this is an advanced migration topic, it is assumed you already know the basics of migration. If you are new to migrations in Drupal 8, I recommend that you read about migrating basic data to Drupal 8 first.
  • This article assumes that you have read our previous article on how to migrate content translations from Drupal 7 to Drupal 8 or have the relevant knowledge.
  • To execute the migrations in this example, you can download the drupal migration i18n example repository from GitHub. The module should work without any trouble for a standard Drupal 8 install. See quick-start for more information.
  • To see the example migrations in action, you need:
    • A Drupal 8 site.
    • The relevant D7 database, since we are migrating data from a Drupal 6 site.
    • Drush will be required to execute migration commands.

The module

To write the migrations, we create a module - in our case, it has been named migrate_example_i18n. Just like migrating content translations from D7 to D8, we create 2 YML files to define:

  • The example_creature_base migration will migrate all base data or non-translations.
    • The source/translations parameter is omitted or set to false.
    • The destination/translations parameter is omitted or set to false.
  • The example_creature_i18n migration will migrate all translations.
    • The process/nid is configured to use the migration plugin to lookup the node in the base language.
    • The source/translations parameter is set to true.
    • The destination/translations parameter is to true.
    • The migration_dependencies parameter declares example_creature_base as a dependency.

We group the two migrations using the example_creature migration group to keep things clean and organized. Then we can execute both migrations with drush migrate-import --group=example_creature --update.

How to migrate Entity Translations?

Entity translations! Drupal 7 content translations are supported since Drupal 8.3. At the point of writing this, there is no standard method for migrating entity translations to Drupal 8. In this example, we will migrate D7 nodes translated with the entity_translation module, however, the procedure should be similar for other entity types as well. Before we start, here are some notes about what's so different about entity translations:

  • All translations have the same entity_id. So, for a translated node, the entity_translation module will result in only one entry in the node table.
  • Translation information, certain metadata and revision information for entities is stored in the entity_translation table.

So if an English node with ID 19 has translations in Spanish and French, the entity_translations table has the following records:

An extract from the entity_translation table. entity_type entity_id revision_id language source uid status translate created changed node 19 1 en   1 1 0 1485800973 1487198982 node 19 1 es en 1 1 0 1485802336 1487199003 node 19 1 fr en 1 1 0 1487185898 1487198969

The above data structure is significantly different from the content translation structure. In fact, Drupal 8 handles translations much like the entity translation module! Hence, to handle entity-translations, we must take the entity_translation table into consideration, which the core d7_node source plugin does not do at the time of writing this article. Hence, we override the d7_node source with a custom source plugin named d7_node_entity_translation.

This is where we jump into code! We override certain methods of d7_node source to add support for the entity_translation table.

class D7NodeEntityTranslation extends D7Node {
  // Determines if the node-type being translated supports entity_translation.
  protected function isEntityTranslatable() {}
  // Depending on the "source/translations" parameter, this method alters
  // the migration query to return only translations or non-translations.
  protected function handleTranslations(SelectInterface $query) {}
  // This method has been overridden to ensure that every node's fields are
  // are loaded in the correct language.
  public function prepareRow(Row $row) {}
  // This method is called by the prepareRow() method to load field values
  // for source nodes. We override this method to add support for $language.
  protected function getFieldValues($entity_type, $field, $entity_id, $revision_id = NULL, $language = NULL) {}
  // Since all source nodes have the same "nid", we need to use a
  // combination of "nid:language" to distinguish each source translation.
  public function getIds() {}
}

Here's a quick look at the changes we need to make:

  • function getIds() tells the migrate API to use one or more source properties which should be used to uniquely identify source records. When working with entity translations, all translations have the same entity_id, but they have a different language. We override this method to tell Drupal to consider both the entity_id and the language properties to uniquely identify source records. So, the source records are uniquely identified something like 19:en, 19:es, 19:fr instead of using just 19.
  • function handleTranslations() is the method which adds support for the translations parameter we use in the source plugin. The translations parameter tells Drupal whether to migrate entities in their base language or to migrate translations. We override this method to:
    • See if the node type being migrated supports entity translations.
    • If the node type supports entity translations, then we INNER JOIN entity_translation and read translation data and some entity metadata, like date of creation, date of updation, etc from that table.
  • function prepareRow() as the name suggests, prepares a row of source data before it is passed to the process plugins. At this stage, field data is also attached to the source data. However, it does not load field data in the language specified in the source row. To overcome this problem, we override the getFieldValues() method and make sure it loads the field data in the same language as specified in the source row.

That's it! You should now be able to run the migration with drush migrate-import --group=example_creature --update. The output should look something like this:

$ drush mi --group=example_creature --update
Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_base'
Processed 9 items (9 created, 0 updated, 0 failed, 0 ignored) - done with 'example_creature_i18n'

Note: Keep an eye out for Drupal core updates. If the drupal_migrate module adds support for entity translations, migrating entity translations might become much easier.

Next Steps

Jun 16 2017
Jun 16

Start: 

2017-06-15 (All day) - 2017-06-18 (All day) America/Toronto

Event type: 

Sprint

Several key contributors to the Migrate Initiative will be at the sprint at DrupalCamp Montreal on Sunday (and to some degree on earlier days as well). Join contributors Adam G-H (phenaproxima), Maxime Turcotte (maxocub) and Dave Vasilevsky (vasi) in person. Initiative coordinator Mike Ryan (mikeryan) is also planning to join remotely on Sunday.

Among the most important Migrate critical issues on the table that are planned to be worked on is auditing for potential ID conflicts before upgrading from older versions. This is the most thorny outstanding issue for the initiative. Use cases and feedback in general is welcome. Further migrate issues are categorized and tracked in the Migrate triage spreadsheet (update regularly). These include handling import of private files, adding back support for incremental migrations, redirecting for obsolete content translations when they are merged in the migration, etc. All of those need helping hands and this is a great time to get experienced with help from the most well versed people in the field.

If you cannot join the sprint this time, your involvement is more than welcome anytime. The migrate team has weekly meetings on every Thursday at alternating meeting times. See https://www.drupal.org/node/2735059#meet for the upcoming meetings.

Jun 16 2017
Jun 16

Two of the biggest retailers in the world are getting together. This morning, Amazon.com, the juggernaut that continues to put massive pressure on brick-and-mortar retailers, announced that it is buying Whole Foods, the popular, high-end organic foods grocer.

Both companies are major stakeholders in the Drupal ecosystem: Amazon made an investment in Acquia in 2014, and much of Acquia’s hosting infrastructure relies on Amazon Web Services. Whole Foods, for its part, has used Drupal for its web presence for at least five years—if not much longer—and holds Acquia as a key partner. Acquia Drupal is a significant part of the Whole Foods DevOps story. (I can just imagine that email from the Whole Foods Accounts Payables department to Acquia: “Send the bill to Amazon.”)

From a presentation at an Acquia event:

So why would Amazon jump out and make this purchase? The answer is complex and multi-faceted.

For Amazon, it's all about the data.

First, Amazon is, at its core, a data company. They use shopping history and patterns to sell us things we need before we even know that we need them. With all the newly acquired data from Whole Foods upper-end clientele, Amazon can make more efficient stock decisions in both the retail and physical stores. In February, Whole Foods Chief Executive John Mackey said that they would retain the services of Dunnhumby, a customer data and insights company, to inform merchandising and services (in other words, help us stock our shelves and get our prices down). I can’t help but think that Amazon could do even better.

Distribution

Second, this acquisition gives Amazon access to a grocery distribution network that enhances their own. It creates more markets for home grocery delivery. Nomura Instinet analyst Anthony DiClemente recently said that the grocery industry remains one of the largest and most under-penetrated markets for Amazon. Well, that just changed.

How convenient could Whole Foods home delivery be? As Dries has demonstrated in recent keynotes (blog post: http://buytaert.net/cross-channel-user-experiences-with-drupal), I can envision a future where I ask my Echo Dot for some free-range chickpeas and organic shampoo and a Whole Foods van shows up at my door an hour or two later with my products (and as of today, with a sizable charge on my debit card).

The Whole Foods brand - a trip down memory lane

Third, it gives Amazon a very strong brand that is associated with organic groceries and high-end shopping experience.

I’m from Austin, and I’ve been shopping at Whole Foods since there was a single store in the early 80s. My family lived in nearby Temple so once a month we’d drive to Austin so Mom could shop at Whole Foods while us kids ran around the nearby Book Stop (Look it up. It was ahead of its time.), and eat at a fancy restaurant called Chilis.

So, maybe my brand recognition and a lifelong love of the grocery chain is stronger than most. There's no denying that it looms large over the health-food industry and is super-popular with upper-middle class soccer moms and those avocado-on-toast loving millennials we hear so much about (joke). How will Amazon leverage that loyalty? Could we see Amazon Fresh become “Whole Foods from Amazon”?

It's Go time.

The fourth and perhaps most compelling upside for the acquisition lies with Amazon Go, a recent experiment with automated retail stores.

Go is a frictionless shopping and checkout experience for physical stores. According to their website, you just “browse and shop like you would at any other store. Then you’re on the way: no lines, no checkout.”

Convenient.

It's currently only open to Amazon employees in a single Seattle store but the idea is as simple as the implementation is complicated: use advanced scanners and trackers to automate checkout. But what does this do to labor cost? In their commercial, the lone store employee is making sandwiches. That's hyperbole, but it makes that point: this is what Amazon wants. Any labor that doesn’t directly enhance the customer experience is suspect and should be eliminated as soon as possible.

Yesterday, outgoing CEO of GE Jeff Immelt scoffed that robots were not going to take over factory jobs in the next five years. Perhaps, but in retail, it has already begun. Many retailers from grocery stores to Home Depot offer self-checkout. If Amazon leads the way to friction-free checkout in supermarkets, retailers that do not follow in their footsteps will find that they’re the next Borders, CompUSA, or Radio Shack.

The Go technology isn't ready for real world use yet but let's say it's at most 36 months away from being ready for prime time. That means that in relatively short order, Amazon can dramatically reduce one of the biggest expenses Whole Foods carries today: labor. They'll still have the cheese guy and the bread lady—those personal interactions are why people shop at a high-end grocer after all. Still, no more jockeying for the shortest checkout lines. It's hugely convenient, and it will happen.

With Go, Amazon can now tackle Whole Foods’ biggest issue for most people: price. As much as I love it, my family doesn’t do our grocery shopping at Whole Foods. I have a great experience, but I need a second job just to pay the bill. In fact, I walk around with my iPhone out looking up pricing and even placing one-click orders on Amazon. Now, if I could get that Whole Foods experience at Amazon prices? Sign me up.

Amazon will continue to do what they do best: leverage technology to remove inefficiencies in established industries, give customers the best possible experience along the way, and provide a shortcut to the things I want to do. This combination is their killer app.

The Drupal Opportunity

The opportunity for Drupal companies could be limited or could be huge. It seems unlikely that Amazon will continue to use Drupal to power their Whole Foods infrastructure in the long run. In the short run, however, Whole Foods will continue to operate as an independent, wholly-owned subsidiary—just with a lot more coverage and support from the most technically-savvy retail company around.

Outside of the immediate timeframe, it could open opportunities to build closer ties to Amazon through the use of headless Drupal for backend data storage, retrieval, and integration. As much as retailers suffer from Amazon’s dominance, manufacturers benefit from frictionless distribution and additional sales channels that will be created. That gives us, the Drupal community, more opportunities to do what we do best with Drupal 8 and beyond. We can continue toward building voice interactions that tie into Amazon’s Alexa infrastructure in unique ways; Tech stacks that better integrate e-commerce platforms into Amazon’s listings and sales engine; and possibly even recruiting opportunities for top Drupal talent that may be winding down their tenure with Whole Foods.

And that’s not even to mention the retailers that want to compete with Amazon head-on. They need what Drupal has: vision, community, and a platform for building world-class, sustainable, and expandable solutions. They need technology that allows them to meet and beat the Amazon at their own game. They need a shortcut to success, and that’s Drupal 8.

Jun 16 2017
Jun 16

This blog post is transcribed from the session "More Social, Less Media: Harnessing the power of Human Connection to Achieve Marketing Success" presented by Molly Nelson at Drupal Texas Camp in Austin, TX - June 2017

More Social, Less Media


First and foremost, I want to begin by explaining the idea behind more social, less media, though I have to admit I cannot take credit for this concept. It was one that was actually introduced to me a few years ago by a blogger and fitness expert, Dallas Hartwig. And the way he described this concept is to not permanently avoid all media and digital technology, but rather to focus on prioritizing meaningful social interactions, to reassess the way that you consume digital media. And the addition of quality time is just as important as the reduction of distracting devices.     

Honestly, it kind of got me thinking about the implications of this process and of this concept. And while those implications really have an impact on our personal lives, away from our devices, and establishing those real human connections, it really got me thinking about, as a marketer, from a business standpoint, had I been placing enough weight on the tactics that really encourage that real, meaningful human connection on the business side of things? So that's really how this concept and this presentation kind of evolved.     

So today I want to start with what we will not be chatting about. I want to start out prefacing this by saying that these are absolutely crucial, fantastic parts of any marketing mix. I'm by no means saying that marketing metrics, and analytics, and ROI, and digital marketing tools are not important things. Because of course, as we all know, they are incredibly crucial parts of all business. But I'll be honest, it's just all too easy for marketers, for business development professionals, for project managers, for developers, any part of the business that you're a part of; it's easy to get caught up in hitting numbers, and filling your pipeline, and slamming your professional services team with as much work as they can possibly handle. But sometimes we forget to just stop and focus on what we do best, and trying to do better at harnessing that human connection.     

I want to invite every body to just take a step back from the numbers, from those tactics that might get us that nice, pretty ROI that everybody's looking for, especially when we're investing time and resources into the marketing side of things. And maybe even forget, for a while, about the MailChimps, and the HubSpots, and the Marketos of the world. We know they're not going anywhere, and they're always going to be tools that we want to use, and they're very necessary, but let's talk instead about what really matters most. And that's the people. All of the people that we interact with. It's going to be your team, your client, the Drupal community that, of course, brought us all here this weekend; and then of course, you, and your personal brand, and what you bring to the table both as a professional and just as a person too.     

Building Lasting Client Connections

We're going to go over establishing those real, lasting connections with your clients, how to harness the strengths of your team, finding and focusing what your business is really well at and how you can do more of it, and then using all of those things to market yourself, market your brand, and your team, or even your business as a whole. So let me give you just a little bit of history and background on myself first. Way back in 2011, just to give you all a little bit of context, I was right out of college and thrown into making a Drupal 6 site with my previous company, Go. They said, "We hired this freelancer, we're four months into the process," they told us it was going to take four weeks, "we need you to take this CMS and make it live."     And, first of all, I didn't know what a CMS was. I didn't know what Drupal was. I basically had only had the exposure of building a geocity site for my high school softball team, and building a little WordPress site for my study abroad adventures when I was in college. So I needed help. And all so often this is a similar story that I hear from a lot of the clients that Promet works with. We get people who say, "I've just had this site dropped in my lap, and I don't know what to do." That's really where Promet came in to rescue me.     

Of course there were plenty of other web development shops that the company that I worked for at the time met with, but it turns out that I ended up being a Promet client. It only took a little bit of googling Chicago Drupal support for that to lead me to Promet Source. As we can see, that digital marketing wizardry does play a role here, but it really wasn't what made the lasting impression. We met with plenty of other web development shops that whizzbang cool things that they could build for us. We were a small engineering firm, just kind of taking our business online for the first time, and we weren't really sure what we needed. And all these other shops told us all these cool things that they could build for us - they showed us their case studies, they showed us their products, and the things that they built for other people. But the problem was, we didn't even know at that time what we needed. And as a marketer, and being fresh out of college myself, and having to really make this Drupal site go, I had no idea what I needed.     

It turned out that what we did need was somebody to just sit down and talk through with us what we were trying to accomplish. What were our goals? And what were we trying to do by taking our business online? So when I stepped into the role I was previously in, they said, "We need a website. Everybody has a website. Our competitors. Our customers, they want to be able to see our business online." But there was really no talk about what the business goals were, what were the objectives we were trying to address, and what did we want our customers to really engage with when they went to our site? Did we want to make a sale? Did we want to educate them? And that was where Promet really led us through that process. It really helped that they took the time to understand our business. So they said, "Let's talk about it. Let's talk about your goals. Let's establish those goals."     

From there, my team really had the confidence in Promet that they truly understood our business, especially when it came down to getting to the project scope. So it wasn't just a conversation of numbers, and results, and what they were going to build for us; it really started with, "What would the business need?" So we felt like, as the client, the hardest part was really over, and we could hand over the website project, and that we knew that it was in good hands. So the next step, of course, from there was to build something great. But really, the long term impact for me as the client really didn't even come then. It's what I think can often be overlooked in what we're going to talk about today.    

Jenna, who was then my project manager, and now a coworker of mine at Promet Source, didn't just stop checking in with us when the project was over. It wasn't, "Here's your website, nice knowing ya!" It was those continual check ins, that every so often I'd hear from Jenna, and it might be a phone call, or it could be when she was passing along Drupal resources. She would say, "Hey, here's theweekly drop." Or, "Here's this news that's coming out of Drupal.org that you might want to take a look at because I know that you're new to Drupal and you're new to content editing." She knew that I was kind of like a baby deer. I was kind of lost and needed to find my way in the technology space. So it really helped me to feel more familiar with Drupal.     

Now, as a marketer for Promet, I can see the impact that both Jenna and our other project managers, and our account managers can really have on Promet's current and potential clients, and how that leads to more and new business. It's not the fact that we're just sending out the marketing campaigns on a regular basis, it's the fact that they know Jenna, and those all important check ins are helping to establish what's really most important in that long-term; lasting relationship with our clients.     

The Most Important Element in Lasting Client Relationships: Trust

So what do you guys think that is? What is that most important factor? Anybody have any guesses? Anyone? It's one word. Just one little word. Five letters. No? Anyone? It's trust. Yeah. So really, it's just the trust that their business, their project, their idea, their goals are in good hands. That they can rely on you no matter what the issue is, or the problem is that they might be trying to solve. They want that friendly face, or that friendly voice on the other end of the phone that's going to say, "We hear you. We understand what you need. Let's work through it together." And that trust is what's going to lead to that repeat business.     

So once you have the trust, how are you going to go about keeping the trust? One of my favorite questions that a mentor of mine years ago started prompting me to ask our clients is, "What would I have to do for you to fire us?" And that's something that kind of takes people aback when they hear it. They think that you're trying to catch them, or it's some type of trick. But really, what you want to get to is, what is the thing that would make you lose their business? And then, you just have a conversations, and kind of get to the point of, "Okay. Well, we're going to try to not do that thing."     But really, what it often leads to is that that conversation about, "Why did they choose you in the first place?" And, "Why have they stuck around." And that, for me as a marketer, that's the thing that I like to get to the heart of with our clients, and especially ones that have stuck around. And even those that we might have lost to another firm, or decided to go with somebody else for a new project. It's good to get to the heart of, "What were those factors that really led them either away, or that keep them as a customer for the long term?"     

A lot of times, those reasons that they've stuck around have to do with things that aren't necessarily tangible. It might not be the same reasons that they became a customer in the first place. Because, if you think back to some of the projects that you're working on right now, or some of your current clients, maybe they came to you because they saw another project that you put together. Or maybe they saw another client's website that they really liked. Or it might have been a case study, or one of your out-bound marketing campaigns. Or it could have been that they met you at Drupal Con. Who knows? But, more often than not, the reason that they decide to stay has nothing to do with those original reasons that they became a customer in the first place.     

Oftentimes, it has to do with your team. That's what's going to keep them coming back again and again for your expertise. And that's where building up your teams, and building up the strengths of your team, and really harnessing the power of that, especially when it comes to marketing and to business development, has to come into play. So when I have shared this slide with my team, it's kind of met with confusion. A lot of times, it's met with a little bit of panic. Like, "Are you going to take the developers and make them make cold calls? Are you going to take our project managers and send them all out to Drupal Con and say, "Bring us back 10 leads a day"?" And that's by no means what we're talking about.     The truth is that every single person, each and every one of them on your team, is a marketer. Everyone is a business development professional. Everybody has something of value to share. But a lot of times, our natural inclination is to have that imposter syndrome set in. To think, "Okay, well I've only been a developer for a couple years." Or, "I don't have anything of value to contribute back to the community." Or, "Anything that I might write a blog post about, what if people don't read it?" Or, "What if people call it out and say, "Well, actually, you should do things this way."" And they just get a little bit scared. They need to kind of have that drawn out of them. And as marketers, any of you that might be marketers in the room, that's really on us to draw that out of our teams, and to really get that engagement, and to get people excited about sharing what they've done. And a lot of times, that can be buried in a project retrospective.     

It could even just be the simple answer to a development question that maybe took somebody hours of googling to find. I mean, how often are you trying to find an answer to a question, or a way to solve a problem, and it takes you really long time to figure it out? Well, more than likely, somebody else has had that same issue at one point or another. And that, in and of itself, is worthy of a blog post, it's worthy of a tweet, it's worthy of a Facebook post, and putting it out there for the rest of the community to see. Because, more often than not, you're going to become that source of information that they're going to go to when they have a similar problem. They'll see that, "Oh. Well, John from Promet, he figured this out for me. Next time I have a similar problem, I'm going to cal him up. He might know what to do."     

So really, when you think about it, each team is completely unique. We might all be development firms, or freelancers, or digital agencies, or we might even work for a university, or work for a healthcare organization and think, "Okay, well, we have similar needs. We have similar interests. We might have some overlapping problems that we're trying to address." But when you think about it, the collective experience of your team is entirely unique. No two teams is going to work on the same projects, be working from the same set of requirements, or do the exact same thing every time.     

So when defining differentiators, I feel like this is one that can be often overlooked. We're trying to figure out, "What niche can we address that hasn't been addressed by another Drupal agency?" Or, "What product can we put out there that's trying to solve a problem that somebody else hasn't solved yet?" But really, if you just kind of look inward, and look at the team that you're surrounded by every day, you might come across some of these skill sets, or some of these areas of expertise that your team wants to pursue more of.     

How do you market that? You share the knowledge. Of course, a lot of us were brought here this weekend for the Drupal camp. Some of you might have also done speaking engagements at Drupal Con, or even some of the camps, but we even want to look outside of Drupal. Maybe talk to our customers about, if they are in a specific vertical, or in a specific industry, where they're getting their knowledge from. What publications are they looking to? What opportunities could you have to go to one of their events and present, or even build up your team and offer to help write a session submission?" I can tell you that, in the weeks leading up to Drupal Con, it was a lot of getting on HipChat and saying, "Hey. I saw that you did this cool thing. Do you want to speak about it?" Or, "Hey, I saw that you have this interest in this one specific area. How can I support you in that?" And, a lot of times that's all it takes to bring people out, and get them talking about projects that they've done, or areas that they want to learn more about.     And that's a great way to start submitting a session, is just pick a topic that you want to spend time doing research on. You don't have to know everything, but you've just got to kind of put yourself out there. So getting involved in the Drupal community, and even branching outside some of those Drupal specific events which we'll talk a little but more about in a couple slides, really gives your team a chance to establish that credibility and build up their confidence as well.     

Another way that you can do that is developing case studies. Of course, this might seem like a no-brainer, but one thing that a lot of people don't necessarily always consider is, even going back to previous projects and looking at case studies that you might have written years ago, and seeing, "Okay. What did we do previously, and how can we replicate that? If we build this really great solution for, say, a community college, for this one specific time of business, what are the chances that that specific type of business might also want the same type of solution?" And that gives you the opportunity to not only collaborate as a team, but then reach out on a more one-on-one basis to other people in that area that might be interested in that product, or that service that you have to offer.     And then, of course, hosting webinars as well. And this is also a great opportunity to get more of that collaboration. One thing that I've kind of found to be beneficial for our team is, when we do a project and we might be using some new tools, or we might be doing something for a vertical, or for a new type of client, that we've never done before, we kind of go through that project retrospective, and then we say, "Okay. Let's talk about this." Like, "Let's just collaborate." It might first be an internal webinar. Actually, at Promet, we call them "IT meetings", we have them on a weekly basis for our internal team. But that can kind of bleed into something that becomes either a session submission, or a blog post, or a webinar that we actually promote to the larger Drupal community, and even at camps and cons as well.     

And then, of course, there's also blog posts, press releases, and even podcasts. We've had a couple of our team members that have gone on some tech-specific podcasts. And then, past few months, I think there's a few more coming up to talk about the tactics that they've done, some of the solutions and business problems that they've solved for their clients. And again, that's just another way to get your team more confident, and talking about their experience, and kind of get past that imposter syndrome of feeling like they don't have anything of value to share.     

Marketing our Expertise: Promet's Training Practice

Training was one of those things that we'd tried to handle internally for a lot of years. We found to not only establish credibility for us in the community, but something that's really given us an opportunity to establish that human connection; is really getting involved with mentoring and training. At Drupal camps, at Drupal Con, and having a public training schedule as well. To give you a little bit of history, our training practice manager Margaret Plett, who was the author of the Drupal 8 Acquia curricula came on board with Promet a little over a year ago, and we started to build this training practice as a separate piece of our business.     

Now, what this opportunity to do training has led us to, is the fact that we get this great one-on-one face time with people who are current clients, or potential clients, to not only learn more about what their needs are, and what problems they're trying to address, but it also gave us at Promet the opportunity to establish our credibility and make those lasting connections with our students. Oftentimes, now that we've had this practice in place for a little over a year, we're starting to see all of that effort come full circle. We're seeing those students coming back to us when they have a question, or they have a problem they're needing to solve, or maybe they have a topic that they want some additional training on.     

This really comes back to those relationships that we've established with them. As much as I want to say it's because of my email newsletters, and my marketing campaigns, and all the tweets that I'm sending out, I know that it has much more to do with the connection that Margaret's establishing with our students, and the fact that we're making ourselves available to them, and we're becoming a resource for them long into the future. And that's something that even your team, from a mentoring standpoint, can get involved with with the local Drupal community.     

Filling the Other Guy's Basket

Another concept I wanted to introduce that was first introduced to me several years ago in a book called Uncontainable ... Which was actually written by an Austin native and container store founder, Kip Tindell. One of the concepts that really struck me the most in this book was one from Andrew Carnegie that goes, "Fill the other guy's basket to the brim. Making money then becomes an easy proposition." Now, for a container store, this became one of the core philosophies of their business from the very start. And the idea here is to fill the other guy's basket, allowing them to creatively craft mutually beneficial relationships with their vendors. And the way that container store has embraced this concept is really by investing in those relationships. Investing in their partnerships that they have in their professional community. That way, they're always making sure that they're nurturing those relationships in the long-term, and they're creating those really nice win-win situations.     

So for them, that can mean allowing their vendors to test out new products in their stores, which can often lead to container store being the first on the list to receive, say, a new shipment, or a certain product if it's out of stock. And then they're able to better serve their customers. And that cycle just continues to repeat itself. When you're creating those win-win situations for your customers, your business is going to succeed while their business is succeeding as well.     

Now, in our space, that doesn't necessarily always mean dollars. That might mean, for an association, a way for them to promote to their membership. So say you go out and your team builds this really great solution and a really great website for a new association, or for one that's trying to grow their membership. Now, one way for them to get the word out might be some of those co-marketing activities. And that's the really cool thing about all those tactics that we talked about. All of those very same tactics, from speaking at camps, to developing case studies, hosting those educational webinars, doing blogs, press releases, mentoring and training; those are all things that you can involved your team on, but you can also involve your clients and your industry partners as well.     

A lot of times, we're going back through retrospectives, and we're trying to identify, "Okay. What was the problem here that we were trying to address?" Or, "How did this solution come about in the first place?" And a lot of times, as a team, we can't answer those questions internally. We have to go back to our clients. And when we go back to our clients, that opens the door to the conversation of, "Well, how can we take this, and utilize this product we've put together for you, and how can we make it really move the needle for your business as well?" So if we're going to do a press release, then why not also do a press release on behalf of our clients as well? It's just kind of a natural extension of those marketing efforts that are only going to help establish that credibility, and that ability for you guys to continue the relationship with your clients.     

So how do you continue to kind of cut through the noise and make sure that customers stay loyal and continue to come back to you? So back in 2009, there was a Gallup study that actually showed that 70% of customer loyalty and spending decisions are based much more on emotional factors. So how can we continue to engage individuals and connect them emotionally. The thing that I've found over the years, as a marketer, and especially as I've started to work more in the Drupal space the last few years, is that a healthy mix of digital marketing and human connection is always key.     

I know as Drupalists, and being in technology, it's easy for us to say, "Okay. Well, I'm going to have my drip campaign set up." And, "I'm on the first page of Google," and, "I'm tweeting all the things," and, "I'm posting everything on Facebook," and, "All right, I'm done. I've done all the marketing I could possibly do." But sometimes it's just picking up the phone. It's asking somebody to meet you for coffee. Because what are they going to remember more? Are they going to remember the email you sent them asking if they were ready to start the next project? Or are they going to remember the time you took them out for coffee at Drupal Con and talked about your mutual love of Game of Thrones? I mean, which one would you remember most?     

You want to nurture those relationships and turn your customers into advocates. Because, a lot of times, you're going to want to go back to ask for referrals. And that would lead to new business. But, honestly, we have to earn the right to those referrals. We can't just expect, just because we launched a great product for somebody and sent them off into Drupal land, that they're going to continue to want to come back to us. We have to earn that right. We have to continue to nurture that relationship.

Jun 16 2017
Jun 16

Ha sido un placer trabajar con el equipo de La Drupalera, también desde Reino Unido y en remoto. Se aseguraron en todo momento de que la distancia y el idioma no fuera un problema, manteniéndonos al día del progreso del proyecto y resolviendo todas las dudas y retos durante el proceso de desarrollo con Drupal hasta su lanzamiento.

Jun 15 2017
Jun 15

One of the best parts of Drupal 8 is our shift to enterprise PHP coding structures. With tools like composer and Symfony’s structures like Events and Dependency Injection, Drupalists are learning to be great PHP developers, and vice-versa. Today, the fastest route to becoming a rock star Drupalist is through PHP.

I’m one of the PHP track chairs for Drupalcon Vienna, and this year our focus is better PHP === better Drupalists. How can better PHP make your life as a Drupal developer easier?

Do you like PHP 7? We want to hear about the technicalities of types, throwing all the things, and your favorite operators (mine is null coalesce, but full respect for you spaceship operator fans).

Have you seen the light of functional programming? Tell us why we should love higher orders with lambda functions and closures. Let’s hear the finer points of first class functions.

Do your tests bring all the bugs to the yard? We want to talk about it. Every method is a promise, and your tests make sure you keep your promises. We want sessions about test driven development in a drupal context, choosing the right test framework and scope, and how your real-world tests are saving you real-world time.

Have you written a composer library wrapper module yet? Submit a session about how composer is saving you lines of code.

Is your development environment fine-tuned for drupal excellence? Tell us how, and why.

We have only two weeks left until session submissions close! Get your session in now and help us make Drupal code something to be proud of.

Jun 15 2017
Jun 15

The Contributed module Display suite (“DS”) allows you to take control on How do you want to render them using interface. admin has ability to arrange nodes, comment,user data, views etc. provides drag and drop after as we do for managing field section.

If you want to build a drupal custom page and really don't have any drupal technical knowledge or coding skill or, you don’t want to write custom templates, and  for smaller stuff then you can go ahead with this Display Suite module. Is really helpful when it comes to replacing the default view of an entity to user defined view using application interface. It’s straightforward and simple that is why developer build this for community.

To enable Display suits in Drupal 8 site it required layout_plugin as it has dependency
 

Display Suite enable

So, let’s get started. Download “Display suits” and “layout plugin” module from drupal.org and place it in your module directory as you do for enabling your module. Once the module is enabled  you can find “Display suit” available in  admin >> structure page. 

Display suite in structure list

 To Create a Display Suit for your node create test node first for test purpose. Below content i have created in one of my local system.

Default article node view

To create/change the layout go to admin >> structure >> ds
On this page you will find “Manage display” for all the entity type. This manage display apply not only to the content type but also to all the entity on the site. On this page you will find 2 more menu item in quick tab.  

   1.Classes
     -- You can create custom css classes for your new region and assign back to them.
   2.Fields
     -- You can manage different display field to your region. By assigning some of the block , view or tem to the region.
 

Displays list

So, let’s go ahead and create display suits for article node.by clicking on “Manage display” 
Admin >> structure  >> types >> manage >> article >>display 

At the bottom you will find Layout for article in default tab, Select a layout and click on save button. As soon as you will select the layout you will get a layout preview. I have selected Three column

Layout for article
 

As soon as you save the configuration you will find the page layout with some of the group called left, middle, right. Assign your field to those group using drag and drop feature. And you are almost done. The below screen will help you to build drupal custom layout.

Group configuration

After rearranging my page looks like below screen. 

rearranging-dispaly

Let’s check out the entity view for article. As you can see page having 3 column left, middle, right

Firebug result for class

dispaly suite test page

Did you we have discussed #2 Classes quick tab, you can access them from below path 
Admin >> structure >> ds >>classes

This page is used for adding extra classes to the section you assign. We have seen it earlier, while creating Display suit it provide their own classes. If you want to add your own class then you can do this here.  
 

CSS classes for regions

As i have created three classes cust_class_left,cust_class_middle,cust_class_right

Added CSS classes for regions

So far we already created our custom class. It’s time to assign those classes to our region. Follow below path to add classed to the article bundle.
Admin >> structure >> types >> manage >> article >> display

You will find your new classes under custom classes quick tab.
manage custom classes


I have assigned <none> for layout cust_class_left for left region , cust_class_right for right  region and cust_class_middle for middle region.
 

custom classes assigned

So let’s see how does it work in browser. Ok Perfect

firebug test

To add a Custom Wrapper to each region of you article entity you can add them from below path
Admin >> structure >> types >> manage >> article >>display
Go to “Custom wrappers” and select wrapper for each of the region.


custom wrappers

You will find new markup available for left, middle, center and outside container. So without writing any custom code you can add wrapper.

Custom wrapper in firebug

So far you must be familiar of Display suites and their usage. Some of the front end Developer must be thinking it’s similar to Panels. Yes you are absolutely right.  In this blog i have gone through creating a Display suit assigning their field to different region and adding custom wrapper & classes.

Jun 15 2017
Jun 15

We, the website development team at Texas Creative, are big fans of the Paragraphs Module. For the last couple of years, it has become a larger and larger part of our Drupal 7 and Drupal 8 websites. In this post, I will give three tips we’ve discovered that make Paragraphs even easier for the end-user to use, in our case clients.

What is the Paragraphs Module?

To quote the Paragraph module description page: “Instead of putting all their content in one WYSIWYG body field including images and videos, end-users can now choose on-the-fly between predefined Paragraph Types independent from one another.”
In short, it helps Drupal do structured, repeatable content even better than before. The end-user doesn’t need any technical HTML skills. The web designer can design specific sections/layouts of content and give tremendous flexibility to the end-user to edit, create, or reorder without compromising the design integrity. If you aren’t using this module in your Drupal 8 builds, you are really missing out.

Tip 1: Add Publishing options to an Individual Paragraph

Who knew you could add the “Published” checkbox to each paragraph in the Manage Form Display for the Paragraph Type by just dragging the “published” field out of the Disabled section and then setting it’s widget to ‘Single On/Off Checkbox’? After this is set up, the paragraph is only displayed when the box is checked. This is useful for content like slides on a rotator block which may need to be taken out of rotation for a time and then reinstated. This feature has been in Paragraphs for a long time but isn’t completely obvious.

 

Tip 2:  Rename Your Paragraphs Field Titles

Most of our clients aren’t familiar with Drupalisms, so the term “Paragraphs” can be a bit confusing on a content edit form. It doesn’t explain what exactly is being added. The Paragraphs module maintainers luckily anticipated this and provided a way to customize the user-facing language.

On the parent entity’s Manage Form Display tab, where you setup your Paragraphs reference field, you can customize the singular and plural for the Title of the field. This changes the interface wherever the word “Paragraphs” would normally appear and is customizable on each Paragraph field.  

We often add Paragraph types that are interchangeable, full-width areas below the main page content. The word “Panel” just fits what they are so we change the title to “Panel”. To an experienced Drupal developer “Panels” is a very different thing, but to our clients “Panels” are those flexible, repeatable, full-width areas they can add to the bottoms of their pages. It makes much more sense to them than “Paragraphs”.

 

Tip 3: Add Contextual Links to Paragraphs

As more Paragraphs are added to a piece of content, it quickly becomes difficult to edit due to the size and complexity. A simple solution to this is to install the Paragraphs Edit module on your site. This module adds contextual links to individual paragraphs to edit, delete and clone. Now the end-user can hover the paragraph on the frontend of the site and see options to edit a single paragraph without needing to edit the entire page worth of paragraphs. Note: The 2.x-dev version has more compatibility with complex paragraphs and advanced features, but requires Drupal 8.3 or higher.

 

Importance of User Experience with Paragraphs

For us and our clients, any criticisms of Drupal’s out-of-the-box experience become irrelevant since we don’t leave it that way. The work has to be put into the client experience just like it is the site visitor experience. The accumulation of these kinds of small wins in user experience add up to a happy client. So, customize your customers’ Paragraphs experience.

Recent Projects:

San Antonio Bioscience Research

Take Care of Texas

Jun 15 2017
Jun 15

A recent prospect responded to my inquiry about the project budget with this:
 
"We can't release budget information as we need all vendors to bid their best price. If they know the budget they just bid right up to it."
 
I've always known that is the fear, but in the hundreds of  website projects I've pursued over the years, I think that is the first time a potential client was ever that forthright about it. However, it's an unfounded fear. In a competitive situation with 6-50 firms proposing, we all aren't going to peg our proposals at the top of the budget. Without a budget, those 6-50 vendors aren't even proposing on the same solution. They are proposing on their perception of what they think you want for a solution. That is why you'll get bids ranging from $25K - $250K from the same RFP.
 
If you want to receive a good mix of proposals, all proposing in the same budget neighborhood, so that you get to the no-lose situation of a short list with 3 or 4 vendors that will all do a great job on your website, you have to provide the budget in the RFP. If you truly don't have a budget, give us a ceiling, or what you consider a reasonable neighborhood. It’s 2017,research is easy. Nobody believes you are putting out an RFP without having done some basic research into what “this” should cost. If you truly want a partner (which is what every RFP claims), treat us like partners, from day 1. Share the important information so that we can craft a solution that will actually work for you.
 
Any competent web shop can scale a proposal to fit a budget. We can take the same basic set of requirements and design a $40K site, or a $140K site. The primary differences between a $40K site and a $140K are:

  • Depth of the discovery consulting
  • Amount or complexity of the interactivity in the site
  • Integration with 3rd party apps
  • Amount of customization in the site

Sure, we prefer to build the $140K sites. That kind of budget allows more time for creativity in the design, and more time to customize Drupal to do exactly what the client wants. However, if $40K is all you have that is fine. We can deliver a compelling website for $40K. What we can't do is read minds. Without some guidance on budget we have to guess at whether you want the $40K site, or the $140K site. Help us help you by sharing the information we need to give you the best site possible for your budget. The reason real estate agents on HGTV ask about the budget is that a 3 bedroom / 2 bath house can have a 300% or more variance in cost based on location, upgrades, quality of materials, etc. Web sites aren’t that different.
 
Budget is the most important information you can provide in an RFP. Given the choice of  responding to 30 pages of feature requests with no budget, and 2 pages with some very basic goals and a budget, I’d prefer to write the second proposal every time, because I know up front how to meet the customer’s expectations.
 
The client at the beginning of this post? They wanted the $40K site. I guessed wrong on that one.

Jun 15 2017
Jun 15

When you are calling a function or method that has an argument(s), you don’t always know what type (array, object, string etc) of argument to pass to the function. And if you end up passing in the wrong type, you’ll get a less than helpful error.

To fix this, you can using type-hints to improve the clarity of your code and improve errors. Type hinting allows you to specify data types you expect for an argument for a function declaration. You can specify data types such as arrays, objects and interfaces. Type-hinting is optional, but it does makes it easier to debug your code and allows your IDE to provide autocompletion amongst other benefits.

Consider the following simple example:

<?php

$ingredients  = array('banana', 'strawberry');

function shake ($ingredients) {
  foreach($ingredients as $ingredient) {
    print $ingredient;
  }
}

shake($ingredients);


This will print banana and strawberry to the screen.

But it isn’t immediately clear that the $ingredients argument in the shake function needs to be an array. So what happens if you pass in a string instead?

$ingredients = 'coconut';

function shake ($ingredients) {
  foreach($ingredients as $ingredient) {
    print $ingredient;
  }
}

shake($ingredients);


You will get the following error:

Warning: Invalid argument supplied for foreach()

The error is referencing the foreach because you have tried to pass it a string when it was expecting an array.

To use a type-hint with this example, add the date type to the function argument. In this case, the data type is array.

function shake (array $ingredients) {
  foreach($ingredients as $ingredient) {
    print $ingredient;
  }
}

Then if you pass in the string, you will get a more meaningful error:

$ingredients = 'coconut';

function shake (array $ingredients) {
  foreach($ingredients as $ingredient) {
    print $ingredient;
  }
}

shake($ingredients);

The error is now:

Catchable fatal error: Argument 1 passed to shake() must be of the type array, string given, called in /Users/blairwadman/Sites/tutorials/typehinting/index.php on line 13 and defined in /Users/blairwadman/Sites/tutorials/typehinting/index.php on line 7

This is very meaningful and tells you exactly what the problem is and the line it is on.

Object type hinting

You can also specify a class or interface as the type-hint.

Consider the following Drupal implementation of hook_form_alter():

<?php
/**
 * Implements hook_user_login($account).
 *
 * @param $account
 */
function welcome_user_login($account) {
  $name = $account->getDisplayName();
  drupal_set_message(t('Hello @name, thank you for logging in and welcome!', ['@name' => $name]));
}

You now have the display name from $account. But you have to know that getDisplayName() is an available method.

Fortunately, there is an easier way if you use a type-hint and an IDE like PHPStorm.

If you include a base class or interface for the $account variable, your IDE will tell you the available methods and properties.

Add ‘AccountInterface’ type-hint to the welcome_user_login() function:

function welcome_user_login(\Drupal\Core\Session\AccountInterface $account) {

And now when you start to type $account-> , the IDE will offer you autocompletion.

Adding a use statement

You can also include a use statement in the .module file so that you can reference 'AccountInterface' rather than the full namespace hierarchy.

At the top of .module file, add the following use statement:

use Drupal\user\AccountInterface;


Change the function argument:

function welcome_user_login(AccountInterface $account) {


Putting this all together, welcome_user_login() is now:

<?php

use Drupal\user\UserInterface;

/**
 * Implements hook_user_login($account).
 *
 * @param $account
 */
function welcome_user_login(UserInterface $account) {
  $name = $account->getDisplayName();
  drupal_set_message(t('Hello @name, thank you for logging in and welcome!', ['@name' => $name]));
}


Wrapping up

Using type-hints in your code makes it clearer and less error prone, improves the errors you get back and also aids in autocompletion. Type-hints aren’t part of the Drupal code standards yet (so they are not required for core and contributed code) yet, but you find plenty of examples in core code.

Pages

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