Drupal Feeds

Learn all about Twig templates in Drupal 8 from our very own Larry Walangitan.

Configuration management (CM) in Drupal 8 is great. However, when more complex configuration scenarios arise, we must find solutions to problems that core CM functionality doesn’t address (yet).

Drupal has a powerful suite of tools and features for just about any type of website, and eCommerce websites are no exception. Drupal has a very active and healthy eCommerce community that creates some amazing features.

The Drupal eCommerce market mainly consists of Ubercart and Drupal Commerce, but there are also some impressive emerging technologies to keep an eye on, such as the Stripe payment API, that allow for more customized solutions.

The eCommerce solution that you choose will depend upon the particular Drupal site you’re developing. Is it a simple online store with just a few products, or a much more robust site with a wide variety of products? This is one of the strengths of eCommerce with Drupal: you can build the kind of solution you need without the extra, unnecessary features and functionalities. Ubercart vs Drupal Commerce Drupal Commerce is by far the most popular Drupal eCommerce solution these days. It’s the successor to the original eCommerce solution, Ubercart. Drupal Commerce was written for Drupal 7 by the same developer that created Ubercart, Ryan Szrama, using the latest APIs and features for Drupal 7.

Drupal Commerce is supported by Ryan Szrama’s company, Commerce Guys, and the Drupal community as a whole. Developers are more likely to add new features to Commerce because it is more widely used in Drupal 7 and beyond. The Drupal 8 version is still in beta, so more work needs to be done to get it to a full release. Check out the Drupal Commerce issue queue to see where you might be able to help.

Drupal Commerce learned from Ubercart's primary shortcoming; it was difficult to configure and not very modular. Where Ubercart was one module that was difficult to build upon, Drupal Commerce has a small set of features in the main module and a large suite of available contributed modules. This allows for easier configuration and more customizations. Kickstart Your Online Store One of the most useful features available for Drupal Commerce is the Commerce Kickstart Drupal distribution. This is a great way for non-technical store owners to get a Drupal Commerce store up and running quickly and easily. It comes with an impressive installer that allows you to install an example store to see how everything can be configured. It then allows you to wipe the site clean and start a fresh build of your own custom store.

The Commerce Kickstart comes with some additional built in modules and configurations that help get a Drupal Commerce site up and running quickly. This is a more efficient solution than building from scratch with the Drupal Commerce module and any contributed modules that are necessary to achieve the desired functionality. The Commerce Kickstart distribution shows off the power of Drupal distributions; it’s a turnkey solution for Drupal eCommerce websites. Stripe API One of Drupal’s greatest advantages over its competitors is how well it integrates with third party APIs. This allows for integration with many different payment gateways, one being Stripe API. Drupal developers can integrate Stripe with a Drupal site through a custom module and create highly customized payment solutions. This type of customization allows for a variety of solutions for selling and accepting payments that would be more challenging to implement with Drupal Commerce. Which Solution Should I Choose? The solution you choose depends on the site’s needs. A small online store that only needs a simple shopping cart might be best suited for Ubercart. At its core, Ubercart is still the easiest to set up without using a Drupal distribution like Commerce Kickstart.

Drupal Commerce is a much more robust eCommerce solution for Drupal with enterprise level features that large online stores use to sell products like product displays. On top of that, you get all the features of a normal Drupal website like content types, taxonomies, and user permissions.

If you are looking to build a very customized payment solution that doesn’t really fit into either of these categories, perhaps a custom solution with the Stripe API module is best.

In the end, the Drupal eCommerce solution you choose should be easy to use for your store administrators and easy for your customers to buy your products online.

Drupal + Cloud9

Cloud9 is an IDE and development environment in the cloud. Yeah yeah, buzzwords buzzwords, but what does this really mean?

Let's dig in a bit, starting with the positives.

What I Like

I've been using it heavily for a few months now, and here are the features that stand out to me. 

Workspaces

C9 gives you "workspaces", each of which is a complete Ubuntu-based environment (i.e., a Docker container behind the scenes). This means that you can install stuff, use sudo, change config, etc. You can create and delete workspaces as you please.

You can really go to town on these things in pretty much any way that is useful. 

Workspace cloning

C9 also lets you clone workspaces to create new ones. Cloning is super fast - usually around 30 seconds for me from start to finish. This means I can do things like having a stock "Drupal" workspace that has all the tools and config that I like to have for Drupal projects, which I just clone when setting up a new Drupal site. There are other cool possibilities here too, which I'll get to shortly.

Sure, theoretically Vagrant and friends let you do this already for local environments, but the speed and ease that C9 brings to this process is unmatched compared to anything I've seen.

Out of the box debugging (for Node.js, PHP, Go, and C++)

Interactive debugging is already there, waiting for you. In PHP for example, you just click the little "bug" icon before running your app, and then set a breakpoint wherever you want. No messing with xdebug config or path mappings or exposing ports, none of that. Just click and you're done.

This is especially nice for me on the Node.js side, since I've never learned how to set up a Node debugger and don't particularly want to.

Custom runners

Cloud9 environments come with some pre-configured "runners", which are basically commands that you can run by clicking a button, and have their output stuck into their own tabs. For example, starting the app typically means starting the "Apache" runner to get the server running, which will throw Apache logs into the output of that tab. 

That's all fine, but it gets more interesting when you create custom runners. You can drop in a name and command and some configuration such as the current directory, and then you have a nice little command runner waiting to be clicked. I like this for things like "grunt watch" which watches for Sass updates, but it's even more useful for commands with hard to remember names, so that you can kind of abstract that away. It's like shell aliases on steroids, in a way.

Performance

Cloud9 is surprisingly quick given that it's a pretty bulky web app. I don't have an insanely powerful laptop or anything, and I found the Cloud9 IDE to be responsive enough that I never really saw any noticeable slowness, which is the goal after all.

What I don't like No VPNs

Due to the way Cloud9 is built, it can't really connect through an existing VPN. So if you're trying to work on a site that is hidden behind a VPN, then it might be test to avoid Cloud9 for that project.

IDE limitations

The C9 IDE is ok, but not good, and definitely not great. If PHPStorm is a 9/10 in terms of IDE functionality, then Cloud9 is more like a 4 or a 5. It's a pretty decent text editor, but a pretty lame IDE.

For example, it's missing features like:

  • Jumping directly to a function definition from somewhere that function is called
  • Auto-generating block comments with @params, etc., based on function code
  • Function parameter hinting as you type
  • Viewing all usages of a given function
  • Project-wide autocompletion that works smartly and consistently
Restricted workspace cloning

You can only clone your own workspace - you can't clone someone else's. This means that it's basically impossible to have a setup where a tech lead manages a "pristine" project workspace which everyone else can clone whenever they need to start fresh, or when new people are ramped on. I love the sound of that workflow, and it's disappointing that it isn't allowed.

Credit card required for signup

You can't sign up to C9 without entering your credit card info, even for the free accounts. This isn't the end of the world for me or possibly for you, but it can be a real bummer when you want to give someone on your team access to your codebase to do some pair programming. The "how much do I really want this?" factor kicks into high gear when you're asked to pull out your credit card.

Use cases Open source work

C9 is great for doing open source work. It gives you the ability to share your code or your environment when anyone just by sending a link,  which can help a lot when collaborating on something remotely that is only on your local environment.

Plus, with workspaces being so cheap and powerful, you can have a separate workspace for each open source project that you maintain. That way, you always have an environment ready to be worked on for everything, and you never have to wonder if that environment you build 6 months ago for module X is still running and working.

Demos

Creating a workspace specifically for a demo (or a prototype or anything else temporary that you want to show other people) can be really nice. It even gives you a URL to share with people so they can try out your demo with their own two hands.

This lets you work on your demo in a clean, empty environment, which can just be deleted when you're done. 

Random fiddling around

You know that thing where there's a new tool or app or whatever that you want to try installing, but you don't want to worry about adding more dependencies or possibly bringing in a different version of a dependency that will break something else? 

The speed with which you can spin up C9 workspaces is great here. Create a workspace in a few seconds, do whatever you want, and delete it. That way you never have to worry about leaving any remnants of your random tinkering on your main computer.

Pair programming

One of the banner features of C9 is the ability to live-edit code along with other people, and see each other's updates in real time. If you ever pair program, then this is basically the dream. It sure beats screen sharing over a Google Hangout. 

Debugging

The out of the box debugger support kind of automatically makes "debugging" a good use case for Cloud9. The fact that you have a full Ubuntu environment means that you can usually change whatever you need to change to replicate your prod setup, and the built in debugger can take it from there to help you find your bug.

Again, you can always just use Docker yourself to replicate an environment and install Xdebug, but this is just so much easier.

Regular old development

If you can live without advanced IDE features, and you don't need a VPN to access anything, then you can really do most of your regular everyday development on C9. That way you have cheap workspaces and easy debugging and shareable URLs for everything that you work on.

Tips

Finally, here are some tips for getting the most out of Cloud9, especially if you're using it for Drupal.

1. Start each workspace from a starter instance that has all the tools you need

For example, create a "Drupal" starter workspace that has Drush, Drupal Console, Apache config, git aliases, XHprof (here are installation instructions), etc. Then, whenever you spin up a new site, just clone that workspace.

2. Create per-ticket workspaces

Taking workspace cloning to the next level, you can just create a stock workspace for your project which you never actually touch except to keep it up to date. Then just clone it every time you start work on a new ticket. That way you can have completely separate environments for unrelated workstreams, and you never have to worry about clobbering data or whatnot when switching back and forth. Plus, that ticket you worked on 3 weeks ago will still have a working environment to go back to when it fails QA and needs a fix.

3. Make the keybindings match your main editor/IDE

Cloud9 has fully configurable keybindings for just about everything. This means that you can make C9 keyboard shortcuts match the ones you're already used to from your normal editor/IDE. That way it's really easy to switch back and forth. There are even Vim and Emacs modes!

4. Create custom runners for all the things

Think of all the commands you run on a regular basis. Things like "grunt watch" or "drush cc all" or "drush updb -y && drush fra -y", etc. Put all of those things in custom runners, so you can just click a button to watch them run in their own tab. This is especially useful for complex commands that you're likely to forget.

5. Go crazy with the layout

C9 lets you drag and drop tabs to dock to the left or right or bottom, and resize however you want. You can have a terminal on the right and server logs at the bottom, or keep them all in tabs in the same place. It's up to you. 

6. Don't ignore the project search (and replace)

If you're like me then you might be tempted to install The Silver Searcher or Ack or just use grep to search your codebase. Before you do that, at least give C9's code search a try. It's fast, it supports regex, and it gives you lots of options about where you want to search. It's surprisingly robust, so give it a shot.

The end

Overall I think Cloud9 is really pretty great for what it is. It's lacking some IDE features and it suffers a bit unavoidably just based on the fact that it's cloud based, but it also solves a lot of real world problems that make up for all that in most cases.

I'm using it for a pretty big chunk of my day to day development nowadays, and it's saved me plenty of headaches.

Do you have any concerns or questions? Feel free to comment below if so. I'm curious to hear about the types of things holding other people back from using it.

mcrittenden Tue, 01/17/2017 - 17:26
SRI International Drupal Case Study antonella Wed, 01/18/2017 - 03:00

Quizzes and contests are the ways to improve a user activity and to grab the attention of even a rather passive user. We’ll tell about Drupal modules enabling different widgets and voting feature/quizzes features: Webform default fields, Quiz, Advanced Poll and other are combined in this compilation. Click! :)

This one is dedicated to all my fellow Drupalers. There’s no better exercise for a brain than reading ancient chinese poetry taming Drupal 8. When I’m bored, I turn to Drupal!

Recently I got my Drupal 8 Address module updated and it turned out that from now on street address ...

Read now

Welcome to the third part of our series on writing Views query plugins. In part 1, we talked about the planning work that should precede coding. In part 2, we covered the basics of actually writing a query plugin. In this final chapter, we will investigate some enhancements to make your plugin more polished and flexible.

Exposing configuration options

Allow Site Admins to set their preferred units: metric or imperial.

Most Fitbit endpoints accept an option to set the units the response is returned in. If you are Canadian like me, you know that metric is preferable, but it’s also in our nature to be be nice, so we should expose a configuration option to allow our American friends to show data in their anachronistic imperial units. (I jest, love you guys!)

Exposing configuration options for a query plugin is done in two parts. First, build the UI and, second, make use of the stored configuration. In our query plugin class, we’ll implement two methods to help us create the UI, defineOptions and buildOptionsForm :

/** * {@inheritdoc} */ protected function defineOptions() { $options = parent::defineOptions(); $options['accept_lang'] = array( 'default' => NULL, ); return $options; } /** * {@inheritdoc} */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { parent::buildOptionsForm($form, $form_state); $form['accept_lang'] = [ '#type' => 'select', '#options' => [ '' => $this->t('Metric'), 'en_US' => $this->t('US'), 'en_GB' => $this->t('UK'), ], '#title' => $this->t('Unit system'), '#default_value' => $this->options['accept_lang'], '#description' => $this->t('Set the unit system to use for Fitbit API requests.'), ]; }

With this done, we should see our configuration options in the Views UI under Advanced > Query settings.

undefined

However, it won’t work because we’re not actually using the stored configuration yet. To do that, we’ll add to our execute method in our query plugin:

/** * {@inheritdoc} */ public function execute(ViewExecutable $view) { // Set the units according to the setting on the view. if (!empty($this->options['accept_lang'])) { $this->fitbitClient->setAcceptLang($this->options['accept_lang']); } // Clip... }

Query plugin options are available via $this->options, which Drupal provides as part of the QueryPluginBase class that our Views plugin is extending. We use the stored value, together with a method on the Fitbit client service to set the preferred units for all subsequent API requests: $this->fitbitClient->setAcceptLang($this->options['accept_lang']); . With that, site admininstrators can set their preferred units, and the result set will reflect that choice. Since this is Views and we’ve exposed height as a numeric field, Views core gives us a nice way to format the data and suffix it with units so we end up with a polished result. Just edit the field options.

undefined Field plugin options

Adding options to customize the appearance of the avatar field.

Views also allows us to have custom options for our field plugins. In the last article, we set up a field plugin for avatar which uses the avatar URI from the API response and renders it as an <img> tag. Fitbit’s API actually provides two avatar size options and it would be great to leave it to the site administrator to decide which size to render. We’ll use field plugin options to do that.

As with query plugins, exposing configuration options for a field plugin follows the same two parts, with one small addition. In our query plugin class, we’ll implement two methods, defineOptions and buildOptionsForm , to build the UI:

/** * {@inheritdoc} */ protected function defineOptions() { $options = parent::defineOptions(); $options['avatar_size'] = ['default' => 'avatar']; return $options; } /** * {@inheritdoc} */ public function buildOptionsForm(&$form, FormStateInterface $form_state) { $form['avatar_size'] = [ '#type' => 'select', '#title' => $this->t('Image size'), '#options' => [ 'avatar' => $this->t('Default (100px)'), 'avatar150' => $this->t('Medium (150px)'), ], '#default_value' => $this->options['avatar_size'], '#description' => $this->t('Choose the size avatar you would like to use.'), ]; parent::buildOptionsForm($form, $form_state); }

This should be fairly self explanatory; we’re defining a form element for the UI and, once saved, the configuration option will be stored in $this->options['avatar_size'] . The small addition I referred to earlier lies within the query plugin. Before, we were only passing along the single value for avatar. Now that the site administrator has the option, we’ll want to make sure both values for avatar are passed along in the Views result. We do that, in the query plugins execute method like so:

$row['avatar'] = [ 'avatar' => $data['avatar'], 'avatar150' => $data['avatar150'], ];

Instead of a flat value, we’re setting ‘avatar’ to an array with both values for avatar from the API response. Then, back in the field plugin, in the render method, we take care to use the appropriate size avatar according to the option selected:

/** * {@inheritdoc} */ public function render(ResultRow $values) { $avatar = $this->getValue($values); if ($avatar) { return [ '#theme' => 'image', '#uri' => $avatar[$this->options['avatar_size']], '#alt' => $this->t('Avatar'), ]; } }

We simply call $this->getValue($values), which is able to pull out the value we want from the ResultRow object. The render method receives a ResultRow object that has all of the data for the row. FieldPluginBase has a getValue method which we can access since we are extending FieldPluginBase . With that done, we can now click on the avatar field in the Views UI and set the desired image size:

undefined Filter plugins

Filtering the leaderboard by user id.

What if we wanted to limit the result to only a particular user? Say we wanted to show a user's Fitbit details on their Drupal user profile page. For that, we’d need to filter the result set by a user id. To make that happen, we need a Views filter plugin. The first step is to define the field to filter on in hook_views_data():

/** * Implements hook_views_data(). */ function fitbit_views_example_views_data() { // Base data and other field definitions... $data['fitbit_profile']['uid'] = [ 'title' => t('User id'), 'help' => t('Drupal user id, not to be confused with Fitbit profile id.'), 'field' => [ 'id' => 'standard', ], 'filter' => [ 'id' => 'fitbit_uid', ], ]; return $data; }

The part we are most concerned with here is the ‘filter’ key. Its value is an associative array with one key ‘id’, which we set to the name of the filter plugin we’re going to create. Also, note the ‘field’ key, which makes the Drupal user id available as a field in the Views UI. It doesn’t hurt to add it, and it also illustrates how plugins related to a certain field (e.g. field, filter, and others like relationship and argument) are all defined in the same array in hook_views_data(). So, for the next step, we’ll create this file: fitbit_views_example/src/Plugin/views/filter/Uid.php 

<?php namespace Drupal\fitbit_views_example\Plugin\views\filter; /** * Simple filter to handle filtering Fitbit results by uid. * @ViewsFilter("fitbit_uid") */ class Uid extends FilterPluginBase { }

So far, this is typical Drupal 8 plugin scaffolding code. The file is placed in the right folder for the plugin type. The namespace follows PSR-4 naming. The annotation for the plugin type assigns an id to our plugin. Finally, we extend the base class provided by Views for the plugin type. Now let’s look at the specifics required for our filter plugin implementation:

class Uid extends FilterPluginBase { public $no_operator = TRUE; /** * {@inheritdoc} */ protected function valueForm(&$form, FormStateInterface $form_state) { $form['value'] = [ '#type' => 'textfield', '#title' => $this->t('Value'), '#size' => 30, '#default_value' => $this->value, ]; } }

$no_operator = TRUE tells Views that we are not interested in the site administrators having an option to select an operator. In our case, we’ll keep things simple and always assume '='. You could, of course, allow for choice of operators if your remote service supports it. The key component here is the valueForm method. In it, we need to set an appropriate Form API element for the ‘value’ key of the $form array passed as the first argument. The name ‘value’ is important as the base class expects this key to work. The form element that you return is used in a couple of places. It’s used in the Views UI for when the site administrator is setting up a filter. It’s also used if the filter is exposed, rendered in the exposed filters form with the view itself. That’s it for the plugin implementation.  At this point we can add the filter in the Views UI:

undefined

The last step adjusts our query plugin to be able to handle and make use of the filter. The first thing we’ll need to do is implement an addWhere method on the query plugin class:

public function addWhere($group, $field, $value = NULL, $operator = NULL) { // Ensure all variants of 0 are actually 0. Thus '', 0 and NULL are all // the default group. if (empty($group)) { $group = 0; } // Check for a group. if (!isset($this->where[$group])) { $this->setWhereGroup('AND', $group); } $this->where[$group]['conditions'][] = [ 'field' => $field, 'value' => $value, 'operator' => $operator, ]; }

Here, especially, we can see Views’ biases to SQL rear its head. The method name, addWhere, is odd from our perspective of querying a remote service. There is no notion of a WHERE clause present in the Fitbit API. Further, Views supports grouping filters, and logical operators within each group. Here again, the remote service we are using has no notion of this. It’s possible the remote service your implementing does in which case the flexibility Views affords is amazing. In our case it’s overkill, but I’ve copied core Views implementation for the SQL query plugin, so we’ll be able to handle everything that the Views UI allows for setting up filters. The final step is adjusting the execute method on our query plugin to incorporate the filter into the call to the Fitbit API:

/** * {@inheritdoc} */ public function execute(ViewExecutable $view) { // Clip ... if (isset($this->where)) { foreach ($this->where as $where_group => $where) { foreach ($where['conditions'] as $condition) { // Remove dot from beginning of the string. $field_name = ltrim($condition['field'], '.'); $filters[$field_name] = $condition['value']; } } } // We currently only support uid, ignore any other filters that may be // configured. $uid = isset($filters['uid']) ? $filters['uid'] : NULL; if ($access_tokens = $this->fitbitAccessTokenManager->loadMultipleAccessToken([$uid])) { // Query remote API and return results ... } }

Here, we’re looping through any filters that have been configured on the view and grabbing their values. We then ignore any other filter that may have been configured on the view, since we’re only supporting uid for now and pass it along to $this->fitbitAccessTokenManager->loadMultipleAccessToken([$uid]), which will limit the access tokens we get back to just the uid set and only show us results for the corresponding user.

Often, as was the case on a recent client project, the filters that you set up will actually get passed along in the remote API request. The Fitbit API is a bit odd in this regard in that most endpoints only return data for a single user anyway, so there is no filtering that makes sense.

That’s it! After all that work, we can set up a filter by uid to limit the results to a single user.

Wrap up

We did it, at long last, we’ve produced a custom Fitbit leaderboard, which might look something like this:

undefined

Of course this is just stock Drupal 8 with the Fitbit module installed and configured, but it’s Views and we all know how to customize the look and feel of Views, so make it pretty to your heart's content.

While we've looked at a lot of code, I don't think that any of it has been horribly complicated. It's mostly a matter of knowing what to put where, with a healthy dose of planning to make sure our data fits into the Views paradigm properly. In summary, the steps are:

  1. Make a plan of attack, taking into account the data you're retrieving and the way Views expects to use it.

  2. Create field handlers for your data as necessary.

  3. Write remote queries to retrieve your data and store it in rows in the view object.

  4. Write filter plugins as necessary to narrow the result set.

There's a lot of work in those steps, but after running through it a couple times the architecture makes a lot of sense.

Get the code!

The code from this article can be found in the Fitbit module on drupal.org. It consists of a base module to handle application setup, authentication and access token storage and two sub-modules for Views integration. The first is fitbit_views_example, which I created specifically for this article series. You’ll find all the code we went through in there. The other one, fitbit_views is a more fully featured and slightly more complex version, including spanning multiple API endpoints with relationship plugins. You should use fitbit_views if your intending on using this functionality on your Drupal site. Feel free to file issues and patches!

Phew, that was a lot. Thanks for sticking with me through it all. Special thanks to Greg Dunlap for trusting me with the reboot of his original series, which has guided me through my own Views query plugin implementations. Thanks also to the Fitbit module maintainer, Matt Klein, who was kind enough to grant me co-maintainer rights on the project.

Benefit Cosmetics Drupal Case Study antonella Wed, 01/25/2017 - 03:00

Drupal 8 has a new core module, the Tour module, which allows us to set up a contextual help to guide users of a Drupal 8 site for their first steps on it, whether for the discovery of their user profile, the possibilities offered to them, how to create content or the overall management of the site's contents.

Direct .mp3 file download.

Dan Schiavone (schiavone), President, Snake Hill Web Agency, and local lead front end track for DrupalCon Baltimore and Elizabeth Lipinski (lizardata), Technolgy Strategist (also from Snake Hill) and the local lead business track joins Ted and Mike to discuss session submission for DrupalCon Baltimore. We also discuss Media in Core and changes to Drupal marketplace rankings before making our picks of the week!

Interview DrupalEasy News Three Stories Sponsors Picks of the Week Upcoming Events Follow us on Twitter Five Questions (answers only)
  1. Turning conference t-shirts into other things.
  2. Avast (anti-virus software).
  3. Not afraid of anything.
  4. Storks.
  5. Dan was jazzed after DrupalCon DC.
Intro Music Subscribe

Subscribe to our podcast on iTunes, Google Play or Miro. Listen to our podcast on Stitcher.

If you'd like to leave us a voicemail, call 321-396-2340. Please keep in mind that we might play your voicemail during one of our future podcasts. Feel free to call in with suggestions, rants, questions, or corrections. If you'd rather just send us an email, please use our contact page.

Introduction and quick guide to using sitediff - a handy site version comparison tool which helps you detect changes between various versions of a website.

read more
There are lots of situations in which you need to run a series of microsites for your business or organisation — running a marketing campaign; launching a new product or service; promoting an event; and so on. When you’re with Drupal, though, what options do you have for running your microsites? In this article I review and evaluate the options in Drupal 8, make a recommendation and build a proof of concept.So, I want to run some microsites …

A client brought me an interesting problem recently, something they need to solve for their production Drupal site. They are an international humanitarian agency who, alongside their main production website, want to run some microsites for a number of their public campaigns. Although they could run them on the main site, they’ve found too many limitations in trying to do that. Campaign teams, frustrated with the lack of flexibility and slow protocols for getting changes made to support their bespoke needs, have often gone off with their small budget and dynamic team to create something quick that fits their campaign with Squarespace or Wordpress or something.

That made the campaigners really happy. But, when the campaign or event lapsed, the campaign site quickly got out of date and went unloved, the campaign team moved on and no-one could remember how to log into the system and it became abandoned.

Hearing this story was so familiar — the same thing often happened when I was a senior developer at Oxfam International.

So, they said, could something be done about it? What, if anything, could be done with Drupal to support campaigners get their microsites running? What would give them the fast, bespoke solution to their microsite problems, whilst still keeping all the content well-managed and being able to share that content with the main site or other microsites?

I scratched my chin and had a think.

How about Drupal multisites?

Since some of its earliest versions, Drupal has included a feature for multi-sites — running several sites from a single codebase installation, sharing the core system, contributed and custom modules and themes. Each multisite has its own database, its own settings and configuration, its own content, and so on. Ideally, it also means updates can be done once.

So, multisites could be an option. Many people find them to be a real workhorse for their context, and often they are right on the money.

Why use multisites

The Drupal.org documentation for multisites includes a simple rule-of-thumb for when to multisite:

As a general rule on whether to use multisite installs or not you can say:- If the sites are similar in functionality (use same modules or use the same drupal distribution) do it.- If the functionality is different don’t use multisite.

(DrupalCon Austin [June 2014] held a interesting debate on Drupal multi-sites, its pros and cons, gotchas and suggestions, which is available on YouTube.)

There’s several compelling reasons to use them.

First, having a single codebase to maintain is a huge plus. Forked codebases can soon become orphaned, and unloved codebases become fraught with problems too quickly.

Second, multisites often mean there is also a single hosting platform to maintain, which is also a major advantage.

That can often mean, thirdly, that multisite installations can make better use of resources, both the server resources and financial, personnel or other physical resources. For example, since multi-sites share the same core and modules, that code need only go into the opcode cache once, saving server resources.

Caveat: is the end of multisites support on the horizon?

It should be noted that a proposal has been made to deprecate support for multisites in Drupal, with a view to removing it in the future.

The basic argument for this is that it’s an ‘old skool’ way of thinking about handling multiple sites. Git and Composer create practices and codebase structures that point in other directions.

The modern approach to multi-site is: git — Same code, different sites. Under your control. And well-maintainable.

There are a number of positive reactions to that proposal, which are variations on a theme:

+1. Multisite is a historical oddity at this point and I’d never tell anyone to use it.

But there are many more negative reactions, which largely go along these sorts of lines:

-1. Multisite has been a workhorse for a ton of Drupal sites and is well established in our code.

In that light, Drupal’s multi-site feature is likely to stay around for a while.

Classic problems with Drupal multisites …

It’s not all a bed of roses, though. There are some classic sticking points when working with Drupal multisites.

First off, handling traffic. One site’s traffic spike can be another site’s nightmare when the hosting resources are all hogged by The New York Times tweeting a link to a page on a site of yours; one site’s ‘BEST DAY EVA!’ can be the worst of times for all the rest.

The load on your database server may also be an issue. Multisites often use a single database server, and heavy load or slow queries in one DB can impact the performance of others. This might even be caused in the normal running of your Drupal sites, such as when running cron.

Running updates often causes headaches. When you update code, you’re updating all your sites at once. That means the updates are deployed, well, instantly across all your sites, but if they need update processes to run, such as updating the database, that can throw unexpected problems or errors.

And the worst of the worst: a small piece of poorly written, inadequately reviewed or tested code mysteriously jumps itself onto production — that never happens, right? No one ever lets that happen, do they? *ahem* — and takes down all your sites at once! It’s just an urban myth, a story to scare the children with at night, right? Never happens.

… and how to mitigate them

There are of course a number of ways to foresee these things happening and be ready for them.

On the performance questions, with smaller demands you can just ride it out — sites on the same hosting platform are fairly tolerant of resources being shared around, and the spare capacity is there for times just like there.

For larger performance demands, handling the pressure is a challenge in any hosting set-up, dedicated hosting just as much as shared. With modern cloud infrastructure, the option of scaling up your infrastructure or spinning up a new cluster when you’re experiencing ongoing heavy demand is much easier than in the past, especially if you plan for it as a possibility.

The next set of mitigations are all about best practice.

For starters, test, test, test. Don’t let any code onto production that hasn’t been tested thoroughly.

Have a solid release process that you always follow. If possible, include dev, staging and quality assurance stages. This should give you lots of points to catch things before they’re released onto your production sites.

Automate all the things. There are lots of ways of automating things to ensure they run consistently and quickly too, from shell scripts up to continuous integration tools. Use them.

And finally, be intelligent. With code changes that need database updates, for example, design your code so that it can be deployed to handle an interval before the database is updated. Or, with important but more volatile updates, be smart about choosing the time of day and week that you deploy it. Don’t ever push something out at 5pm on a Friday afternoon if you want to stay friends with your colleagues, your customers and your family.

Well, yes, in short, kinda. You could run microsites using Drupal’s multi-site feature. Things would work fine, though of course you’d have all the problems described above and have to take the mitigating actions.

However, it wouldn’t solve all the needs described above without some smart thinking. Plus, I’d suggest that you would also have some other problems to solve.

First, multisites all use different databases (sharing databases and tables is possible with Drupal multisites, but really unadvisable!) so the need of a single place for managing all the site content wouldn’t really be satisfied. The way around that would involve using web services, posting and pulling content from one site to another.

Neither would we have a unified search. There are fairly straightforward ways around that, using a tool like Apache Solr. The sites would need to share an index, with each document in the index including a site field, and there’s a contrib module that does that already (although no Drupal 8 version yet).

Lastly, and maybe more pertinently, you would still have all the ‘Drupalisms’ to live with. First of those is the visual design layer, the public user’s interface for the sites, what gets called the ‘theme layer’ in Drupal lingo. Many designers really dislike Drupal’s theme layer, and would really prefer to work with the pure frontend tools they use in other contexts. Drupal 8 has made major strides forward with the theme layer so it’s not as tough for designers as it once was, it’s true, but many (most?) frontend specialists would still rather not work with it.

Some consider influential Drupal figures consider multisites as ‘not enterprise grade’ and opinions like that are worth considering if your situation is enterprise scale.

Other approaches with Drupal

There are a few other ways of supporting microsites with Drupal that might be worth considering.

Domain Access

The Domain Access project was created to support just this kind of functionality. The project overview says as much:

The Domain Access project is a suite of modules that provide tools for running a group of affiliated sites from one Drupal installation and a single shared database. The module allows you to share users, content, and configurations across a group of sites.

This might work. However, there are many of the same problems with core multisites described above with this approach, with one additional one: everything in one database.

Our experience of using it, and this is echoed by others too, is that with a small number of very similar sites Domain Access can work well. With a larger number of fairly different sites, it’s a right pain and actually makes things quite difficult, requiring lots of complicated custom code.

Organic Groups

The Organic Groups suite of modules could be a solution for building microsites. The project allows users to create a ‘group’ within a Drupal site. The group can have its own users, admins, content, menus, even its own visual design. However, it would need every microsite to sit internally, within the main site, so does not solve the need to supporting external sites on their own domain. So, not really the perfect fit.

Best practice: with Git

I quoted above from @sun in the discussion on deprecating multisite support about the modern best practice:

The modern approach to multi-site is: git — Same code, different sites. Under your control. And well-maintainable.

This is certainly my standard recommendation and will give you many advantages: independence of sites for performance, design, etc; single codebase to maintain (though you’ll have a challenge developing and maintaining the variations you’ll want or need for each microsite); better control over updates; and so on.

You might even look writing an install profile to make a full distribution, though with Drupal 8 there is less of a need to do this. With Drupal 8, I’d advocate that you use Drupal Composer to build your site and just export your full site config into your repo (being careful to remove any sensitive settings from the repo with your .gitignore file).

Or you might also consider using Aegir to manage your multiple sites — use Drupal to deploy Drupal, if that’s not too much Inception.

Microsites and Drupal

So if multisites could work but would be a bit of a pain, the other Drupal approaches are even less appealing, and you’d rather not keep multiplying Drupal installations, how else could we do microsites with Drupal?

Well, there are two major moves in modern web development that might help here: RESTful web services, and decoupled CMS architectures (a.k.a. ‘headless’ CMS). My proposal for managing microsites in Drupal 8 depends on both these ideas:

  • Treat your Drupal site as a pure content management system (CMS) — a content hub that allows authors, editors and administrators to create, update and manage the content for which they’re responsible, but doesn’t have any meaningful frontend presentation layer to it.
  • Present the data of the content in the hub CMS via a RESTful API.
  • Implement a separate frontend for the visual presentation layer that communicates with the content hub CMS via the API.

There need be no limit to the number of frontends that use the CMS’s API (though practically you may limit access with firewalls, CORS or some other means) so you could power a primary public site, other sub-sites, native mobile apps or even another CMS or two, each potentially with their own visual design. The limit is your own imagination and situation.

RESTful web services and Drupal 8

A new addition to Drupal 8 is the RESTful Web Services API. REST resources can be exposed to allow other things to talk to/consume/feed a Drupal site. Many core entities have REST resources, but it is also fairly easy to build custom REST resources. (There a number of interesting web services contrib projects that are worth considering, such as the GraphQL project that presents a GraphQL schema, and the RELAXed Web Services project that extends the core REST resources.)

Design your own web services API

The freedom to build custom REST resources in Drupal 8 allows a lot of freedom in designing a RESTful API.

In a forthcoming blog post I’ll write in more about designing an API. For now, all I need to say is you need to actually design your API. Don’t simply use the out-of-the-box Drupal core REST resources — think about the RESTful API that would best serve the frontend you want to have.

My heartfelt recommendation is you do this, designing your API, using the skills of those who’re best at designing things — your designers. They understand best what your users want to do on your sites, will be able to describe what data they want for the frontend (content with/without markup, etc.) and help you design the API that is most appropriate to your needs.

There are some API design golden rules and best practices that you should consider. Also I’d recommend using an API design tool like Apiary.io or Swagger.io. They’re invaluable for many reasons, not least of which is the lovely documentation they generate and mock data servers they include that can help frontend devs get going quickly.

Decoupled frontend

With the content hub now presenting the managed content as RESTful data, we just need a standalone frontend system to present your website to your users: one for your primary site, and one for each of your microsites. Your frontend specialists can then work with the right tools for the task, then.

There are several advantages to consciously uncoupling the content management and the frontend.

Freedom: frontend specialists are free to the implement the user experience with native tools that are built for the job.

Performance: everything in this architecture can be streamlined. The CMS simply presents the content data. The frontend focuses on the display logic.

Experience: the website can respond to users in real time, communicating back and forth with the CMS to give real-time interactions in the browser.

Future proof: it becomes much easier to replace any part of the system as you require, such as redesigning the website without re-building the CMS.

Microsites in Drupal 8

So, how might we do this practically in Drupal 8? Here’s how I tackled it.

First, I thought about designing a quick prototype API that could be used to describe microsites and their content. I used Apiary.io to design it, and you can view the API at docs.campaignmicrosites.apiary.io.

API design at docs.campaignmicrosites.apiary.io

Next, I installed a Drupal 8 instance with Drupal Composer to act as the editors’ content hub and created a ‘Campaign’ content type with some basic fields. This ‘Campaign’ content type is the core of the microsite support. Each Campaign creates a new microsite.

Since in this client’s conundrum the microsites can be internal (i.e. sit within the main public site) or external (i.e. on their own domain or sub-domain) I added two fields:

  • external site (true/false boolean)
  • external URL (URL)

These will allow requests for the microsite from within the main site to be redirected to the external URL, and will help in constructing the right data in the API resources.

‘Campaign’ content type in Drupal content hub

I also adapted the core Article content to include an entity reference to a ‘Campaign’ node, and included a taxonomy reference field to indicate the ‘type’ of article — news; FAQ; info; etc.

The next task was to create the REST resources that matched the APIs I’d designed. For this I created a custom module, campaign_api, and created four classes, one for each of the API resource collections I’d designed, in the `Drupal\campaign_api\Plugin\rest\resource` namespace.

Drupal custom module for the new REST resources

The quick and dirty code for the `get` method on the Campaigns resource looks like this:

/**
* Responds to GET requests
*
* Returns an array of Campaign data.
*
*
@param null $unserialized
*
@param \Symfony\Component\HttpFoundation\Request $request
*
@return \Drupal\rest\ResourceResponse
*/
public function get($unserialized = NULL, Request $request) {
$build = [];
// Default langcode
$langcode = $request->query->get('langcode', 'en');

// Load campaign nodes
$query = $this->entity_query->get('node')
->condition('type', 'campaign')
->condition('langcode', $langcode);

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

// Array of image styles to support
$image_styles = [
'large' => 'full',
'medium' => 'medium',
'thumb' => 'thumbnail'
];

/** @var NodeInterface $campaign */
foreach ($campaigns as $campaign) {
$image_array = [];
$image_file = File::load($campaign->get('field_image')->target_id);

foreach ($image_styles as $name => $style_name) {
$style = ImageStyle::load($style_name);
$image_array[$name] = [
'url' => $style->buildUrl($image_file->getFileUri()),
'alt' => $campaign->get('field_image')->alt,
];
}
$external = (integer) $campaign->get('field_external')->getValue();
$build[] = [
'id' => $campaign->id(),
'uuid' => $campaign->uuid(),
'langcode' => $campaign->language()->getId(),
'languages' => [
$campaign->language()->getId() => $campaign->language()->getName(),
'default' => $campaign->language()->getId(),
],
'title' => $campaign->getTitle(),
'created' => $this->date_format->format($campaign->getCreatedTime(), NULL, 'c'),
'external' => !empty($external),
'external_url' => $campaign->get('field_external_site_url')->getValue(),
'description' => [
'formatted' => check_markup($campaign->get('body')->value, $campaign->get('body')->format),
'raw' => $campaign->get('body')->value,
],
'image' => $image_array
];
}

$response = new ResourceResponse($build);
$response->addCacheableDependency($langcode);

return $response;
}

Enable those resources (by clicking stuff with REST UI module installed, if you like), of course, and then create some content to populate the responses — one campaign called ‘DIY succulents’ and the other ‘Slow-carb cred’ (yep, I used some Hipster Ipsum).

Enable the resource endpoints

Then you should be able to retrieve your data at the appropriate endpoints. A nice way of doing that is with the free Postman app (there’s a Chrome extension also). Postman makes a request to the endpoints you specify and pretty-prints the response. Marvellous!

The final part is the standalone frontend tool. For this I used React. I used React to build my frontend app, but there’s obviously plenty of other options depending on what the frontend needs to do. React worked for me because I just wanted the view layer, but Angular or Ember could be more appropriate if the frontend needed to be a more substantial app. You’d need to evaluate the frontend options carefully.

I’m not a frontend specialist, so my prototyping code is pretty fugly. Despite that, we’re able to serve two microsites simultaneously on different URLs, with a different theme, just by switching the campaign ID in the API request.

Bingo!

Deploying to production

There’s a few things I might do to deploy this to a production system.

Secure serving

As a good internet citizen, I’d want to put everything on SSL.

Frontend deployment

To deploy the frontend, I’d be looking at options to run the apps on a NodeJS server so that most of the scripts can run server side.

I’d probably want to put an Nginx instance in front of it, for SSL termination, caching static assets and reverse proxy.

Use Drupal multisites ;-P

I think there is actually a neat way of using Drupal’s multi-sites feature here: use a different domain for the RESTful API. For example:

Editorial interface: hub.yourdomain.com
API interface: api.yourdomain.com

Both of these point to your Drupal codebase but you can then handle requests differently on each domain. For example, you might add an authentication provider that checks the domain to give you some access control, so there’s no access to the editorial interface on the API subdomain, and none to the API on the editorial domain.

Caching etc.

This would then allow you to do some smart things with caches and other parts of your hosting stack, offloading much of the pressure on the codebase to the caching architecture and removing the actions of editorial staff from affecting the RESTful API’s performance.

Databases

It might also be possible to configure GET requests to only use a slave database, which could be useful for performance — though may be more hassle than it’s worth. POST, PUT, PATCH and DELETE requests would still need to go to the master.

In summary

This prototype worked really well for me and I was very happy with the results, and it gave me something very interesting to discuss with the client.

The advances made in Drupal 8 to operate with current standard web practices are good news for developers and for web projects big and small. For this prototype, the particular improvements with providing RESTful resources means that I was able to create a decoupled Drupal system to support a main website and unlimited microsites in an amazingly short space of time.

… and something to take away

If you’re interested in following up this thought experiment with my Drupal 8 prototype, I’ve put the code into a repo in GitHub:

ConvivioTeam/Convivio-ContentHub

Just …

$ git clone git@github.com:ConvivioTeam/Convivio-ContentHub.git {some_empty_directory}
$ cd {some_empty_directory}
$ composer install

… and you’re away.

(My React code is shamefully dirty, so I’m not prepared to share that at moment. ;-) I may tidy it up in the future and share it here.)

Main image: courtesy of Denys Nevozhai/Unsplash. https://unsplash.com/photos/guNIjIuUcgY

Convivio helps organisations to work better for people.

We do this mainly by helping them transform their services using digital tools, but also by spreading new ways of working.

Read our blog: blog.weareconvivio.com
Follow us on twitter:
@weareconvivio
Get in touch:
hello@weareconvivio.com
Visit our website at
weareconvivio.com

Managing Microsites with Drupal 8 was originally published in Convivio on Medium, where people are continuing the conversation by highlighting and responding to this story.

Miriam Webster defines effort as conscious exertion of power: hard work

If you want to learn Drupal, you need to put forth some effort, and if you want to do it properly, get ready to exert some power for months, not days.  People ask us all the time if they can get a job right out of our Drupal Career Online program. The truth is, it depends on how much hard work you put in to get out ready enough for an internship or junior position. Whether it’s Drupal or anything else, learning something and being able to apply it well depends on how much you absorb and practice, both of which are best done over time.

Last summer, James Dennin wrote an insightful piece of advice for those seeking careers in coding for Fusion.net. It touches on a lot of the same issues with bootcamps that we have heard about for years from students who come to DrupalEasy Academy after disappointing experiences. While we don’t like to throw barbs, we like less the sad stories of lost dollars and time in unguided crash courses where people are seated in a room, immersed in videos and teamed with other, non-skilled newbies on trying learn Drupal. A 5- or 10-day whirlwind of information overload is seldom a successful learning experience.

Becoming proficient in Drupal is no cakewalk; it includes amassing knowledge, learning best practices and developing skills as part of a challenging learning process, whatever your process may include. Education experts recognize as many as seven different styles of learning, including:  Visual, Aural, Verbal, Physical, LogicalSocial and Solitary. Most people find a combination works best. For anyone, regardless of the learning style; taking the time to really soak it in and get some hands on experience is key. The bottom line is that Drupal takes time and practice.

For those who do well on the solitary route, Build-a-Module, which routinely supports students and alumni of our career training program, has a solid, comprehensive library of instructional videos that you can take your time to work through with a modest monthly subscription.  You can also check out Drupalize.me.

For those who learn better with a formal course or need to train-up a team; our Drupal Career Online program uses live instruction; a stackable-skill designed curriculum; practical exercises; and group learning.  We also provide resources like lesson guides, screencasts for every lesson, and help when you need it. In addition to all the great feedback we get from our students and all the great graduate case studies, we ensure our program meets accepted educational standards as a career program, so we go through an annual review to ensure we remain a licensed, post-secondary institution through the Florida Department of Education, Commission for Independent Education (see page 21 of the linked PDF.)  

We are committed to Drupal and developing awesome Drupal talent, which is why we cringe when we hear about drinking-out-of-the-firehose learning scenarios. It is also why we have been perfecting our course (yes even making it longer) over the past 6 years. Best practices and allowing students the time to soak up what they’ve learned, along with hands-on projects and expert-developer instruction are fundamental elements of Drupal Career Online. It includes 84 hours of live, online instruction over 12 weeks as part of the learning community of current students and alumni. The course covers practical projects and assignments, and includes 12 co-working labs and instructor office hours, which are available to current students and alumni every week. The Spring 2017 session begins March 13, with the deadline to apply March 6.  

For most, learning anything, especially Drupal, is a process that takes an investment of time and effort, not just from the students, but from those who endeavor to help them learn.  Don’t cheat yourself and risk wasted time by trying to save time. Whatever learning styles work for you, make sure you take the time and put in the effort to follow a logical path that builds knowledge and helps you get comfortable with key skills in the way that ensures your hard work leads to your ultimate success.

For more resources about becoming a Drupal developer, take a look at our Career Resources.  To learn more about our upcoming Drupal Career Online Spring session, sign up for one of our free Taste of Drupal online information sessions in February.

take your time concept clock Photos by Pond5

Entity Lookup & Generate migrate process plugins

Thanks to the drupaleros community, Drupal 8 has two new plugins added in the migrate plus module: entity_lookup and entity_generate. These can be used to lookup and create an entity if it does not exist. I will show you a way in which we can implement these plugins and we will see for what applications they can be used.

Ada Hernández Wed, 01/25/2017 - 10:06
As the first month of the new year comes to an end, the Drupal Community is ramping up for the many DrupalCamps and annual DrupalCon that are sure to happen. As part of our Web Dev Wednesday, we compiled a list of DrupalCamps in the United States everyone should attend.   

In Drupal 7, if you wanted to reference a view display from a node field, you had to use a module such as Viewfield. In Drupal 8, this can be done with Drupal core alone by using the built in entity reference to reference a block instance created from the view.

Step 1: Create a hidden region in your theme.

1. Open your THEMENAME.info.yml file.
2. Find the section for "regions:"
3. Add a new line: hidden: 'Hidden region for referenced blocks'

Completed Drupal site or project URL: http://umn.edu

Simply put, University of Minnesota is enormous. Nearly 70,000 students are enrolled at this Big Ten university with five major campuses spread throughout the state of Minnesota. Much has evolved since it was founded in 1851, but the University’s core values remain the same: enrichment by understanding, advancement of learning through education, and the search for truth through research; all of this to benefit the people of the state of Minnesota, the nation, and the world.

The University of Minnesota was planning to replace its existing Oracle Universal Content Management (UCM) system with a flexible, hosted Drupal implementation. The University’s UCM implementation had more than 600 sites, which represented a considerable amount of storage, and millions of site visitors monthly. Furthermore, while the University has a central Office of Information Technology (OIT), the system is a distributed environment where each collegiate unit has its own management structure and its own internal Web team.

OIT wanted to create a centralized platform that would be an attractive and more easily maintainable alternative to departments spinning up their own independently-hosted sites. Several pilot sites would serve to provide representative real-life examples of various use cases for the platform.

Key modules/theme/distribution used: PanopolyWorkbenchMigrateZenOrganizations involved: Palantir.netTeam members: agentrickardCrell

Recorded January 19th, 2017

This episode we are ringing in the new year and giving you all a treat, by letting someone else talk. We welcome Fabian Franz, a core committer for Drupal 7  and co-creator of Ryan’s favorite thing in the whole wide world, Big Pipe. You do have to listen to us a little as we talk about Mediacurrent’s awesome blog posts, and Drupal News. Mario brings us the first Pro Project Pick of the year and we’ll finally shut up with Ryan’s Final Bell.

Before working on the Session Track description, I spent some time researching. There are lots of blog posts on the business of Drupal, plus surveys and articles - and, of course, what other Session Track committees have researched and put together.

What it seemed to come down to this year was our own unified experiences - and the first ever Drupal CEO survey that supports what we see and directs our topics.

Pages