Dec 19 2014
Dec 19

Code that performs well should be an assumption, not a requirement. I've never had a client ask me, “will your code make my site run slower?" Clients just assume that I'm going to deliver a codebase that does not hold things up.

However, over the years, I've discovered that code can actually have a major impact not just on how well the website runs, but also on how  much work a coder can get done. And here is the big surprise: a lot of the code I review for others, or sometimes code that I wrote years ago myself, doesn't allow me to work as quickly as I (or the client) would like. It actually sometimes slows me down so much that, by the end of the day, it would have been quicker for me to just rewrite it from scratch, using efficient code and accepted coding standards.

The background to this post

I was recently in contact with a client that had a website which was performing poorly - a pretty standard Drupal 7 website (which somehow took over a year to develop). When the site was eventually delivered, it was so full of bugs that the original development company couldn't (or wouldn't) fix it. The task was clear: make the site run faster (a normal content page would easily take over 10 seconds to load) and fix as many bugs as you can within three days.

Before meeting on site with the client, I got a copy of the codebase and began to make myself familiar with it. Oh man. This already looked monumental. I got scared. Scared because I wasn't sure that I could touch anything on the site without making it fall apart, or making things even worse, or conflicting with another piece of code somewhere else. Or ...?

I'm going to give you a couple of examples of what the client and I decided to do, along with some advice I'd like to give to the original developers if I had them sitting next to me. There will be more in future parts of this series.

Files and folders

There was basically no file/folder structure to speak of. Almost every module was placed in a flat hierarchy, except for some custom modules and the odd (unused) feature. So there was approximately 150 folders in sites/all/modules. But I had no way of knowing if they were patched contrib modules, a custom module, or a sandbox module. They could have been anything. Updating modules was a matter of convincing ourselves that the site would probably break somewhere, and we could take it from there.

I suggested that we left the structure as it was for now, but that they should consider creating a structure that looked similar to this (basic Drupal good practice):

drupal-root-folder
- sites
- - all
- - - libraries
- - - modules
- - - - contrib
- - - - contrib-dev
- - - - contrib-patched
- - - - custom
- - - - custom/features
- - - themes

If a module is patched, put the patch in the module folder, so it can be re-applied if needed when next updating that module. This will also make any new developers that come to the project aware that they should pay extra attention to this module. It's also good practice to contribute the patch back to the community if you think other projects might benefit from it.

Warnings and notices

I hate warning and notices. On this website, they were everywhere. Hundreds of warnings and notices on every page. The former programmer/site builder's solution to this issue appears to have been: turn off message logging. I know that makes sense in a production environment, so you don't expose a weakness to a potential hacker of the site, but it does not solve the underlying problem. To me, it just looked like a developer trying to fool a client, and ensure that, though the site had major issues, the client wouldn't be aware of them.

At one point it was so bad that the customer had to turn off the logging system to help the database that was being overloaded with error logs. However, this meant that if there was a problem - such as the site getting hacked - they couldn't do any meaningful debugging because there was no error log to check.

The solution was pretty simple: start from the homepage and fix all the code that was throwing warnings and errors. Next move on to a sub page, and so on. I spent long, long hours on this, but the work paid off in the end: we got the amount of warnings down to a level where it was possible to have the logging system running again so we could get some real debugging done.

But I still couldn't touch the logic in the code, because I still didn't have a clue what most of it was doing.

Indentations and variables

It is obvious to many programmers that coding standards matter. In this case the developers didn't care about correct indentations, or any other coding standards for that matter. This is an example of what a typical piece of code on that site looked like:

        case 'tasks_node_form':
          $key_value = array_keys($form['field_task_listing_ref']['und']['#options']);
          $ff = array_shift($key_value);
          $new_arr['_none'] = '- None -';
          foreach($key_value as $val)
          {

              $inode = node_load($val);

              //$new_arr[$val] = $inode->title.' -> '.second_mlid_title($val);
              // calling functtion to get complete listing (added by Bob the Builder)
      if(get_complete_listing($val) != ''){
              $new_arr[$val] = $inode->title.' -> '.get_complete_listing($val);
      }
          }
          $form['field_task_listing_ref']['und']['#options'] = $new_arr;
          $form['#after_build'][] = 'custom_after_build';
          $form['#validate'][1] = 'lets_compare_date';

      foreach ($form['field_task_elements']['und']['#options'] as &$option) {
            $option = decode_entities($option);
        }
      foreach ($form['field_section']['und']['#options'] as &$option) {
            $option = decode_entities($option);
        }


     break;

No, there's nothing wrong with your screen, this is how the code was presented when I saw it for the first time. It's almost impossible to read and understand when you have 2000 lines of code looking like that.

But, look carefully and you'll also see a XSS security issue.

You can read more about how you should indent your code (and other coding standards) here.

Comments

The code contained comments. Really, it did. But there was no point to them. They didn't help me to understand what was going on at all. Comments like, "Loop through array", "Call function that cleans up" and "Returning the array". And one that really scared me: "If the alias already exists, generate a new, hopefully unique, variant". We are hoping for a new variant? Why not just make sure it's unique?

The rest of the comments were primarily just bodies lying around (dead, unreadable or commented code). No tombstones (comments, telling why the code is commented), so I could't tell if the code had a reason to stay there or not.

Here are some general rules when commenting code:

  • Don't ever leave commented code in your code base, unless you write a comment above it, telling why this code should stay in there.

    • A "we might need this later" comment isn't good enough. That's what your SCM (Source Control Management, like git or SVN) is for. You can always go back in your scm's history, and resurrect your code from there.

  • Don't state the obvious.

    • I know a loop when I see it. I can read the return statement, there is no need to comment it. I want to know why you are doing something, not what is being done. Don't tell me that you called the clean-up function. Tell me why we need to clean something up.

  • In general, don't comment variables.

    • It's way better to give the variable a descriptive name. If you can't tell from the name of the variable what it contains, you should consider renaming it.

    • Of course, there can be situations where a variable can hold an unspecified data type or unspecified content, and here it is important to make sure that you write a comment saying that.

  • The most important comments in the code are the DocBlock (documentation block) comments.

    • These are the comments that are before EVERY function throughout your code. Don't EVER create a function, without creating a good DocBlock. They are not hard to write. Read more about them here.

    • A good DocBlock doesn't take long too write. If it does, you probably did something else wrong, like your function is doing too much. Try to split it into smaller more specific functions.

    • The first line of the DocBlock is an especially good indicator of whether your function is trying to do too much. The first line must contain a summary of what your function is doing. And it's a one-liner only (80 charecters max). If it takes more than that to write a good summary, consider splitting the function.

    • After the first line, you leave an empty line, and after that again, you can add descriptive, in-depth explanations.

    • Lastly remember to describe all the parameters and the return value as well, using @param and @return.

  • Keep in mind that the DocBlock design that I describe above isn't necessary when you are writing hook functions.

Drupal Coding Standards

Drupal's Coding Standards are there for a reason. They weren't created for fun, or to make text look pretty.

When you return to a broken or unfinished module, or when you read unfamiliar code, and the code is strictly written to comply to the standards, you know how to read it straight away. You know what to search for, because the variables are in the same format. You know what every single function is doing, because it's explained in the comment above the functions. You know what data type a function's parameters expects, and what every function returns.

That's what allows the developer to perform - to get work done quicker. In the long-term, it's a money saver.

Conclusion

The site was FUBAR BUNDY.

What I suggested to the client was something like "Lets get this patched up, so it can last at least a while longer, and then get something new built."

I suggested that they should build the new version themselves as they were now familiar with Drupal and how to code Drupal modules. They could then just get help from consultants like Annertech to help with any tricky aspects that might crop up.

I'd like some help from Annertech

Dec 18 2014
Dec 18

Lose weight. Eat better. Run a 5K. Travel more. These are resolutions we all make year after year. But this year, we challenged our team to think outside the box and inside the drop. Now that 2014 has come and gone, and we prepare to countdown to 2015, we asked our team what they are looking to accomplish in Drupal in the New Year.

“Get more of my modules out for D8.” - Andrew Riley

"Push the limits of what Mediacurrent can do with Drupal." - Brad MacDonald 

"My goals for 2015: Get up to speed on D8 (have lots training materials, yay continuing education!), port all of my modules and have a 1.0 release." - Damien McKenna 

"A real one for me would be to release more modules publicly. I guess to be more specifc, find more problems that need solved and solve them by releasing a contrib module to the community" - David Younker

"You know the usual... Eat better, workout more, lose 20 lines of code..." - Mark Casias

"For me, it's learn Drupal 8 and port Advanced Forum and Author Pane to it." - Michelle Cox 

"Resolution: Build something with headless Drupal and a JS MVC... And get more t-shirts." - Zack Hawkins

"D8." - Rob McBryde 

"One of the things I'd like to accomplish at DrupalCon 2015 is to speak on behalf of Mediacurrent.  I think this will be very challenging and intimidating and that's exactly the reasons why I want to do it. Also, I want to learn more about Drupal 8 and in particular Theming with Twig." - Mario Hernandez

Here at Mediacurrent, we're all about helping people reach their goals through our Drupal expertise and resources. So what is your Drupal New Year's Resolution and how can we help you make them a reality? Let us know in the comments what you'd like to see more of on our blog in 2015!

Additional Resources

Why You Should Speak at Tech Conferences | Mediacurrent Blog Post
10 Things I Wish I Knew About Drupal 2 Years Ago | Mediacurrent Blog Post
Resource Guide to Drupal 8 | Mediacurrent Blog Post

Dec 18 2014
Dec 18

PhotoIn the beginning there was the Common Gateway Interface, commonly known as CGI – a standard approach used to dynamically generate web pages. Originally devised in 1993 by the NCSA team and formally defined by RFC 3875 in 2004, CGI 1.1 took seven years to go from the original RFC to an endorsed standard.

In 1994, not long after the original CGI standard was documented by NCSA, Rasmus Lerdorf created Personal Home Page tools (PHP Tools), an implementation of the Common Gateway Interface written in C. After going through a number of iterations and name-changes this grew to be the PHP language we know and love.

One of PHP's strengths was the way in which it made many of the request and server specific variables, as defined by the CGI standard, easy to access – through the use of superglobals, namely $_POST, $_GET, and $_SERVER. Each of these is an associative array. In the case of $_POST, the request body is parsed for you and turned into an array of user-submitted values, keyed by field name, and conveniently supporting nested arrays. Similarly for $_GET, the query string is parsed by PHP and turned into a keyed array. In the case of $_SERVER, the gamut of server-specific variables are available for your script to interrogate.

Now, as Drupal developers, we rarely interact with $_POST and $_SERVER, and seldom interact with $_GET. Variables submitted through forms are abstracted behind Drupal's Form API; we ordinarily work with the $form_state variable instead of $_POST. In terms of the $_SERVER superglobal, Drupal provides handy wrappers for many of these values too, so instead we interact with those rather than with $_SERVER directly.

Please note that this article is accurate at the time of writing, however there is a proposal (see http://wdog.it/4/1/attributes and http://wdog.it/4/1/match) to improve the developer experience of working with important attributes stored on the Request object. The goal of these issues is to introduce methods on helper classes to make access to important elements of the request/response life-cycle more explicit instead of relying on using arbitrary string keys to fetch items from the Request object.

Under the proposal, items that relate to the routing system will be available from a RouteMatch class containing useful methods, for example RouteMatch::getRawArguments(). This would be used instead of $request->attributes->get('_raw_variables'). Under the proposal this will form a key developer facing API for working with upcast routing parameters so RouteMatch::getArgument('node') will replace $request->attributes->get('node'). This makes sense because the node object is not part of the request, it is a product of the routing of that request.

In addition the existing RequestHelper class will be expanded to add additional methods for interrogating concepts related to the Request but unrelated to routing. For example RequestHelper::isCleanUrl() can be used to determine if the incoming request utilizes clean urls, instead of $request->attributes->get('clean_urls').

Before using the example code in this article, be sure to first review the above issues.

If It Ain't Broke, Don't Fix It?

So what's wrong with using $_GET, $_POST, and $_SERVER in conjunction with some other Drupalisms™ like arg() and current_path()?
Well, does the code below look familiar?

attributes->get(RouteObjectInterface::ROUTE_NAME);
 
if ($route_name == 'mymodule.someroute') {
  // Do something.
}

Getting Request Headers

The Symfony Request object also includes a HeaderBag (Symfony\Component\HttpFoundation\HeaderBag), which gives easy access to any request headers you might need. The HeaderBag contains the same convenient methods as the ParameterBag

Deep Integration with the Routing System

Looking back at that same routing entry from forum.routing.yml, you'll note the 'defaults' section. Those values can also be found in the attributes parameter bag:

attributes->has('foo');
}

Now while that might seem simpler than having the Request object passed in as an argument, you should resist the temptation to use \Drupal::request() in object-oriented code. Calling out to the global \Drupal singleton in your object-oriented code makes unit-testing your code more difficult, as you need to setup a container, add the request to it, and then call the setContainer method on \Drupal before you can do so.

Injecting the Request Into a Service

If you are creating a service and you need access to the request, you can nominate it as a dependency in your services.yml file thusly:

services:
  mymodule.foo:
    class: Drupal\mymodule\MyModuleManager
    arguments: ['@database', '@request']

But this depends on the life-cycle of your service, as the request service isn't always available. For information on how to create a service that might need to be instantiated before Drupal enters the Request scope, see the Getting Advanced section later in this article.

Bring Your Own – Creating a Request

If you're writing code, such as a custom application or a shell script that lives outside the normal Drupal bootstrap, you might find that you need to instantiate a Request object. Or you might be working on some tests and wish to create a pseudo Request. In these cases, you need to build your own Request object. There are two approaches to doing so, depending on your use case.

Transforming Globals Into a Request Object

If you're working in a script or custom outside the standard Drupal bootstrap, you can easily transform the superglobals into a Request object using the static createFromGlobals method:

Making Your Own Request

If you need to create a request for simulation purposes while testing or some other purpose such as a sub-request, you can manually create one using the static create method. This takes arguments for the URL, method, parameters, etc.

  
Dec 18 2014
Dec 18

You may have heard and read a lot about Drupal 8 lately, without much support to go along with it. Well here at Blink Reaction, we are working on changing that and contributing as much help as we can to the community with the issues that we’ve come across so far in Drupal 8. In this post I will show you how you can try Drupal 8 by installing dependencies such as composer and drush so you can have a Drupal 8 site running on your local machine.

Disclaimer:

For this blog post I will be using Mac OS X Yosemite which is the OS I have on my development machine.

To follow this walkthrough you should have an *AMP stack installed and working on your machine. If you don’t already have an environment, here are some options: 

* Mac: Acquia Dev DesktopMAMP or php-osx
* Windows: XAMPPWAMP or Ampps
* Linux: Install with your package manager or Ampps
* Use a Virtual Machine

Whichever environment you choose, make sure you have the following:

* PHP 5.4.5 or higher (very important!)
* A MySQL server that is configured to work with PHP

Download and Install Composer

Composer is a dependency management library for PHP. Follow the instructions from the composer website at https://getcomposer.org/download. You can download it anywhere onto your local computer. 

Then, if you have curl installed:

$ curl -sS https://getcomposer.org/installer | php?

Or if you don't have curl installed:

$ php -r "readfile('https://getcomposer.org/installer');" | php

Accessing composer from anywhere on your system:

To access composer globally move the executable 'composer.phar' to a directory that is already in your PATH.

$ chmod +x composer.phar
$ mv composer.phar /usr/local/bin/composer

Download Drush

Clone the drush git repository in a directory that is outside of your web root.

$ cd /usr/share
$ sudo git clone --branch master https://github.com/drush-ops/drush.git

Install Drush

From the drush root directory, run composer to fetch the required dependencies.

$ cd /usr/share/drush
$ sudo composer install

Accessing Drush from anywhere on your system.

Create a symbolic link to the Drush executable in a directory that is already in your PATH.

$ ln -s /usr/share/drush/drush /usr/bin/drush

Download Drupal

At the time of writing this blog post the latest release of Drupal is 8.0.0-beta3. In order to download Drupal 8 we will use drush dl command an alias for drush pm-download.

$ drush dl drupal-8.0.0-beta3
$ mv drupal-8.0.0-beta3 drupal8.dev

Install Drupal

Change to the directory where Drupal was downloaded by drush and use drush si command as an alias for drush site-install.

$ cd path/to/drupal8.dev/
$ drush si standard --db-url=mysql://root:root@127.0.0.1/drupal --site-name=drupal8.dev --account-name=admin --account-pass=admin --account-mail=jesus.olivas@blinkreaction.com -y

Make sure you use your own user and database credentials when running drush si and never user root on production. In this example we are accepting any interaction - answering yes when passing -y argument.

As you can see, when using Drush the process is very similar to previous Drupal versions - drush dl & drush si.

Finally, if you want to access your Drupal 8 site using http://drupal8.dev you will have to:

Add a new host in your hosts file (‘/etc/hosts’ as I am using Mac OS X)

127.0.0.1 drupal8.dev

Add a new virtual host in our web server config. Apache, in my case.


   ServerAdmin jesus.olivas@blinkreaction.com
   DocumentRoot "/path/to/drupal8.dev"
   ServerName drupal8.dev
  
       Options FollowSymLinks
       AllowOverride All
       Require all granted
  

References:

* Composer: A dependency manager for PHP - https://getcomposer.org/
* Drush GitHub repository - https://github.com/drush-ops/drush
* Drupal project page - https://www.drupal.org/project/drupal
* Detailed information about drush commands -http://www.drushcommands.com

Note:

If you want to try Drupal 8 now. without worrying about configuring your local environment you may use the following online services:

https://insight.acquia.com/free?distro=drupal8
http://getpantheon.com/d8 
http://trydrupal8.com/ 
http://simplytest.me/

Have questions? You can catch me on Twitter @jmolivas. Stay tuned for more helpful posts on Drupal 8.

Blink Reaction sponsors the Console project for developing in Drupal 8.  

Visit http://www.drupal.org/project/console to try it. Please feel free to submit issues and requests!

Dec 18 2014
Dec 18

28 pages of unmarred perfection. This book is pure unadulterated genius

- Chris Arlidge

Never Be Shocked Again! - Budgeting your Web Project

Are you having trouble figuring out an appropriate budget for your next web project? Our whitepaper can help!

Download your FREE COPY, to learn the different types of website projects, understand the factors that play a role in the budgeting process, and determine where your web plans will fit when it comes to costs!

Don’t ever be shocked by web costs again! A clear guide to help you plan the budget for your next web project.

I have been privileged to be able to attend a number of conferences and events, such as DrupalCon Austin, Portland etc,  since we started Cheeky Monkey Media. In the past, we’ve talked about having your DrupalCon Survival kit prepared before you head out the door to help make the most out of any conference or large group you are attending.

BADCamp (Bay Area Drupal Camp) is no exception to this rule. For those of you who are not aware, BADCamp is a conference which focuses solely on the people behind the keyboards and is held annually in San Francisco. The organizers do a ton of work to make this event happen and it shows.

This was our first year going to BADCamp and what an experience. We had the opportunity to check out a great city such as San Francisco and to meet a lot of like minded Drupal developers. The speakers, the sessions, the mini-summits, all delivered on the value we had hoped they would.

Going to this event, we had to make sure we followed our own advice and got prepared.

Why are we going?

That was simple, to just have an opportunity to be there to learn and network with peers on a one on one basis. Typically when we hit events like DrupalCon, there are a lot of competing factors which can get in the way of having the time to take in sessions, such as manning the booth, meetings … the list can go on and on. This time though, we went simply to learn something new and bring it back to our team.

Where are we staying?

We found a great deal on Hotels.com for an older character hotel in the core. We got to experience a bit of glam and see some of the spots we were warned not to go at night time. From our location, it was a 5 to 10 minute taxi ride to most events, and if we were ever in a bind, we had a BART station right outside our hotel.

What events should we hit?

The simple answer, all of them. We had the privilege to be included in the Pantheon Partner dinner, which was amazing food and drinks, while connecting with friends. We knew we were going to hit the two main evening events listed on the site, which as always with a Drupal conference, was never disappointing. On the Friday night, we even found a few people who were wearing our t-shirts we gave away at DrupalCon in Austin, which really made our night.

Who do we want to meet?

This trip for me was not being Gene the owner, but about being Gene, one of the gang :) Before leaving the conference, I reached out to all the people I work with on a weekly basis, as a number of their companies sent people to BADCamp. I made sure to get cell numbers and arrange times to meet face to face. The highlight of my networking was finally getting to meet Drew Stephens after 4 years of talking on the phone, skype and a ton of emails.

What was most important?

For this trip what I found most important was to stay open to any and all opportunities to learn, which we most assuredly did. There wasn’t a single day where we didn’t walk away with more than one great gem to take back to our team, and for me, that is what made the cost and time for the conference worthwhile.

For my first BADCamp, it was an amazing experience, and I can’t wait to be back next year. It is my goal to work with my monkey troops, to come up with something awesome that we can share back with the Drupal community. If you haven’t attended a BADcamp yet, I highly recommend giving it a go, you won’t regret it. If you do decide to attend in 2015, look me up, as it would be great to meet more of our kind!

Dec 18 2014
Dec 18

[embedded content]

Traditional analytics primarily focus on traffic, page views, conversion and a few other high-level metrics. "These are all great indicators, until you try to determine what you should do to convert qualified leads." explains Kylon Gustin, Director of Marketing at LevelTen Interactive. That's where value-based content scoring provides deep insight.

Value-based content scoring reports not only show daily traffic to your website and additional page views, they also provides a more in-depth look into the actual value of your traffic, events and goals.

Open Enterprise IntelligenceTM, for example, focuses on value derived from a number of factors. How engaging is your content? Does your content produce valued results like leads, social shares and comments? Is your content attracting visitors, increasing brand awareness, conversions, and time on site?

When each of these is measured in individual silos, as with most analytics systems, you receive limited value.  However, seaming them together allows you to make educated decisions based on quantifiable data.

All web marketers agree that content is valuable, but not just each piece of content. Authors, type of content, subject matter and several other aspects play a huge role in how valuable a piece of content is to your overall marketing strategy.

For example, you can score traffic sources (organic search, direct, referral, social network) to determine which sources provide the most value to your organization. You can score website visitors to determine which visitors provide the most value through engagement, social shares and form submissions.

So how do you get your hands on this data? It requires a very deep integration between your CMS (we use Drupal), Google Analytics, Add This (social sharing tool), Twilio, MailChimp and other tools that provide crucial data to effectively measure value. Without combining all of your data together, you only get a small glimpse into your efforts. Combining ALL of your data is crucial.

If you are interested in gaining more value from your marketing efforts, we can help. Feel free to schedule a demo or ask questions within our comments below.

Dec 18 2014
Dec 18

As the Drupal market continues to rock and roll, more and more clients need "Drupal Developers". But what exactly is a Drupal Developer? A Drupal Developer is someone who knows Drupal right? Right?!

There always has been some confusion around job titles and skills in the Drupal world. This is especially true with some recruiters and even managers and clients that are hiring. In effect, there are three main areas of expertise in the Drupal world: site building, backend/module development and theming. The skills required for each are quite different.

Drupal Site Builder

A Drupal site builder is someone who builds Drupal sites with point and click in the admin UI without writing much or any custom code. I say much, because they might implement the odd hook here and there. But most of the functionality of the site/application comes from configuring Drupal core and contributed modules. Site Builders will have experience with a wide range of contributed modules and will understand how they work together to solve a particular problem. They will understand the limitations of modules and should be able to provide a concise argument of the pros and cons of various solutions. Site Builders will build the content types, taxonomy, navigation, image presets, rules etc. One of the magnificent things about Drupal is that it does not exclude non-developers. The Drupal community and the platform provides a very powerful tool set for people to build innovative and complex sites without the requirement to be a programmer. And mastering this is a very valuable skill in itself.

Drupal Themer / Frontend developer

A Drupal Themer is the specialist front end developer. They are experts in HTML, CSS and Javascript. They are also experts in the Drupal theme layer. They should be able to take a design and turn it into the working theme. Ideally they will be well versed in implementing responsive design.

Drupal Module Developer / Backend developer

A Drupal developer is someone who writes a lot of PHP and other server side languages. They write custom modules, automated tests, consume web services, automate deployment etc. They may also be know as “backend Drupal developers”. They may also get involved in some of the more advanced side of the theme layer as well. Often they will set up automated deployment.

A note on contributing and collaboration

Drupal is inherently a collaborative project. Site Builders, Module Developers and Themers will often contribute their work back to the community and collaborate with others. It is common for module developers to share and collaborate on contributed modules, themers on contributed themes and site builders on site building recipes and other forms of documentation.

The Three Disciplines

What is a drupal developer?

Drupal Generalist /Jack of All trades

It is very common to do all three. You may be more advanced in one area or another, but still act in a general capacity.

In most of the projects I have worked on, there has not been a dedicated site builder. Both backend developers and fronted developers will do elements of site building.

A Drupal developer who is a jack of all trades

How a business hire and use Drupal people varies. In one extreme, a business may hire specialists. To deliver a particular piece of functionality or feature, the work may have to go through each of the specialities before it is done. One of the other extremes, is a business may assume that a Drupal person should do all three specialities. In this case, it is common for the team to be a team of “Drupal Developers” and the role encompasses site building, backend development and theming. Both approaches have their pros and cons, but that is for another day!

Other roles

Just like any other web development setup, there is a range of other roles included in the process of building and support Drupal applications. This includes:

Sysadmin / Devops - run the live stack, will often deploy Drupal sites to the live environment, deal with performance issues, setup a CDN, Varnish, Memcache etc.

QA - test all changes to ensure quality and that they meet the requirements. Setup automated tests.

Project Manager / Scrum Master - run the scrum team, remove impediments to progress, ensure delivery of the project on time and budget.

Product owner - comes up with the requirements. Works closely with the project manager to prioritise the backlog. Normally has final sign off of all changes.

Design / UX - comes up with the design and user experience. They might build prototypes that can then be converted into a Drupal theme.

Who is not a Drupal developer

This advice should be given to any recruiter or hirer in the Drupal space. A PHP developer is not necessarily a Drupal developer. It does not matter how good the PHP developer is at PHP, unless they have decent Drupal experience and understand its API’s and, dare I say it, “the Drupal way”, they will make many mistakes. You will then need to hire an experienced Drupal developer to clean up the mess left behind. Of course, I am being a bit simplistic here. In current times where demand far out strips supply, it as not as simple as that. You might be forced to hire a PHP developer who doesn’t have much (or any) Drupal experience. That is fine, but the minimum requirement should be that the developer wants to learn the Drupal standards, understand the Drupal culture and try and do it the Drupal way. You don’t want someone who treats it as just another framework that can be bent and broken to the developer's way of thinking. That is a recipe for creating a maintenance nightmare that will cost the business in the long run.

Where do you go from here?

When I first launched the early edition of my book, Master Drupal Module Development, I asked people on my mailing list whether they were Site Builders, Backend Developers or Themers. The split was mostly between Site Builders and Backend Developers but most of the developers were people who developed in tech outside of Drupal and were looking to find the best way to learn Drupal development.

Developer from another technology

If you are a developer from another technology, there are a couple of routes available. One is to build a couple of sites using pure site building. And then, once you are happy with the basics of Drupal, you could dive into module development. Being an experienced developer will almost certainly give you a leg up, because you obviously already know how to do development. Now you need to learn the Drupal APIs and the Drupal way.

Site Builder

If you are a site builder, you might want to move into module/backend development. Because you already know your way around Drupal, you also have a leg up. However, you still need to learn the Drupal APIs and the Drupal way of developing. In addition, if you don't have any or much programming experience, you will need to learn some of that to. You don't need to be a programming genius to get started with Drupal development. You can get started with just the basics of PHP in addition to something like my book.

Themer

If you are a themer, you might not want to do anything else but get better at theming and frontend development. After all, there is a ton to master there, especially when you include CSS and Javascript. But you might want to learn some module development. It will certainly help you broaden your horizons and achieve more.

Module Developer

If you are a Module/Backend Developer, then where do you go? You can always learn more about theming. But might also consider learning more about being a solutions architect. If you are happy being a backend developer, then getting more experience in other PHP frameworks (such as Laravel or Symfony2) is very beneficial to your career prospects and capabilities as a developer.

Where do you fit in?

Do you consider yourself a Site Builder, Themer, Module Developer or something else? Are you looking to move into another area? If so, what are your main obstacles? I'd love to hear from you in the comments below.

Dec 18 2014
Dec 18

Got some Drupal 7 modules that use the Form API lying around? Want to learn how to port them to Drupal 8? The process could just be the crash course you've been looking for to learn Drupal 8 object-oriented module development and Drupal 8's Form API.

Back in the day, Lullabot trainers produced a module to demonstrate how to use Drupal's Form API. The module was called Form Fun and today, I'm going to tell you a little bit about the "fun" I had porting the Drupal 7 version of this module to Drupal 8.

In this blog post, you'll learn:

  • How to use Drupal Module Upgrader to upgrade a D7 module
  • How hook_menu was replaced with routes and controllers
  • How to find information about API changes in Drupal 8

To get a jumpstart on porting this Drupal 7 module to Drupal 8, I decided to give the Drupal Module Upgrader module a try. I saw a demonstration of it by Angie Byron at the Pacific Northwest Drupal Summit in October and I have been determined to try it out ever since.

Getting Ready to Port

To start, I created a Drupal 8 site on my local machine. At the time, this was Drupal 8, Beta 3. For information about how to install Drupal 8, read this Installation Guide.

I also have Drush 7 installed. You will need this, too, if you want to use the Drupal Module Upgrader. In Terminal, or your command-line interface of choice, type drush --version to see which version of Drush you have installed. If it returns 7.0-dev, you can move on. (Likely any 7.x version will work.) But if you find you need to upgrade Drush, check out my blog post on Upgrading Drush to Work with Drupal 8 for some tips.

Both Drush 7 and Drupal Module Upgrader require Composer. If you are brand new to Composer and would like to learn about what the heck it is, check out this free video on Drupalize.Me from our partners at KnpUniversity: The Wonderful World of Composer. If you don't remember if you've installed Composer already, if you're on a Mac, fire up Terminal and type which composer. If a path is returned, then you're all set. If you need to get Composer, see this doc page.

Drupal Module Upgrader

I recommend installing the latest dev version of Drupal Module Upgrader (DMU). I ran into some problems just installing the stable version which were fixed in the latest dev. So, save yourself some troubleshooting and go ahead and install the latest dev using drush by running this command in your command-line interface (CLI): drush dl drupalmoduleupgrader --select and select [1]. For this tutorial, I downloaded the 8.x-1.x-dev | 2014-Nov-27 | Dev version.)

Follow the instructions in Drupal Module Upgrader's README.txt file. If you run into errors with any of the dependencies that Composer is updating, like Pharborist, try running composer update in the /modules/drupalmoduleupgrader directory. For other troubleshooting help, search the Drupal Module Upgrader Issue Queue.

Now we're almost ready to port this thing, but first we need to copy the D7 module into the modules/ directory.

Back in your CLI, with the DMU module installed, we now have some new Drush commands. Run drush help --filter=drupalmoduleupgrader to see the shiny new commands provided by DMU module.

Analyzing the API Changes

Now run drush dmu-analyze. This command creates an HTML file in your module's directory with a breakdown of every API change that affects your module with links to the change records. (Note: I discovered that this page renders much better in Chrome than in Firefox, on a Mac anyway, so take that for what it's worth.) Right away, I can see that form_set_error() is now a method of FormStateInterface. but there are many more changes listed, with links to the change records containing more information about the API change.

form_set_error() is now a method of FormStateInterface.

Running the Upgrade

After perusing the changes that will need to be made, we're about ready to run the upgrade process. But first, make sure you've got a backup of your module before proceeding.

My module's machine name is form_fun. To have DMU attempt to upgrade it to D7, I run drush dmu-upgrade form_fun (replace "form_fun" with the machine name of your module, if you're playing along).

In the case of my module, it was a bit anti-climatic. But, navigating to modules/form_fun, I can see a bunch of new files! I'm excited! (Or maybe I should be afraid!?)

More Than Just Form API Changes

Even though my module was all about demonstrating Drupal 7's Form API, it used other Drupal 7 APIs and function calls to create menu links, URLs, and page content. This means that in this process of porting this D7 module to D8 using Drupal Module Upgrader, I'm also learning about how Drupal 8 replaced hook_menu and other functions. I'm also getting a crash course on object-oriented PHP and using controllers, classes, and methods instead of as a bunch of procedural functions inside .inc files.

Hook_Menu's New Split Personality

hook_menu has been removed from Drupal 8

hook_menu has been removed from Drupal and in its place, routes and controllers. A route defines what happens at a certain URL and a controller determines what content or functionality should be found at a certain URL.

So, for purposes of comparison, here's a snippet of the D7 version of Form Fun's hook_menu implementation that defines pages, their paths, access, files, functions or "page callbacks", related pages, and in what order those sub-pages should be listed in a menu:

D7 example usage of hook_menu

/**
 * A super-simple menu hook that tells Drupal about our Fun Module's page.
 */
function form_fun_menu() {

  $items['form_fun'] = array(
    'title' => 'Fun with FormAPI',
    'page callback' => 'form_fun_page',
    'access arguments' => array('access content'),
  );

  $items['form_fun/cake'] = array(
    'title' => 'Death, or cake?',
    'page callback' => 'form_fun_cake_page',
    'access arguments' => array('access content'),
    'file' => 'form_fun.cake.inc',
    'weight' => 1,
  );

  $items['form_fun/existential'] = array(
    'title' => 'Existential questions',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('form_fun_existential'),
    'access arguments' => array('access content'),
    'file' => 'form_fun.existential.inc',
    'weight' => 2,
  );

...

  /**
   * These menu callbacks should be ignored! They're secret. Suuuuuuper secret.
   */

  $items['form_fun/death_image'] = array(
    'page callback' => 'form_fun_death_image',
    'access callback' => TRUE,
    'file' => 'form_fun.cake.inc',
    'type' => MENU_CALLBACK,
  );

...

  return $items;
}

In the Drupal 8 version of Form Fun, created by DMU, the functionality in the D7 Form Fun hook_menu has now been placed in the following three files:

  • modules/form_fun/form_fun.routing.yml
  • modules/form_fun/form_fun.links.menu.yml
  • modules/form_fun/src/Controller/DefaultController.php

So now if you wanted to tell Drupal to do something at a certain URL, like build a page, display a form, or create some menu links programmatically, you will need a YAML file (perhaps more than one) and potentially a Controller php file. In the case of form_fun, DMU created src/DefaultController.php to output content for one of the pages in the module, created form_fun.routing.yml to tell Drupal about the names of the "routes" declared in this module, and form_fun.links.menu.yml to tell Drupal about how a menu of links should be built for this module.

Defining Routes with YAML

The form_fun.routing.yml file is a YAML file that describes route names, like form_fun.page. It describes any necessary related information like the path, title, what type of page it is, and where to find the method that builds whatever it is. That could be a controller definining page content, or a class handing a form. Think of the structure of a YAML file as an array, but with colons instead of commas and meaningful indentations.

Here's a snippet of the form_fun.routing.yml file created by DMU in the upgrade process:

form_fun.routing.yml (snippet)

form_fun.page:
  path: /form_fun
  defaults:
    _title: 'Fun with FormAPI'
    _content: '\Drupal\form_fun\Controller\DefaultController::form_fun_page'
  requirements:
    _permission: 'access content'
form_fun.cake_page:
  path: /form_fun/cake
  defaults:
    _title: 'Death, or cake?'
    _content: '\Drupal\form_fun\Controller\DefaultController::form_fun_cake_page'
  requirements:
    _permission: 'access content'
form_fun.existential:
  path: /form_fun/existential
  defaults:
    _title: 'Existential questions'
    _form: \Drupal\form_fun\Form\FormFunExistential
  requirements:
    _permission: 'access content'
 

Note that in Beta 4 of Drupal, you won't have to specify that a route uses a _content controller. You will just need to specify _controller. (See this change record: Routes use _controller instead of _content.)

As you can see, if a route is a form, you specify a _form key with the value being the name of the class that defines your form and its workflow.

Defining Menu Links for the Module

There's now a separate place for defining menu links in your modue. In my Form Fun module, these are contained in the new form_fun.links.menu.yml file created by DMU. Notice the parent and weight keys that create a hierarchy and order menu links.

form_fun.links.menu.yml (snippet)

form_fun.page:
  route_name: form_fun.page
  title: 'Fun with FormAPI'
form_fun.cake_page:
  route_name: form_fun.cake_page
  title: 'Death, or cake?'
  weight: 1
  parent: form_fun.page
form_fun.existential:
  route_name: form_fun.existential
  title: 'Existential questions'
  weight: 2
  parent: form_fun.page

Controllers

Finally, the Controller. A Controller is the place to put methods that output some content to the page. It replaces the page callback procedural function. In the case of the Form Fun module, it's the page that defines a method that returns a list of links to the other forms. It's also the home of several methods that output some images to certain pages. These pages will serve as redirect locations in one of Form Fun's forms. We'll even output a form to a page in a Controller, replacing Drupal 7's drupal_get_form procedural function. I found this handbook page a helpful resource in deciphering the changes that DMU made in replacing hook_menu: An introductory example to Drupal 8 routes and controllers.

src/Controller/DefaultController.php (snippet)


/**
 * @file
 * Contains \Drupal\form_fun\Controller\DefaultController.
 */

namespace Drupal\form_fun\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Url;

/**
 * Default controller for the form_fun module.
 */
class DefaultController extends ControllerBase {


  public function form_fun_page() {
  /* Returns a render array that produces an HTML list of links. */

}

  public function form_fun_cake_page() {
    $form = \Drupal::formBuilder()->getForm('Drupal\form_fun\Form\FormFunCake');
    return $form;
  }
...

So, wow! The changes to hook_menu are really significant. I found it really helpful to learn about those changes in a super-practical way but going through this process of having Drupal Module Upgrader port my D7 module to D8.

@FIXME: Where DMU Only Gets You So Far

Now, DMU did a pretty good job of creating these files and refactoring functions into classes and such, but where it failed, it added comments with @FIXME. For example, I had several @FIXMEs related to building a $links array and displaying those links as a list using a theme function. Here's the comment left by DMU:


// @FIXME
// l() expects a Url object, created from a route name or external URI.
// $links[] = l(t('Death, or cake? (The basics)'), 'form_fun/cake');

Ok. So what to do? What I found the most helpful in this case was to head over to the change records on Drupal.org. There were some direct links to change records provided by the upgrade-info.html file generated by drush dmu-analyze. But where I didn't find a reference there, I simply searched for the function name in question.

So, for this @FIXME, on the change records page I filtered by keywords l() and found this change record: l() and url() are removed in favor of a routing based URL generation API. Usefully, on this change record, there was an example for how to create a Url object. So...

$links[] = l(t('Death, or cake? (The basics)'), 'form_fun/cake');

...is refactored to...


  // Death or Cake? (The basics)
  $url = Url::fromRoute('form_fun.cake_page');
  $text = 'Death, or cake? (The basics)';
  $links[] = \Drupal::l(t($text), $url);

The other thing that was refactored by DMU was the theme function that produced an HTML list of links contained in the $links array, but I found this caused many errors and obviously needed to be changed. I finally found an example of an item_list theme function and refactored DMU's output: return _theme('item_list', array('items' => $links)); to this:


  // Preparing a render array of a HTML item list of the $links array.
  // @FIXME
  // #title value outputs twice on page, as H1 and H3. Fix in twig file.

  $item_list = array(
    '#theme' => 'item_list',
    '#items' => $links,
    '#title' => t('Fun with FormAPI!'),
  );

  // Returning the render array that produces an HTML list of links.
  return $item_list;

You'll notice that I left a @FIXME for myself to fix the duplicated title output, but the takeaway is that Controllers expect render arrays, response objects, or html fragments—not strings. At least that's what the error messages in the "Recent log messages" insisted upon. Also, I discovered that _theme used to be theme() and shouldn't be called directly, so as to encourage the consistent building of renderable arrays. As this is a custom module, I thought I had better refactor. See theme() renamed to _theme() and should not be called directly.

Lessons Learned and What's Next

When I started this process of porting the D7 Form Fun module to D8, I naïvely thought that I would primarily be learning about changes to Drupal's Form API. But what I discovered was equally valuable: lessons on object-oriented PHP, how a major function like hook_menu was replaced with YAML files and Controller php files, new types of files and structure in modules, an invaluable resource in change records, and a great helper in Drupal Module Upgrader.

In my next post on upgrading the Form Fun module to Drupal 8, we'll explore interfaces, a bit more with a Controller, and we'll define a class that defines, builds, validates, and submits a form. Throughout this series on the Drupal 8 Form API, we'll dive into various types of form handling including multi-step and AJAX forms. Stay tuned!

Resources

Dec 18 2014
Dec 18

The Drupal Rules Filter Module is a simple module that makes it easy to sort through a long list of Drupal Rules. This is a module that is especially useful on those larger scale Drupal websites that rely heavily on the rules module and have many contributed Drupal modules installed.

It categorizes and adds a search box to the Rules UI page that makes instant search possible. It's very similar to the Module Filter module. The Module Filter module makes searching Drupal modules easy, the Rules Filter module makes searching Drupal rules easy.

There is not much configuration needed for the Drupal 7 Rules Filter module. Just make sure you download the List.js plugin to your sites/all/libraries folder (placing the list.min.js file in a listjs folder).

What do you think of the Drupal 7 Rules Filter module? Do you think it's a module you would use when building out a bigger Drupal 7 website?

Dec 18 2014
Dec 18

Kate Marshalkina, Drupal ExpertThis post is part of an ongoing series detailing the new personas that have been drawn up as part of our Drupal.org user research.

Kate Marshalkina has been using Drupal for three and a half years. A web developer by trade, Kate was approached by a friend who wanted her to do Drupal work with him. After doing some research on the system, Kate agreed.

“It’s quite difficult to learn Drupal without paid work because it requires a lot of time and experience to learn the Drupal way of doing things,” Kate said. “I had joined a security startup, and a security company obviously cares about security on the web. So we decided to use Drupal because it’s a safe, well known open source system. I learned a lot while I was working on my tasks, but I spent a lot of my free time to learn Drupal. Once I started learning, I couldn’t stop— I’d previously worked with other content management with less documentation and information and then I started learning Drupal and... because of the community, and all of the learning resources and videos that are available, I was hooked."

“After working with Drupal for three months, I started my blog and not long after that I presented a session at DrupalCamp Moscow. Now, I’m a Drupal lover after three and a half years working with the platform."

Drupal.org: A Valuable Resource

Every day, Kate checks in to Drupal.org: she says she visits the site to find new modules, check the issue queues, and check API documentation. “I’m very comfortable with Drupal.org, but it was hard getting used to it when I started. Initially, it was a question for me why I should even use Drupal.org, and I didn’t know what the benefits are.

"I really like my dashboard on Drupal.org,” said Kate. “It’s a great page where I can see daily updates on my issues — and of course I follow a lot. It’s nice that I can also easily view updates on issues in critical bugs in core and so on, see crucial updates, core releases, and of course I also follow the Drupal Planet RSS feed."

Drupal Planet is one of the most helpful tools for Kate when it comes to getting new Drupal knowledge, and she often encourages her colleagues to follow it. "I think Drupal Planet is an exciting part of Drupal.org. It’s a great resource for Drupal related articles for everyone; beginner to expert, frontend to backend to sysadmin, the information for all these people is usually very high quality on Drupal Planet. When I’m working with fellow developers who have questions, I always ask them to look on Drupal Planet because I know that the information there is of a high quality, and that anyone can find the knowledge they need in there."

It's About the People

Some of the recent changes made on Drupal.org, including the addition of user pictures to the issue queue, have made Kate’s Drupal experience vastly better.

“[The pictures] are great because it makes Drupal.org more personalized, and you can more easily remember the people you talked to because of their photos. And, it reminds people that Drupal isn’t just a CMS, it’s a community, and the people are important.”

“It’s a big question for me how to enroll younger developers,” said Kate. “Looking at the contribution opportunities, [new people] may feel like they can’t be a contributor. So sometimes, they may encounter a bug they don’t know how to fix and think, “oh no, a bug!” instead of recognizing it as an opportunity to learn and grow. If we can encourage more people to become contributors, they will benefit from it and Drupal will benefit from them."

Kate’s advice for new Drupalers is to “start right out and register on Drupal.org. Share modules, create patches, learn how to use git and so on… it’s not easy, but it’s worth it."

Growing With the Project

As for herself, Kate hopes to increase her skill level by contributing to Drupal 8 core.

"I participated in DrupalCon Amsterdam, and really liked what Dries said about getting more benefits to small companies who contribute so that it will be easier for employers to understand why they spent their time and pay for developers on core. I would be much more experienced if I could participate in Drupal core development."

"I also want to someday give a session at DrupalCon,” Kate added. "I give a lot of sessions in my local community, camps and so on. I’ll be speaking at Moscow Drupal Camp in November, but hope to speak at a DrupalCon soon."

We all wish you the best of luck, Kate, and hope to see you on a stage at DrupalCon soon!

Dec 18 2014
Dec 18

Intro

Solr is an open source search engine with many powerful features.

I encounter a lot of experienced developers that either don’t know how to use it or avoid it as it’s in the to hard/scary basket. In this introductory article we’ll talk briefly about how to install Solr in order to use it for development.

There are many ways to install and configure Solr but in this article I’ll show you how to set it up quickly so you can get started developing with it. While the installation and setup will be generic to any framework you want to develop with, I’ll also, show you a couple of extra steps if you’re using Drupal.

Requirements

The only real hard requirement/prerequisite for running Solr is Java. Version 1.6 is recommended for Solr version 4 and upward. Ubuntu and Mac should come with Java pre-installed.

I’m not a windows guy so sorry you guys are on your own There’s pleant of resources out there.

You can find out the version of Java you are running with the following command.

$ java -version

java version "1.7.0_72"
Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.72-b04, mixed mode)

I am using Ubuntu 14.04 but the instructions in this article should work if you’re on a Mac or another variant of *nix

Download

Open a terminal and make a folder we can use for working in, and change to that directory:

$ mkdir solr
$ cd solr

Navigate to the Solr download page and find the closest mirror for you. At the time of this article the latest version of Solr is 4.10.2.

Copy the download link for either the solr-VERSION.tar.gz or the solr-VERSION.zip. You don’t want the solr-VERSION-src.tgz (this is the source code and will need to be compiled) and download it with wget.

$ wget -c http://mirrors.sonic.net/apache/lucene/solr/4.10.2/solr-4.10.2.tgz

Unpack

Once downloaded (it’ll be about 150M) we can un-compress it and change into the directory.

$ tar -zxvf solr-4.10.2.tgz
$ cd solr-4.10.2/

Make a working copy

In the current directory there is a folder called example we want to make a copy of this folder.

We could just use the example folder but it’s nice to leave that clean on case you want to use this copy of Solr for other sites as well. So we’ll make a copy and then change directory into the newly created copy.

$ cp -prv example my_solr
$ cd my_solr

Make it work

Now we’re ready to run it for the first time. To run Solr it’s really simple. Simply run:

$ java -jar start.jar

You should see a whole bunch of output (to stop solr press CTRL^C). After a few seconds if you open your browser and navigate to http://0.0.0.0:8983/solr/ you should see something similar to the following (the actual screen may differ depending on your version)

Solr dashboard

That’s it. Solr is now set up and ready to use. Depending on your client frame work you may need to makes some config changes to Solr itself. Consult the installation instructions of your chosen framework. If you’re using Drupal keep reading and I’ll show you the steps required to make Solr ready for Drupal integration. First lets stop SOlr from running by hitting CTRL^C in your terminal.

Modules

There are a couple of modules you can use for Drupal integration with Solr. I wont go into the Drupal configuration side of things (I’ll leave that for another day) but will talk about the steps required to get the Solr server we’ve set up ready for Drupal usage depending on the Solr module you’ve chosen.

Search API and ApacheSolr

If you’re using the search_api you will need to ensure you have the search_api_solr module installed. Otherwise the [apachesolr] module is the way to go.

In both the search_api_solr and [apachesolr] modules, you’ll find a folder called solr-conf in this folder there will be version folders 4.x, 3.x etc. Choose the version of Solr you downloaded. This folder contains all the config files you need to install in your Solr install. I could probably write a whole bunch of articles about the contents of these files but since this is a beginner tutorial we’ll just take the easiest route.

You want to copy the contents of the solr-conf/4.x/ folder into your solder core. We can do this with the following, go back to your terminal, and run (change the path to your Drupal module):

$ cp -v **/path/to/apachesolr/or/search_api_solr/**solr-conf/4.x/* solr/collection1/conf/

That will copy the config for your Drupal site into the my_solr/solr/collection1/conf/ directory.

Conclusion

Solr is now ready for use by your Drupal install. You can run it whenever you like by changing into the my_solr directory and starting it.

$ java -jar start.jar

I wouldn’t recommend using this setup in production. However, for developing on your local machine, it’s perfectly fine.

In the next article, I’ll talk about how to configure the search_api and search_api_solr to use Solr as a search engine for your Drupal site.

Please enable JavaScript to view the comments powered by Disqus.

Dec 17 2014
Dec 17

Nathaniel Catchpole , the Drupal 8 release maintainer and Tag1 Senior Performance Engineer, suggested that Drupal shops everywhere could support the release of Drupal 8 by upgrading their own sites and addressing the issues they find along the way. This series chronicles the journey from Drupal 6 to Drupal 8.

Part 1: Readiness Assessment

Before performing a major version upgrade, I usually go through a series of steps that help me determine:

  1. What compelling business needs or new functionality are prompting the move? In this case, the site builder view on the status of D8 will help us identify and hopefully address real barriers to adoption, as well as to prepare materials that help document the journey.
  2. What does the site do? If there are functional tests or test plans, I review those. Then, I manually review the site, paying attention to functionality for particular roles. I also check with at least one or two of the stakeholders with each role to learn what features they regularly use, what improvements would better support them, and what they’d really like to see. I don’t normally act on that wish list answer as part of the upgrade proper, but knowing what new functionality they desire can help make decisions about the new modules to use.
  3. Are there features that are no longer in use? I’m always surprised, though by now I really shouldn’t be, by the number of things that seemed like a good idea at the time to someone which were never used at all or which are no longer in use.
  4. Is now the right time? Are the contributed modules on which the site depends ready or is there a new way to achieve the required functionality.

1- Compelling Functionality

As noted above, this particular journey is compelled by the desire to identify and fix bugs during the Beta period of Drupal 8. That doesn’t mean we’re not excited by:

  • WYSIWYG in Core- I am ecstatic at the prospect of NOT having to choose and configure basic WYSIWYG functionality.
  • Views in Core - I pay a lot of attention to the experience of content contributors. They’re the everyday users that Dries talked about back at DrupalCon San Francisco, people who use the interface of Drupal as their day job. What a site builder does for them (or fails to do) can make or break the success of the site as well as cement the organizational satisfaction with Drupal itself.

I want Tag1’s busy staff to find it a pleasure to keep their blogs, community contributions, and case studies up-to-date.

2 - Current Functionality

Our speciality is performance and scalability for complex websites, which never necessitated building a complex external site for ourselves. We have internal sites that put Drupal 6 though its paces, but the main Tag1 site is a combination of blogs and brochure:

  • Review what the current site does
    I start any readiness evaluation looking at the site from the user perspective, clicking around, then reviewing any documentation. The site revealed no surprises. I jotted notes about those user-facing features, mapped to Drupal functionality, and stored them as a sheet in the Readiness spreadsheet. For a basic site, the notes aren’t too impressive, but the process was a valuable refresher on what the site does.
  • Inventory the enabled modules
    After looking at the site from the user interface, I make an inventory of enabled modules. The following Drush commands make nice spreadsheets:
    drush pm-list --no-core
    drush pm-list --core
    

    You can take a look on Sheets 2 and 3 of the Readiness spreadsheet to see the entirety of what was and and wasn’t available.

    In our case there are just two areas of concern:

    Blogs have been removed from core, but with views moved in, this won’t be daunting to rebuild. They may work a little differently, but odds are that will be for the better!

    The only missing module that had no alternative and looked like it might hurt was Pathauto. It’s nice to keep URLs tidy and hard to remember to set them, but wouldn’t be strictly necessary for our purposes and there were were no other glaring show stoppers.

    Note: It looks like upgrade work is happening on Github so I updated the spreadsheet to make note and will evaluate the status as part of the process.

  • Look for customizations
    In addition to custom and contributed modules, it’s good to check for inappropriate customizations done directly to core or contrib. Whatever reason they had for being done back then may need to be accounted for, hopefully in a best-practices way, on the new site.

    Although it seemed unlikely that any relevant changes had been done, for good measure, I always run Hacked. It’ll let you know about files that have been changed from the source.

    There were some theme customizations and a .gitignore file was missing, so as suspected, nothing to worry about.

3 - Features no longer in use

I’ve learned over the years that not every module that is enabled is in use! I try to find a link that illustrates somewhere on the site that the module is visibly in play. Even when there is a place in production where the module is used, it’s entirely possible that the production feature itself doesn’t make sense to upgrade. A serious investigation of analytics and logs can be insightful. Data can guide conversations with product owners about what’s still valuable and support decision-making.

On our straightforward site, there’s not much to not use. As I learned running the first migration, though, even features that were briefly explored but never used can come into play. More on this later.

4 - The right time

Once you’ve completed your archaeology, you’ll need to find the right time for your organization. Talk with stakeholders about the change and be on the lookout for in-process or upcoming feature requests that you might not be prepared to accommodate.

In our case, because the motivation for this upgrade is process, not product, we’ll proceed and go as far as we reasonably can with the upgrade. At the time of this writing, I’ve done a D8 install and begun running a migration. (That’s how I know to be on the lookout for certain disabled modules!) I’m feeling confident that we can get a long way.

Unless the migration process is flawless and the Drupal 8 to Drupal 8 update path is in place I'd be unlikely to recommend deployment of the work, especially with an impending re-design. While re-entering some data manually has always been a part of previous major version upgrades, I’d be loathe to commit to beta adoption if I thought we’d find ourselves stranded in the latest version. Fortunately, all the preparatory work can be done without the upgrade path in place!

Coming next in this blog series, Part 2: Preparing to Migrate.

What modules and processes do you use to prepare for a major version upgrade?

jam
Dec 17 2014
Dec 17

Part 1 – Larry Garfield and I had a long chat in front of my camera at DrupalCon Amsterdam. Part of the idea was to help Larry prepare his thoughts for writing the blog post that has turned into "Building Bridges: Linking Islands" in the Future of PHP guest blog series on Acquia.com. In this part we cover Larry's start in Drupal, some project history, what Drupal can teach (and needs to learn) about contribution and community ("celebrating the newbie" and the power of "thank you"), The New PHP, fuzzy project boundaries and inter-project collaboration.

Building Bridges

Larry explains, "The PHP ecosystem is coming together. The web ecosystem is coming together. It's a lot more integrated. It's a lot more collaborative. So projects that are collaborating need to ask themselves 'What is our value-add?'. Drupal's value-add over the PHP baseline is not that it does dependency-injection. It's not that it can serve HTML. It's not that it has forms. It's value-add is entities, views, and the community. We are a content management system and a very good one. By that I mean a structured system to manage content, not a tool for building pages. And we have a community behind it that has your back, that you can rely on, that is not going away any time soon. That's Drupal's value-add. So put our emphasis and effort there; on building a really solid, flexible CMS platform with a community that can support it."

"Those other things that get us there? That's not our value-add. People don't use Drupal for hooks. They use Drupal for nodes. They use Drupal for Views. The more we can outsource our irrelevancies and focus on core competencies, the more we can say, 'The important things that make Drupal worth using, let's focus on those.' And the things that are not the reason people come to Drupal, we can save time by outsourcing that. It may not be perfect ... Could we write something better [than the Symfony routing component] ourselves? Probably. Would it be done right now? Not even close. But we brought in all this code and got 3/4 of the way we wanted to be by adding one, single library."

I proposed one more aspect to Drupal's value-add, "Drupal is architected in a way that is extensible and flexible. You get some more baggage, but its advantage over a specialized system is when your next requirement comes in, we're ready to incorporate it or communicate with it." Larry adds, "That goes to the whole framework versus application debate we've been having since there's been a Drupal. In Drupal 8, in some ways, we became more of a framework, in other ways, more of an application." Pointing to himself, "As one of the framework people for a long time, I think the [framework side] actually lost that battle and we lost it to modern PHP."

"Meanwhile, the application has evolved to being a platform and we should focus on thinking of Drupal as a PHP-powered content management platform. And think of it not in terms of, 'What is the canned user experience we can offer?' But [rather] how can we make a toolchain that let's you build a great user experience. How can we build a toolchain that let's you do all the content modeling shenanigans for whatever site or task you're doing and have reasonable defaults. Look at it as not an application, but as the core of a platform ecosystem. That means designing things and planning things in different ways than you would a pure application. You need to think about extensibility in a a different way between a framework and an application and a platform. I think at this point platform is the right way to think at the high level ... with some framework stuff alongside it."

Links/References

Interview video

[embedded content]

Image credit

linking_islands_1.jpg - Image by Jay-P - https://www.flickr.com/photos/esqenzo/248879957/ License https://creativecommons.org/licenses/by-nd/2.0/

Dec 17 2014
Dec 17

How do you insert a text field into a rendered entity, all within a field collection? This question came to mind on a recent Drupal 7 build. What at first sounded complicated turned into a concise and elegant solution.

The basis of the requirement broke down into the need for events to list those participating in the event. The build already had existing Event and Profile content types, so the new functionality would only require implementing the list of Profiles participating in an event. Each participant would include their role at the event, along with links to contact them.

blog

To implement this, an Event Participant field collection was added as a field to the Event content type. Each instance of the field collection included a single Profile content type and a single text field for their role at the Event. The Profile would then be displayed as a rendered entity within the field collection so that the Profile’s image and contact links could be displayed. The point at issue then arose. How would the Participant’s role at the event be placed within the rendered Profile teaser, along with the other Profile fields? To the user it needed to look like a single unified entity, with the Profile’s image, role at the Event, Profile name, and contact links all included.

Screen Shot 2014-12-11 at 4.27.43 PM.png

After some initial brainstorming a handful of different approaches came to mind. The initial impression was to use template_preprocess_field() since it allows the alteration of values in the theme layer. The participant role field would be removed from it’s initial location and inserted into the participant profile object. This did not work though. Despite the repositioning of elements within the render array, the changes occur too late in the rendering execution. The render array had already been rendered and thus the display remained the same.

After quickly realizing a theme function wasn’t the answer, hook_node_view() came to mind. The hook allows for the alteration of a node before it is rendered and so all that would be needed would be to shift the location of the Participant Role field within the $node array. The issue with this implementation and the reason it wasn’t chosen, is that it would require reaching out to the global state to determine what changes are needed. In other words hook_node_view() doesn’t realize what context it is called under and would thus require a hack of sorts to determine when it was being called under an Event node. This could be worked around by checking the URL path, but this is not best practice as it is brittle and prone to breaking with future site updates.

As they say the third time’s the charm. The final solution was to use hook_field_collection_item_view(). This hook allows for the alteration of a field collection item before rendering. Unlike many of the other options, this hook is called for each field collection item, allowing one to both check the field collection name and adjust it’s internal field ordering, before any rendering occurs. Using this hook, each Event Participant field collection item is altered, removing the Role field and inserting it into the Profile rendered entity. Simple as that. Now each Event Participant is correctly displayed as a single unified entity, with an image, name, and a set of contact links.

function hook_event_field_collection_item_view($field_collection_item, $view_mode, $langcode) { if ($field_collection_item->field_name == "field_event_participants") { $role = $field_collection_item->content['field_event_participants_role']; $profile_id = $field_collection_item->field_event_participants_profile[LANGUAGE_NONE][0]['target_id']; // Remove Participant Role from previous location in field collection output unset($field_collection_item->content['field_event_participants_role']); // Insert Participant Role into the Participant Profile output $field_collection_item->content['field_event_participants_profile'][0]['node'][$profile_id]['field_event_participants_role'] = $role; } } 1 2 3 4 5 6 7 8 9 10 11 12 functionhook_event_field_collection_item_view($field_collection_item,$view_mode,$langcode){  if($field_collection_item->field_name=="field_event_participants"){    $role=$field_collection_item->content['field_event_participants_role'];    $profile_id=$field_collection_item->field_event_participants_profile[LANGUAGE_NONE][0]['target_id'];       // Remove Participant Role from previous location in field collection output    unset($field_collection_item->content['field_event_participants_role']);       // Insert Participant Role into the Participant Profile output    $field_collection_item->content['field_event_participants_profile'][0]['node'][$profile_id]['field_event_participants_role']=$role;  }}

Through several quick, small, iterations an elegant, straight-forward solution was found to what at first sounded like a complicated feature request. Now users viewing an Event can see a list of Participants, with each Participant displayed as a single item. Check out more on field collections on the Phase2 blog!

Dec 17 2014
Dec 17

Chris Ohmstede, Skilled Drupal UserThis post is part of an ongoing series detailing the new personas that have been drawn up as part of our Drupal.org user research.

Chris Ohmstede is based out of Los Angeles, California. An experienced programmer, Chris is new to Drupal but already identifies as a skilled persona. Several months ago, Chris discovered Drupal as he was looking for solutions to build a website for hosting a program he wrote.

"I spent a number of years in the banking industry, and in that industry banks are constantly making connections to everything. I was always running in to problems when things couldn’t connect— it was always an issue trying to figure out what was actually going on. Over the years, I wrote a bunch of applets here and there to figure out what the problems were, and my program whycanticonnect is a conglomeration of those applets that work across operating systems, mobile— I’ve got cloud services approaching me about it, too.

Wanted: Custom Functionality

“Originally, I was hosting my project for download using a different CMS option, but things weren't working properly. Finally, I hit a point where I said “I’ve got to make a change.” I initially went to Drupal because I use Linux as my OS, and Drupal is one of the only CMSs available out of the repositories. I saw that, went and did some research, and Drupal looked big and well organized. One of the cool things that caught my attention is that I could Google around and see that everything I needed was already built. I never had to ask for any help — I was able to roll on through and put my site together easily."

“Also, one of the reasons why I selected Drupal was that I've released my product in 12 different languages, and Drupal looks like it has some decent translation services coming in. I want my site to be usable in all 12 languages I support."

After downloading Drupal, Chris relied on his technical knowledge to carry him through. Though he initially encountered some difficulty getting the modules to do what he wanted, he found after some searching that deriving his theme would fix his problems.

"Once I derived the theme, everything got easier— the way drupal derives themes is perfect. It’s very object oriented, which is fantastic. The nice thing about Drupal was that I could figure out what I wanted to mess with, and I could build variables on the local scope and carry them through the whole page and process, which is surprisingly difficult to do with other systems."

"It gives me everything I need"

“The great thing about Drupal is that you're not limited in how to inject code,” said Chris. "I like my download module because it gives me everything I need. It figures out intelligently what’s the best download to go with, it builds a link and launches the javalaunch, so it’ll work whether java is enabled or not— which was a problem I’d had before. I’m very happy with it, and very happy with Drupal."

For the time being, Chris doesn’t plan to put together more Drupal sites — rather, he’s going to focus on maintaining the one he has.

"I have no desire to become a web designer,” Chris said. “I built my site because I know I'll need to change it often, and with Drupal it doesn’t cost me anything. As far as giving back to the community, I’m mostly focused on working with my product. I need to write an Android, Mac, and iOS version. I’m planning on submitting some of my modules to Drupal.org once I’ve got them in shape, and I’ve made posts for people asking the same questions and encountering the same problem as I have. Maybe someday down the road I’ll have time to do more, though I certainly wouldn’t make any promises about it."

Dec 17 2014
Dec 17

Global #SprintWeekend will be 17-18 January 2015.

Please encourage contributors you know to host a small local sprint near them.

Post an announcement in your local meetup groups please; ask if anyone is interested in hosting a sprint and wants some support organizing it.

List sprints on the wiki: https://groups.drupal.org/node/447258
That wiki also has more information about organizing a sprint.

We will have a couple meetings to support organizers (doodle for organizer support meetings: http://doodle.com/uutcp2ge7gt3a8ed )
and also have mentors in irc over the sprint days (doodle for mentoring during the sprint: http://doodle.com/5vr54mpvxq4k7x29 ).

Dec 17 2014
Dec 17

Attention Michigan Drupalers! Mark your calendars for DrupalCamp Michigan, Saturday January 31 at Henry Ford College in Dearborn. For only $15, you get a full day of Drupal presentations, discussions and lunch!

Online registration/tickets will be available soon, and we’re currently accepting session proposals. If you’ve got an interesting presentation to share, please post it to the website here: http://2015camp.michigandrupal.com. Session selections will be made in early January.

Interested is sponsoring the camp and getting your name out to the local Drupal community? Sponsorship information is available here: http://2015camp.michigandrupal.com/sponsors.

Dec 17 2014
Dec 17

The Password Reset Landing Page or PRLP module is honestly one of the simplest modules you have come across. The sole purpose of the module is to provide the ability for users who request a new password to be able to reset their password on the password reset landing page instead of having to do so on the user edit page.

The main use case for this module is to limit users who request a new password and then once they click on the one time login they forget to set their password. If they forget to do this they would again need to request a new password.

Configuring the PRLP module is easy. With the configuration settings you can set if you want to require them to enter a password on the landing page, the page they will be redirected to after they login and also the fields that appear on the landing page. In this Daily Dose of Drupal I walk through these options and also explain how the process works with and without the module.

Every module has a place and this module definitely falls into the category of "nice to have", but not essential. Go ahead and try this out on your site and let me know what you think.

Ben
Dec 17 2014
Dec 17

It's the final week of work before Christmas and Code Drop have sponsored me to work on core for the whole week :). I've been working towards a successful end to end migration from Drupal 6 to Drupal 8 and after debugging 5 core bugs, I finally have a working solution. Checkout the video!

[embedded content]

The video shows an out the box Drupal 6 website with a bunch of fields, taxonomies and settings created. Most of the stuff comes across to Drupal 8 but there are still a few issues that need work.

Current Core Bugs

These are the core bugs that are required to get this demo working.

Dec 17 2014
Dec 17

Keiko Kanda, Drupal Learner This post is part of an ongoing series detailing the new personas that have been drawn up as part of our Drupal.org user research.

In April of 2014, the Japanese Drupal community gathered in Kyoto for their first ever DrupalCamp. Individuals came from other countries to attend the conference, and that was how Keiko Kanda was first introduced to the project.

“I think it might be a bit unusual to get involved the way I did,” Keiko said. “My cousin who lives in Sydney, Australia, married an Australian man. He came to Japan to attend the DrupalCamp in Kyoto and he asked me to accompany him… though some people were presenting in English, he was concerned that he might need a translator.”

“I knew almost nothing about Drupal, even though he had introduced me to what he was working on at that time. But I thought, I would be glad if I could help him out. So I went to the DrupalCamp in Kyoto and it turned out to be a very interesting experience for me.”

“To be perfectly honest with you, when I decided to tag along with my cousin’s husband, Colin Watson, I didn’t realize how fun it would be. I never thought my involvement would last this long,” Keiko said.

Serving an Immediate Need

At the camp, Keiko quickly found herself enlisted as a translator for some of the sessions, and was surprised by the number of foreign attendees at the conference.

“They were all very nice people, and there was much more international attendance than I expected. There were maybe fifteen or twenty international attendees there, and probably ten or fewer were giving presentations in English. Some were able to give parts of their Drupal explanations in Japanese, but they needed a translator to help introduce themselves. So when I arrived at the venue, the camp organizer asked me to translate the introductions from English to Japanese."

That was how Keiko met Chris Luckhardt, a Drupal Master that we will hear from later in the week.

"Chris was one of the speakers... though he had another translator to translate the technical parts of his presentation, when he spoke about himself and other innocent, casual stuff, he needed someone to translate. So that's how I got involved."

Stayed For the Community

"After the Drupal camp in Kyoto, the organizers — Satoshi Kino and Kyoto Ohtagaki — they asked me to do the translation stuff not only at DrupalCamp but at the meet-ups and meetings. According to them, many Japanese Drupal developers can understand when they read English, but when they have something to express it’s very hard to write or speak whole thing in English.

"Kino-san says it’s hard for Japanese developers to catch up with the latest information on Drupal.org,” Keiko continued, “So he and some other Japanese community members are trying to translate some of the useful English information into Japanese, though it takes time.

"I was — still am — studying to be a translator,” Keiko added, "and I thought it would be a good experience for me to help them. But many of Drupal technical terms... for me, they are gibberish. It’s not a language problem, it’s a problem with Drupal technical terms. So even though at DrupalCamp Kyoto they were talking in Japanese, I often couldn’t understand what they were talking about."

"I refer to Drupal.org occasionally when the community members talk about something very complicated— something about Drupal or what they were doing with Drupal… [translation is] hard for me but it’s fun, and in the process I can learn not only Drupal technical terms, but also what is going on in the Drupal world, learn about the problems the Drupal Japanese community has, and so on."

Ways of Mastering Drupal

When it comes to her current work with Drupal, Keiko is more focused on supporting the CMS than using it.

“When Kino-san organizes Drupal meetings, like monthly meetings, he will post the venue and time and date on Facebook in Japanese, and I will translate that into English and spread the word. When Kino-san or Kyoto-san works with Chris [or other English-speaking Drupal users], I facilitate the meeting on Skype. Though they understand English, it is hard for them to speak in English so I translate from Japanese to English for them."

Keiko has plans to help with translating quite a bit of technical material in the future. She has already agreed to assist Chris Luckhardt with translating a Drupal 8 tutorial video into Japanese, and has volunteered to help translate several books as well. In the meantime, she wishes there was a better way to get ahold of other translators like herself.

“I’m not sure because I’ve never thoroughly searched around Drupal.org, but it would be great if there were resources for people who aren't developers,” Keiko said. “I wish there was a better way to find translators, or event organizers— maybe people who don't create websites but instead help to build the project and the community — not only local communities but worldwide communities too. It would be good if there was a place I could go to find people with experience that might be helpful when organizing DrupalCamps, DrupalCons, and Drupal meetups."

Finding a Common Vocabulary

Keiko has a few other pain points, but they mostly revolve around language.

“As a community member, I think so many challenges I have, are… well, first I’m trying to understand what other community members are talking about as accurately, correctly as I can. That’s the first challenge. And I’m trying to learn more Drupal technical terms so that I can understand people's conversations more easily, but oftentimes… it might appear to be an innocent conversation, but behind the ordinary conversation sometimes there are subtexts… you imagine that someone is talking about an innocent topic but when you try to read between the lines there are implications of bigger problems they have.

“For instance, many people in the Japanese Drupal community are spending incredible amounts of time trying to understand what’s written on Drupal.org, because it’s written in English. It’s my impression — and it might be wrong — that the Japanese Drupal community falls into one of two categories: either they catch up with latest information using Drupal.org frequently, or they are totally left behind, staying within only Japanese-written world, because it is so difficult to read English.

"It’s my impression and opinion too that the Japanese community members are trying to attract more people who maybe did not have anything to do with Drupal, but are good with English. For me, I would be happy to find someone who speaks English and Japanese better than I do... the workload can be overwhelming sometimes, but if I could share the task for someone, that would be very helpful for me. "

Dec 17 2014
Dec 17

Imagine somewhere deep in your site that you have a page with the alias:

/how-to-build-drupal-site.

Now, let’s imagine this page is not a link in your site’s menu. Your visitor remembers that they have seen this page on your site and starts typing in the address line:

http://yoursite.com/how-to-make-drupal-site

What will they get? They may get a 404 error page or perhaps a sitemap with a lot of links which could confuse the user. What is their most likely path at this point? Will they start searching interesting pages in the sitemap or just go away and Google it? Answer: Neither.

Chances are, your visitor will leave your site and may not ever come back. Wouldn’t it be nice if on ‘page not found’ your visitors could search the words in the path ‘how to make a drupal site’ and it could present search results with the intended result at the top? Meet Search404.

This post is related to one of the Top 100 Drupal Modules (as on Sep 9, 2012) Search 404 and its work with Apache Solr Search on a Drupal 7 base.

First we’re going to assume that you have installed and configured Apache Solr Search and is working on your site.  The next step will be to download and enable the Search 404 module. After that, you'll be ready to configure their work as partners.

Step One. Site page 404 settings

On Configuration -> System -> Site information page set default 404 (not found) page to search404 (Fig. 1).

C:\Users\User\Documents\Blog\Search404\Fig01.png

Fig. 1 Default 404 page

Step Two. New Apache Solr Search page

On Apache Solr Search configuration page (Configuration -> Search and metadata -> Apache Solr search) go to PAGES/BLOCKS tag (Fig. 2).

Fig. 2 Apache Solr Search configuration page

And add a new search page (Fig. 3) with desired settings.

C:\Users\User\Documents\Blog\Search404\Fig02.png

Fig. 3 Add search page

Make sure Path in your new search page is different from default 404 site page, not equal to search404 (Fig. 4). Also use a custom filter to filter content types that are used as pages on your site. Custom filter must be like bundle:{content_type} without braces.

Fig. 4 Apache Solr search page settings

Step Three. Search404 settings

Go to Configuration -> Search and metadata -> Search 404 settings. Enable Do a "Search" with custom path instead of a Drupal Search when a 404 occurs checkbox and fill Custom search path with your Apache Solr search page, created on previous step, and /@keys argument (Fig. 5)

Fig. 5 Search 404 settings

The rest of the settings can be set based on required behavior.

Ok, we’re almost all done.

Step Five. Status 404 Not Found

For this moment you must have a search404 not found page that will make search with Apache Solr search. But this page won’t set page status 404 (https://drupal.org/node/1852240#comment-6944804). That is why it was written ‘almost all done’. To do this you will need to add some code. You can use hook_preprocess_html_()  to set page 404 status, like in an next example:

function MODULE_preprocess_html(&$variables) {

 // ‘page-not-found’ path was set in step two.

 if (arg(0) && arg(0) == ‘page-not-found’) {

   drupal_add_http_header('Status', '404 Not Found');

 }

}

or you can use your option to set status 404.

Now we’re all done and you have a 404 page with search results gathered by keywords from the wrong link that the visitor originally visited.

Dec 17 2014
Dec 17

Imagine somewhere deep in your site that you have a page with the alias:

/how-to-build-drupal-site.

Now, let’s imagine this page is not a link in your site’s menu. Your visitor remembers that they have seen this page on your site and starts typing in the address line:

http://yoursite.com/how-to-make-drupal-site

What will they get? They may get a 404 error page or perhaps a sitemap with a lot of links which could confuse the user. What is their most likely path at this point? Will they start searching interesting pages in the sitemap or just go away and Google it? Answer: Neither.

Chances are, your visitor will leave your site and may not ever come back. Wouldn’t it be nice if on ‘page not found’ your visitors could search the words in the path ‘how to make a drupal site’ and it could present search results with the intended result at the top? Meet Search404.

This post is related to one of the Top 100 Drupal Modules (as on Sep 9, 2012) Search 404 and its work with Apache Solr Search on a Drupal 7 base.

First we’re going to assume that you have installed and configured Apache Solr Search and is working on your site.  The next step will be to download and enable the Search 404 module. After that, you'll be ready to configure their work as partners.

Step One. Site page 404 settings

On Configuration -> System -> Site information page set default 404 (not found) page to search404 (Fig. 1).

C:\Users\User\Documents\Blog\Search404\Fig01.png

Fig. 1 Default 404 page

Step Two. New Apache Solr Search page

On Apache Solr Search configuration page (Configuration -> Search and metadata -> Apache Solr search) go to PAGES/BLOCKS tag (Fig. 2).

Fig. 2 Apache Solr Search configuration page

And add a new search page (Fig. 3) with desired settings.

C:\Users\User\Documents\Blog\Search404\Fig02.png

Fig. 3 Add search page

Make sure Path in your new search page is different from default 404 site page, not equal to search404 (Fig. 4). Also use a custom filter to filter content types that are used as pages on your site. Custom filter must be like bundle:{content_type} without braces.

Fig. 4 Apache Solr search page settings

Step Three. Search404 settings

Go to Configuration -> Search and metadata -> Search 404 settings. Enable Do a "Search" with custom path instead of a Drupal Search when a 404 occurs checkbox and fill Custom search path with your Apache Solr search page, created on previous step, and /@keys argument (Fig. 5)

Fig. 5 Search 404 settings

The rest of the settings can be set based on required behavior.

Ok, we’re almost all done.

Step Five. Status 404 Not Found

For this moment you must have a search404 not found page that will make search with Apache Solr search. But this page won’t set page status 404 (https://drupal.org/node/1852240#comment-6944804). That is why it was written ‘almost all done’. To do this you will need to add some code. You can use hook_preprocess_html_()  to set page 404 status, like in an next example:

function MODULE_preprocess_html(&$variables) {

 // ‘page-not-found’ path was set in step two.

 if (arg(0) && arg(0) == ‘page-not-found’) {

   drupal_add_http_header('Status', '404 Not Found');

 }

}

or you can use your option to set status 404.

Now we’re all done and you have a 404 page with search results gathered by keywords from the wrong link that the visitor originally visited.

Dec 16 2014
Dec 16

Row of seedsSometimes CSS feels like it stands for “Complete Sh*t Show.”

Lucky for us, there’s a tool to help get our CSS under control. This tool is Sass; Simply Awesome Style Sheets. Well, actually: Syntactically Awesome Stylesheets.

Sass is a preprocessor for CSS. Just like PHP & Drupal create Drupal’s Very Rich and Enhanced Markup™, Sass does the same for CSS, but properly, by taking your .scss (sass) files and turning them into super .css files, with variables, functions, and other fancy powers.

.sass files -> [magic thingie] -> .css

Install Sass

Installing Sass on your machine is straightforward, if you’re not afraid of the terminal. Simply do a "sudo gem install sass".

Boom.

You’re ready to get Sassy.

But if the terminal gives you agita, you can install Sass with a GUI, a complete list can be found on sass-lang.com/install or LiveReload.com.

Here’s a video showing how this process works: http://wdog.it/4/1/video

Setup your Drupal theme

How Sass works with multiple files
In order to make Sass work in your theme, you need:

  • a Ruby config.rb file, for configuration;
  • a Sass folder for all your Sass files;
  • a CSS folder where all your compiled CSS files will be created.

Say Good-bye to Your CSS Files

First, accept that once you convert your CSS files to Sass, you will never again have to look into the CSS folder.

Your days of fiddling directly with CSS are over, and everything is gonna be OK.

Setup the Sass File Structure

Screen Cap
One of the cool things about Sass is being able to split up all your files and let the preprocessor do the heavy lifting. Sass collates all your files into one minified and ready-to-go file, which grants you a bit of sanity inside the [themename].info file.

Instead of creating each of your Sass files (fx foo.scss) to become a .css file (foo.css), add a "_" to the files you don't want to have rendered fx: _menu.scss, _blocks.scss,
and add the partials to your main theme Sass file (theme_name.scss).

Theme Structure

The theme structure can be found here http://wdog.it/4/1/mdk.

Drupal has a tendency to add at least one CSS file per module, which can be a PITA. Attack that the Angry Themer™ way; put the css files into your theme and let Sass take care of it.

By following a combination of sensible file organizing – and competently navigating Drupalisms (i.e., all the dumb rigmarole you have to account for in Drupal that doesn’t happen anywhere else) – you can structure the sass so that you can easily find them again.

Sass folder:

 
/sass/base/
  _base.scss
  _image.scss
...
/sass/drupal/
 _forms.scss
 _forms-login.scss
...
/sass/layout/
 _grid.scss
 _page-layout.scss
...
/sass/design/
 _colors.scss
 _typography.scss
 -fancy.scss
...
/sass/style.scss
buttermuffin.scss

Inside the main sass file for your theme, import all the files you need:

@import "drupal/forms"
@import "drupal/forms-login"

That is the file that will be finally rendered (remember the underscore trick) into style.css.

As the next step we add the style.css file to the theme's info file:

buttermuffin.info
....
 
;-------------- C S S -------------
stylesheets[all][] = css/buttermuffun.css
stylesheets[all][] = dragons.css

In the .info file, we point the theme to the compiled .css file.

Now that I have ranted about the awesomeness of Sass, you might ask: What is that dragons.css file doing there in my theme?

Here’s why: I use the dragons.css for my cute developers – who shouldn’t be meddling with my Sass files – or for when I need a quick ‘n’ dirty fix on a live server. Use the dragons.css file to add stuff in without having to re-roll the sass to css files.

Conquer

Other articles from this issue:

Columns

Doug Green

Familiarity breeds ease-of-use.

Coming Soon

Articles

Karoly (Chx) Negyesi

The power of process plugins.

Coming Soon

Melissa Anderson

Migrating. Now. Here's how.

Coming Soon

Dec 16 2014
Dec 16

INTRODUCTION

Faceted Searching is a method that allows a user to apply multiple filters of varying dimensions to a list of items on your website. This is a great method for quickly filtering a long list of information down to narrower results that are relevant to what you’re searching for.

For example, on Amazon.com you may filter your product lists by “department”, “rating” or “format” or on Zappos.com you may filter by “shoe size”, “shoe width” and “shoe color” to narrow the list of shoes. Faceted searches are a common and effective method for simplifying the searching of items on your website. But how do you achieve this in Drupal? In this tutorial we’ll show you how to create faceted searches that you can use on your Article listing page created using a Drupal View. This method can also be used for Drupal Commerce product pages and almost any other type of data you may be displaying on your site.

Drupal Search API Module Exmplae

VIDEO AVAILABLE: Please note that there is a video version of this tutorial available at the end of this page.

MODULE SETUP

Install the following modules:

Enable the following modules:

  • Current Search Blocks
  • Database Search
  • Search APi
  • Search Facets
  • Search Views

Drupal Search API Module Settings

NOTE: The Search API system that we’ll be using does not require Drupal’s core Search module. If you’re not using a site-wide system search you can safely disable this module.

Dependencies:

The above modules have the following required modules, if there are not already then they will also need to be installed.

NOTE: For this tutorial we’re going to use Drupal’s built-in Article content type. However, you can use any Drupal entity that can be displayed in a View to create your search facets. You can also chain referenced entities so, for example, you can show Drupal Commerce "Display Nodes" while pulling information from the product entities attached to them into your search facets.

CONFIGURATION

SERVER SETUP

The first thing we’ll need to do is create the ‘Server’ that will host your search index that we’ll be using.

  1. Navigate to CONFIGURATION->SEARCH AND META DATA->SEARCH API (YOURSITE/admin/config/search/search_api)
  2. Click the “Add Server” link.
  3. Enter a name and description for your server for your reference. For example, “Search API Server”
  4. From the “Service Class” drop-down, select the “Database Server” option.
  5. Click the “Create Server” button.

Drupal Search API Create DB Server

INDEX SETUP

The next step is to create the index that will hold your search index information. This index will reside within the server object created in the previous step.

  1. Navigate back to to CONFIGURATION->SEARCH AND META DATA->SEARCH API (YOURSITE/admin/config/search/search_api)
  2. Click the “Add Index” link.
  3. Give your index a name, for example (“Article Index”)
  4. In the “Item Type” dropdown, select “Node”.
  5. In the “Server” dropdown, select the server you created in the previous step.
  6. If your index is going to be large then do not select “Index items immediately”. Since our site will not be very large we will check this option so that node changes are updated in the index right away instead of having to wait for the next cron run.
  7. Click the “Create Index” button.

Drupal Search API Index Settings

FIELD SETUP

The next step is to select the fields that will be indexed. This is a basic and arbitrary list for this example but should give you an idea of how the field selection works to get you started. First, under the “Add Related Fields” section near the bottom of the page, add the “Author” and “Main Body Text” to our index. This will give us access to ‘related’ fields to use in our index. After adding these two related-fields you’ll see more fields available to add to your index.

For this example, we’re going to select the following fields:

  1. Title – Even though this isn’t going to be a search facet, we may want to use this for text searches.
  2. Author > Name
    • IMPORTANT: Change the ‘type’ from ‘Full Text’ to ‘String’. This will index the all words of this field as one string instead of individual words.
  3. Tags
  4. The main body text » Text – Even though this isn’t going to be a search facet, we may want to use this for text searches.
  5. Click the “Save Changes” button.

Drupal Search API Field Settings

NOTE: You can adjust the ‘boost’ level as need to increase or decrease the importance the index will give to that field.

FILTERS SETUP

Now we need to set up the fields for our index. You should already be on the “Filters” tab for your index.

  1. Click the “Bundle filter” checkbox so we can limit our index to the Article content type.
  2. Click the “Exclude unpublished nodes” checkbox if you do not want your unpublished nodes to be indexed.
  3. At the button of the form you should now see of list of “Bundles” (exposed by checking the “Bundle Filter” option). Select the “Article” bundle and select the option to ‘only [index] those from the selected bundles’
  4. Click the “Save Configuration” button.

NOTE: For this example we’ve created a few fake Article nodes and populated them some titles, body text, taxonomy tags and authors (Users).

Drupal Search API Filter Settings

FACET SETUP

Now click the “Facets” tab in your Search Index and select the following fields to create facets out of:

  1. Tags
  2. Author > Name

Drupal Search API Facet Settings

NOTE: If your Index is set to "Index Items Immediately" then your Entities will be added to your Index as your create or update them. If this setting is not enabled then your Index will be updated on each Cron run. Either way though, if you make changes to your Search Index settings you will need to rebuild your Index after making the changes. You do this by clicking the "Index Now" button on your Index's View tab.

Drupal Search API Index Now

FACET BLOCKS SETUP

For each Facet created (above) there will be a corresponding Drupal Block available. We'll want to configure these block to display on your search page.

  1. Navigate to the Block configuration page (admin/structure/block)
  2. Find your Search API Blocks (there will be one block for each facet you created earlier and the Block names will start with 'Facet API')
  3. Assign the blocks to the region that you want them to display one. This is usually either Right Sidebar, Left Sidebar, First Sidebar or Second Sidebar.
  4. NOTE: You do not need to assign visibility to the Blocks. They will automatically be displayed only when you ware on a Search API Views page

OPTIONAL: Although optional, you'll most likely want to also enable the "Current search: Standard" to display the result count and parameters of the current search. To do so, simply find the block title "Current search: Standard" and assign it a region. This block usually works best above the main content so the "Content" region with a low weight value should work well.

Drupal Search API Block Settings

VIEW SETUP

Now we'll create a View to display our indexed items and search facets.

  1. Add a new View (admin/structure/views/add)
    • IMPORTANT: Be sure to select the search index name that you created earlier. In this example it is called “Article Index”.
  2. You can create your View however you’d like it to display. In this example, we’ve created our View to display using a Field Display type and the fields we’re using are Node Title, Author Name and Node Tags (taxonomy).
  3. Optional – If you’d like to create a search box for your page add the filter called “Search: Fulltext search”, Expose it and select the text fields to search on. In this example we’re going to allow search on the Title and Body fields so select those two fields.
  4. Save your View once it is setup how you’d like it.

Drupal Search API View Setup

The Magic

Now, when you navigate to your new, Search Index View you'll see the Search Facets appear beside your View. These Facets will automatically display the Facet Fields that you configured and will only display the fields that are contained in your current View.They will also display the Facet count (number of each field contained in your View) and, the best part, they can be combined to produce a very specific list of results!

Drupal Search API View Output

CONCLUSION

This was a very basic example to get you started but, with this very powerful system, you can create complex Search Facets to filter lists using ranges, multiple taxonomy terms, field values, referenced Entities, and much more.

There are additional Facet options available through the Facet's Block configuration options, including, controlling how many items to display, the display type (Check boxes instead of links) and much more. Be sure to explore these options.

NOTE: The Search API module has many Extension Modules available to add additional functionality. A popular Extension Module is the Search API Ranges Module which allow creating slider facets for a high/low range. For example, creating a facet between $100 and $500.

VIDEO VERSION OF THIS TUTORIAL TOPIC

[embedded content]

Dec 16 2014
Dec 16

The world of PHP development is changing. The past few years have seen the rise of a new wave of frameworks, the birth of component-based architectures, the advent of Composer and Packagist.org, and even our own standards body, the PHP-Framework Interoperability Group. A new "Proudly Invented Elsewhere" culture (because everyone loves PIE, right?) has grown exponentially on the reusable community engine of PHP. The future of PHP is now unquestionably in assembling and using decoupled components, from a variety of different sources.

Glasgow Bridge by Moyan Brenn

Specializing and cooperating

For PHP developers this evolution means building with tools from a variety of different sources, not just from Drupal.

When I first started using Drupal nearly a decade ago, PHP was a very different place. Every framework or application was its own universe, and the differences between projects made it normal to buy into one universe or another and hard to get to know many of them.

Drupal, my universe of choice, prided itself on being not really an application nor just a framework. This allowed it to be a "jack of all trades", even if master of none. Getting really, really good at Drupal could serve a developer very well because it let them find creative solutions to many different challenges. At Palantir.net, we had a saying for a while that "Drupal may not always be the best solution, but it is almost always a solution." We could take on almost any project, CMS-ish or framework-ish, knowing that one really good tool really well.

That's not the case anymore. The PHP world – Drupal included – has come together dramatically in recent years and the market has shifted. Drupal itself has evolved, too, to be less a framework and more a first-class Content Management Platform. As it's done so, it has ceded some "pure framework" use cases while pure frameworks have had a renaissance in the form of Symfony2, Zend Framework 2, Aura, Laravel, and other younger projects. The days when knowing just Drupal (or Joomla, or WordPress, or Symfony, or whatever) was all one needed to know are fading. Instead, the future is purpose-built tools born out of common components.

Calgary Peace Bridge by Dave Bloggs

I can work with that!

So where does that leave Drupal 7 developers? It turns out it leaves them with Drupal 8, a child of this new era of PHP. Drupal 8's architectural redesign was driven in a large part, very deliberately, by a desire to bring it more in line with The New PHP, a robust library of tools ready for developers to remix them. The conceptual difference between Drupal, as embodied in Drupal 8, and other major PHP projects is vastly smaller than ever before, providing PHP coders two key advantages: it makes it easier for non-Drupal developers to learn Drupal and it makes it easier for Drupal developers to learn non-Drupal systems.

That's good for everyone for many reasons. For one, it can serve as a solution to Drupal's talent shortage: the easier it is to train experienced, accomplished developers on Drupal, the easier it is for organizations with Drupal sites to find and hire people to maintain them. The most common feedback I get from other PHP developers upon seeing Drupal 8 is "Huh, cool, I can work with that!" I've even gotten that feedback from non-PHP developers, who are another untapped (but now tappable) resource to grow the pool of Drupal service providers the market has been asking for.

On the flipside, this all opens up new opportunities for Drupal developers outside of Drupal. Heretical as it may be to say, Drupal is not the answer to all problems. As software developers, our job is to solve problems, not to solve problems only with Drupal. The more tools we have in our kit, the more problems we can solve effectively. When Drupal isn't the right tool, we need to be able to pivot quickly to the one that fits the job. Pivoting from Drupal 8 and back again will be far easier than ever before.

Navajo Bridge by Glyn Lowe

The future is now

At Palantir, we've already started that process. Last year, we built a REST-centric decoupled CMS platform for a media client using Drupal 7 and the Silex micro-framework, which is based on the same Symfony components as Drupal 8. Earlier this year we built a low-touch site for a client using Sculpin, a PHP-based static site generator that uses some Symfony components but more importantly Twig, the same templating engine used by Drupal 8 (and Symfony, and Oro Platform, Sylius, Foxycart, eZ Publish, phpBB, Piwik, and others). As I write this, my main client project is a two-install all-Symfony project.

Could Drupal have been used for those cases? Quite possibly, but it would not have been a good fit. And that's OK. Look at the commonalities of those projects: Drupal 8, Symfony, Silex, and Sculpin. All four can use Twig templates. All four are built on similar service architectures. All four use, or can use, any of the 30,000 PHP packages available on Packagist. Three of them use the same request/response/routing pipeline. That means any of our engineers can move with relative ease between those systems with only limited retraining. We can use the right tool for the job without having to learn several completely different tools. To do all this all developers only have to learn one main tool: Modern PHP.

The future of PHP is much more heterogeneous than it has been in the past. Of course, such potential is only useful if we’re prepared for it. Every platform has its strengths and weaknesses, and as professional developers we have a responsibility – to ourselves, our clients, and our employers – to know what those are so we can recognize and use the right tool for the job. Modern PHP ties the whole population of solutions together.

Sunset bridge by F Mira

Be the bridges connecting the islands

Two years ago I called on developers to Get Off the Island and attend conferences outside of their comfort space: to meet new faces, learn new things, and open their minds. I've been pleased to see many doing so, with Drupal developers showing up and presenting at general PHP conferences and general PHP developers attending and presenting at DrupalCons and Drupal Camps.

In 2015, let's take that a step further: Don't just learn; Build.

Make it your goal in 2015 to build and launch something meaningful with a new PHP tool. If you're traditionally a Drupal developer, build an all-Symfony project. If you normally use Symfony, build a Zend Framework-based project. If Zend Framework is your home turf, build and ship a project using Aura. If Aura is your happy place, see what Laravel has to offer. If Laravel is your go-to tool, launch a site with Drupal 8. Or even combine pieces of all of them – you can do that now – each playing to its strengths. Get out of your comfort zone … discover a bigger comfort zone!

But don't just build; Teach. Document what you learn by going through the new process. Blog your experiences with your new tools. Share your new insights with your colleagues at your company, at your user group, at conferences.

And don’t just teach; Help. Be a part of The New PHP by helping to build it and the community around it. Be the bridges that are bringing the islands of PHP together, and become a better developer in the process.

Let's learn, let’s teach, let’s help and let’s all build something good together.

Guest Dossier

Image credits

bridge_navajo.jpg - Image by Glyn Lowe - https://www.flickr.com/photos/glynlowe/7183121469 - License https://creativecommons.org/licenses/by/2.0/

bridge_peace_calgary.jpg - Image by Dave Bloggs - https://www.flickr.com/photos/davebloggs007/15267799517 - License https://creativecommons.org/licenses/by/2.0/

bridge_glasgow.jpg - Image by Moyan Brenn - https://www.flickr.com/photos/aigle_dore/4019285756 - License https://creativecommons.org/licenses/by-nd/2.0/

bridge_sunset.jpg - Image by F Mira https://www.flickr.com/photos/fhmira/5019343521 - License https://creativecommons.org/licenses/by-sa/2.0/

Dec 16 2014
Dec 16

The world of PHP development is changing. The past few years have seen the rise of a new wave of frameworks, the birth of component-based architectures, the advent of Composer and Packagist.org, and even our own standards body, the PHP-Framework Interoperability Group. A new "Proudly Invented Elsewhere" culture (because everyone loves PIE, right?) has grown exponentially on the reusable community engine of PHP. The future of PHP is now unquestionably in assembling and using decoupled components, from a variety of different sources.

Glasgow Bridge by Moyan Brenn

Specializing and cooperating

For PHP developers this evolution means building with tools from a variety of different sources, not just from Drupal.

When I first started using Drupal nearly a decade ago, PHP was a very different place. Every framework or application was its own universe, and the differences between projects made it normal to buy into one universe or another and hard to get to know many of them.

Drupal, my universe of choice, prided itself on being not really an application nor just a framework. This allowed it to be a "jack of all trades", even if master of none. Getting really, really good at Drupal could serve a developer very well because it let them find creative solutions to many different challenges. At Palantir.net, we had a saying for a while that "Drupal may not always be the best solution, but it is almost always a solution." We could take on almost any project, CMS-ish or framework-ish, knowing that one really good tool really well.

That's not the case anymore. The PHP world – Drupal included – has come together dramatically in recent years and the market has shifted. Drupal itself has evolved, too, to be less a framework and more a first-class Content Management Platform. As it's done so, it has ceded some "pure framework" use cases while pure frameworks have had a renaissance in the form of Symfony2, Zend Framework 2, Aura, Laravel, and other younger projects. The days when knowing just Drupal (or Joomla, or WordPress, or Symfony, or whatever) was all one needed to know are fading. Instead, the future is purpose-built tools born out of common components.

Calgary Peace Bridge by Dave Bloggs

I can work with that!

So where does that leave Drupal 7 developers? It turns out it leaves them with Drupal 8, a child of this new era of PHP. Drupal 8's architectural redesign was driven in a large part, very deliberately, by a desire to bring it more in line with The New PHP, a robust library of tools ready for developers to remix them. The conceptual difference between Drupal, as embodied in Drupal 8, and other major PHP projects is vastly smaller than ever before, providing PHP coders two key advantages: it makes it easier for non-Drupal developers to learn Drupal and it makes it easier for Drupal developers to learn non-Drupal systems.

That's good for everyone for many reasons. For one, it can serve as a solution to Drupal's talent shortage: the easier it is to train experienced, accomplished developers on Drupal, the easier it is for organizations with Drupal sites to find and hire people to maintain them. The most common feedback I get from other PHP developers upon seeing Drupal 8 is "Huh, cool, I can work with that!" I've even gotten that feedback from non-PHP developers, who are another untapped (but now tappable) resource to grow the pool of Drupal service providers the market has been asking for.

On the flipside, this all opens up new opportunities for Drupal developers outside of Drupal. Heretical as it may be to say, Drupal is not the answer to all problems. As software developers, our job is to solve problems, not to solve problems only with Drupal. The more tools we have in our kit, the more problems we can solve effectively. When Drupal isn't the right tool, we need to be able to pivot quickly to the one that fits the job. Pivoting from Drupal 8 and back again will be far easier than ever before.

Navajo Bridge by Glyn Lowe

The future is now

At Palantir, we've already started that process. Last year, we built a REST-centric decoupled CMS platform for a media client using Drupal 7 and the Silex micro-framework, which is based on the same Symfony components as Drupal 8. Earlier this year we built a low-touch site for a client using Sculpin, a PHP-based static site generator that uses some Symfony components but more importantly Twig, the same templating engine used by Drupal 8 (and Symfony, and Oro Platform, Sylius, Foxycart, eZ Publish, phpBB, Piwik, and others). As I write this, my main client project is a two-install all-Symfony project.

Could Drupal have been used for those cases? Quite possibly, but it would not have been a good fit. And that's OK. Look at the commonalities of those projects: Drupal 8, Symfony, Silex, and Sculpin. All four can use Twig templates. All four are built on similar service architectures. All four use, or can use, any of the 30,000 PHP packages available on Packagist. Three of them use the same request/response/routing pipeline. That means any of our engineers can move with relative ease between those systems with only limited retraining. We can use the right tool for the job without having to learn several completely different tools. To do all this all developers only have to learn one main tool: Modern PHP.

The future of PHP is much more heterogeneous than it has been in the past. Of course, such potential is only useful if we’re prepared for it. Every platform has its strengths and weaknesses, and as professional developers we have a responsibility – to ourselves, our clients, and our employers – to know what those are so we can recognize and use the right tool for the job. Modern PHP ties the whole population of solutions together.

Sunset bridge by F Mira

Be the bridges connecting the islands

Two years ago I called on developers to Get Off the Island and attend conferences outside of their comfort space: to meet new faces, learn new things, and open their minds. I've been pleased to see many doing so, with Drupal developers showing up and presenting at general PHP conferences and general PHP developers attending and presenting at DrupalCons and Drupal Camps.

In 2015, let's take that a step further: Don't just learn; Build.

Make it your goal in 2015 to build and launch something meaningful with a new PHP tool. If you're traditionally a Drupal developer, build an all-Symfony project. If you normally use Symfony, build a Zend Framework-based project. If Zend Framework is your home turf, build and ship a project using Aura. If Aura is your happy place, see what Laravel has to offer. If Laravel is your go-to tool, launch a site with Drupal 8. Or even combine pieces of all of them – you can do that now – each playing to its strengths. Get out of your comfort zone … discover a bigger comfort zone!

But don't just build; Teach. Document what you learn by going through the new process. Blog your experiences with your new tools. Share your new insights with your colleagues at your company, at your user group, at conferences.

Be a part of The New PHP by helping to build it and the community around it. Be the bridges that are bringing the islands of PHP together, and become a better developer in the process.

Let's learn, let’s teach, and let’s all build something good together.

Guest Dossier

Image credits

bridge_navajo.jpg - Image by Glyn Lowe - https://www.flickr.com/photos/glynlowe/7183121469 - License https://creativecommons.org/licenses/by/2.0/

bridge_peace_calgary.jpg - Image by Dave Bloggs - https://www.flickr.com/photos/davebloggs007/15267799517 - License https://creativecommons.org/licenses/by/2.0/

bridge_glasgow.jpg - Image by Moyan Brenn - https://www.flickr.com/photos/aigle_dore/4019285756 - License https://creativecommons.org/licenses/by-nd/2.0/

bridge_sunset.jpg - Image by F Mira https://www.flickr.com/photos/fhmira/5019343521 - License https://creativecommons.org/licenses/by-sa/2.0/

Dec 16 2014
Dec 16
Using Bootstrap as Drupal base theme

There are so many website themes, frameworks and opinions out there ... how do you decide which is the best foundation for your next project?

You can purchase a ready to use theme, start from a base theme with as much or as little foundation as you like or you can build your own HTML from scratch and then add Wordpress or Drupal API code to your HTML.

I have personally used all of these approaches across various projects, but I have a strong preference these days for Bootstrap as the foundation for every website I build on Drupal, Wordpress and small static pages.

Why I don't use the other approaches any longer

Of course, there are more reasons than I can list here, but a few notes on why I don't start projects without Bootstrap:

  • Ready to use purchased theme: There are many thousands of Wordpress ready to go themes and fewer (but still many) Drupal ready-to-go themes. My biggest reason to avoid these has to do with the design being mostly locked in already. These themes are usually complete designs just waiting for a logo, copy and images. I find I have to argue with the theme too much to bend it away from the built-in design. Some of these themes are so complex they actually change the CMS core functions, but I need consistency across projects in the CMS so my content editors can work across client sites.
  • Build your own HTML: For years, my preferred approach was to build my own perfectly clean HTML/CSS. This has the benefit of being clean and exactly suited to the needed design. In recent years, though, I have fallen out of love with this approach due to the need to reinvent the wheel with every project. Now that every website needs to be responsive and work across browsers and devices and websites requirements include sophisticated CSS3 effects, jQuery magic and HTML5 sophistication—it just doesn't make sense to start over with each project.
  • Wonderful frameworks like 960 grid and others don't include all the LESS/SASS mix-ins that I have at my fingertips with Bootstrap.

Why I use Bootstrap

Before I begin, I should include a quick disclaimer—I have used and also love Zurb Foundation. Bootstrap and Foundation have pretty good feature parity these days. We chose Bootstrap when Foundation didn't have as much Drupal support, but Foundation has pretty robust Drupal support now so in the end you can choose by features meaningful to you.

  • Boostrap includes all the documentation and code to work across browsers and devices.
  • Bootstrap includes tons of mix-ins that allow sophisticated content even inside the WYSIWYG. I also use it in template code and event in Drupal views and Drupal Display Suite.
  • Bootstrap has mobile functionality built in. Whether I'm mobile-first or desktop-first, I am pleasantly surprised when I'm styling a page and then check other breakpoints and almost every time, it is already 95% there ... I just need to add a few adjustments here and there.
  • Many common advanced widgets are already included: buttons, carousels, accordion lists, tabs, and more are already included and just require you to add some classes to your html output.
  • Lots of documentation already exists. If I run into an issue, I can check the Bootstrap website, Stack Overflow and Drupal theme support issue queues.

Drupal-specific modules used to help create a Drupal Bootstrap site

What do you think?

If you've tried one of these methods and have other opinions, please chime in. I seem to check out themes and frameworks like a hobby. I often find myself downloading and playing with a new framework or theme and constantly evaluating it against what I do now. Have you found something better?

Dec 16 2014
Dec 16

YouTube is a great service for storing and managing your videos. While this is handy, many people want to be able to display their videos within their own website as well. You can easily copy the embed code from YouTube and paste that into your content body field, but that only works properly if you have your text formats set up correctly, and you may not want to open that up to just anyone. You also have no way of keeping track of the videos from within your site. This is where the Media, Media Internet Sources (part of the Media package), and Media: YouTube modules can help give you a nice, seamless way to integrate YouTube videos into your site, and give really nice control over how those videos look, along with some built-in media management tools.

This tutorial, based on the free Embed YouTube Videos video from the Working with Media Module in Drupal 7 series, expects a basic understanding of the 1.x Media module. We're using 1.x because that is the current stable release, and version 2 is still in an alpha state. We're starting off with the assumption that you have a Drupal 7 site up and running, with the Media and Media: YouTube modules already downloaded and ready to go. At the end of this tutorial you will have a new video content type created, with a YouTube field that lets you paste in a YouTube video URL or embed code. We'll be diving into Media's file display settings to also make sure the embedded video displays we way we want in different contexts.

The key to making all of this work is the Media Internet Sources module, provided as part of the Media package. Without getting into lots of details, this module provides a standard mechanism for handling stream wrappers, which means you can ingest a lot of different internet services. This is a base module that you use combined with specific provider modules, which extend Media Internet Sources for use with a particular service. You can see a list of the various providers you can use on the Modules that Extend the Media Module page, under the Provider Projects section. We're focused on YouTube videos here, but you can use this same base to integrate many different services into your site.

Hands-on

So let's get started! We're going to enable the modules we need, and then build out the content type. Once that's in place, we'll grab a video URL and make our first video node. To clean things up, we'll dive into Media file display settings and make sure the video displays just the way we like it.

Create the Video Content Type

  1. In the Administrative menu, go to Modules (admin/modules).
  2. Enable the Media, Media Internet Sources, and Media: YouTube modules (located under the Media section).
  3. In the Administrative menu, go to Structure > Content types (admin/structure/types), and click on the "Add content type" link.
  4. Type Video in the Name field, and leave all other defaults. Click the "Save and add fields" button.
  5. Add a new field called YouTube video with the following settings:
    Field name Value Label YouTube video Field Type File Widget Media file selector
  6. Click "Save" and then accept the defaults for the Field Settings screen, and click "Save field settings." Note that we are not going to actually upload any files to this field since we're using an embed, so the upload settings can be ignored.
  7. Complete the Video field settings using the following values, leaving any others at their defaults:
    Field name Value Label YouTube video Required Checked Allowed remote media types Video Allowed URI schemes youtube:// (YouTube videos)
  8. Click the "Save settings" button.

Create a Video Node
Now that we have a content type, go ahead and create a new video node as you normally would, entering whatever text you want for the Title and Body fields. When you come to the YouTube video field:

  1. Go to YouTube.com, find a video you like, and copy either the URL or the embed code from underneath the video player, under the "Share" tab. (You can also just grab the URL from your browser's address bar.)
    YouTube video links
  2. Back on your node creation form, click the "Select media" button. This will pop open a media selector.
  3. Click on the "Web" tab, and paste your YouTube video information into the URL or Embed code field. Click "Submit."
  4. Save the node.

Fix the Video Field Display
You'll see that our video is not actually showing up as a video player, but as a link instead, so we need to go tweak the field display.

  1. In the Administrative menu, go to Structure > Content types (admin/structure/types), and click on the "manage display" link for the Video content type.
  2. Update the settings for the YouTube video field as follows:
    Field name Value Label hidden Format Rendered file
  3. Click "Save" and close the overlay. Our video is now displaying as a playable video player.

Modify the Media File Display
The content type is now working as expected, and displaying my video properly, but if you go back and edit this node, you'll notice that we have the same large player displaying on the edit form, and this is actually covering up some important functions, like being able to remove the video from the field. We'll finish this up by fixing that, and getting to understand how you can manipulate the video file display from within your own site. Much like content types, Media field types have different view modes. On a content type, these are things like Default, Full node, or Teaser. On a field type, you have Default, Preview, Large, etc. We need to fix the Preview view mode that is being shown on the node edit screen, as right now it is just falling back to the Default mode that the node is using.

One important thing to note is that the "file display" is what we are looking for here, not "manage display." The file display digs into the file itself, while manage display for the file types lets us control meta information about the file.

  1. In the Administrative menu, go to Configuration (admin/config) and click the "File types" link (admin/config/media/file-types), in the Media section.
  2. Click "manage file display" for the Video file type.
  3. Click the "Preview" sub-tab to get to the settings for the Preview mode.
  4. Check the YouTube Preview Image option in the Enabled displays field, which will open up a Display settings section at the bottom of the page.
  5. Select square_thumbnail for the Image style field, and click "Save settings."

Now if you go back and edit the video node you created earlier, you'll see that the YouTube video field is showing a nice, tame square thumbnail instead of the big video player. If you wanted to change the settings for the video display on the node, you can always go into the Video file display settings and configure the Default, or other file view modes, to the size you prefer.

Summary

In this short tutorial you've built a new video content type that lets you easily embed YouTube videos, using the Media, Media Internet Sources, and Media: YouTube modules. The advantage of using Media for this is that in addition to a handy field for embedding your video, you also get the media management tools to keep track of and reuse these videos on your site, in addition to having nice, fine-grained control over the output. Media gives you display options for different kinds of files, in different contexts, or view modes, including embedded YouTube videos through the File Display settings. Hopefully this introduction not only showed you how to use embedded videos very quickly and easily, but also gave a look at different ways you can use and customize the Media package for your next project.

Dec 16 2014
Dec 16
function mymodule_views_query_alter(&$view, &$query) {

  global $user;
        
  if (($view->name === 'coaches') || ($view->name === 'trainers')) { 
   
    if (!in_array('trainer', $user->roles) && !in_array('admin', $user->roles)) {
  
      $view->query->fields['field_data_field_profile_hidden'] = array(
        'field' => 'field_profile_hidden_value',
        'table' => 'field_data_field_profile_hidden',
        'alias' => 'field_data_field_profile_hidden'
      );
      
      $join = new views_join;
      $join->table ='field_data_field_profile_hidden';
      $join->left_table = 'users';
      $join->left_field = 'uid';
      $join->field = 'entity_id';
      $join->extra = array(
        0 => array('field' => 'entity_type', 'value' => 'user'),
      );
      $join->type = "LEFT";
      $join->extra_type = 'AND';
      $join->adjusted = 'TRUE';
      
      // add the join
      $view->query->table_queue['field_data_field_profile_hidden'] = array(
        'table' => 'field_data_field_profile_hidden',
        'num' => 1,
        'alias' => 'field_data_field_profile_hidden',
        'join' => $join,
        'relationship' => 'users'
      );
  
      $view->query->tables['node']['field_data_field_profile_hidden'] = array(
        'count' => 1,
        'alias' => 'field_data_field_profile_hidden'
      );
  
      $view->query->where[2]['conditions'][] = array(
        'field' => 'field_profile_hidden_value',
        'value' => 0,
        'operator' => '='
      );
  
    }
  }
}
/**
 * Implements hook_update_N().
 */
function mymodule_update_7001(&$sandbox) {

  $uids = db_select('users', 'u')
    ->fields('u', array('uid'))
                ->execute()
                ->fetchCol();
                
  foreach ($uids as $uid) {
  
    db_insert('field_data_field_profile_hidden')
      ->fields(array(
        'entity_type' => 'user',
        'bundle' => 'user',
        'entity_id' => $uid,
        'revision_id' => $uid,
        'language' => 'und',
        'delta' => 0,
        'field_profile_hidden_value' => 0,
    ))
    ->execute();
  
  }             
}
Sam
Dec 16 2014
Dec 16

Earlier this week I had the opportunity to be the first developer at Code Drop to sit an exam to become an "Acquia Certified Developer". I managed to clear the exam with the following results:

  • Section 1 - Fundamental Web Development Concepts: 87%
  • Section 2 - Site Building: 87%
  • Section 3 - Front end development (Theming) : 92%
  • Section 4 - Back end development (Coding) : 81%

Like many others who have done the exam, I will briefly run over my experience and thoughts on the whole process.

Setup & Software

The testing software provided by Kryterion had some serious rough edges and inconsistencies. All in all, I probably spent 20 minutes chatting to support to try and iron out issues with my account and to clarify inconsistencies with their instructions. Amongst the issues were:

  • Total meltdown of my computer after unplugging my external monitors to center the camera on my face during the Biometric Profile.
  • No clear status indicating if the Biometric profile was successful after my computer restarted.
  • General confusion as to why the character "?" was not included as one of the “special characters” required to make up passwords (a trivial point I'll admit).
  • Inconsistent information about what kind of camera and environment is required for the examination.
  • Inconsistent information about software and hardware requirements, specifically around requiring several network ports to be open?
  • The software simply shutting off completely twice during the exam with no feedback as to why (I now suspect it was due to my internet connection dropping momentarily and I was able to resume the test where I left off by relaunching from the online portal).
  • A general lack of polish when being guided through the setup and purchasing of the examination.

All of those quarms aside, once things were churning along, the software did allow me to select answers to questions and it did spit out a score at the end. Ironically, if you excluded all of the faux security around cheating, Drupal would have been an ideal platform for the e-commerce and testing features.

Getting prepared

I read over the Get Ready guide provided by Acquia a few hours before taking the exam.

  • Some of the documentation linked to was for Drupal 6, which did throw me initially. There wasn’t anything that stuck out to me as being D6 specific in the exam.
  • Skimming some of the documentation I was less familiar with was very valuable, especially when I knew I leaned on documentation and my IDE for certain things frequently.
  • A lot of the material linked didn’t come up in any form in the exam, but I imagine my 60 questions were selected randomly from a pool.
  • The relevant training videos from Drupalize.me was a nice touch. Code Drop are an avid subscriber to the website already!

I think in a lot of cases, the questions did heavily lend themselves to someone who had been getting their hands dirty with Drupal as opposed to someone who had memorised the documentation (which is a great sign in my opionion).

Evaluating the test

My thoughts on the usefulness of the test probably echo those of others who have written about it:

Certification isn’t meant to be used as a stand alone method of evaluating candidates.
Heather James

There are many other aspects to recruitment for which certification does not provide a substitute; it is only one piece of the puzzle.
Dries Buytaert

As the above quotes concisely sum up, I would be hesitant to say scoring a passing grade of 65% would be an automatic qualifier for any Drupal development role, but I think passing the exam and spending the time and money to take the exam are good qualifiers for developers who are invested in Drupal. Being invested in Drupal along with skills and experience are all part of the DNA of an excellent developer.

At Code Drop, the following factors come into play when we are looking for Drupal developers:

  • Involvement in the Drupal community (contrib, core, support, conferences, stack exchange, whatever).
  • A hands on interview with coding challenges (we have kicked around the idea of formalising these challenges into an interactive Drupal module which verifies the list of challenges have been completed).
  • The desire to continue to learn and improve their Drupal skills over time.

I imagine most Drupal agencies have some similar set of rules for evaluating candidates. 

Summing up

I would highly recommend taking the certification exam if you are a Drupal developer. If you want to be prequalified as someone who has worked with Drupal before and is interested in the platform, it's a no-brainer.

Dec 15 2014
Dec 15

Earlier this year we undertook a project to upgrade a client's infrastructure to all new servers including a migration from old Puppet scripts which were starting to show their age after many years of server and service changes. During this process, we created a new set of Puppet scripts using Hiera to separate configuration data from modules. The servers in question were all deployed with CentOS, and it soon became obvious that we needed a modular way in Puppet to install and configure yum package repositories from within our various Puppet modules.

Searching through the Puppet Forge uncovered a handful of modules created to deal with yum repos, however most were designed to implement a single repository, or were not easily configurable via Hiera, which was one of our main goals for the new Puppet scripts. So, we decided to create our own module, and the yumrepos Puppet module was born.

The idea behind the module is to provide a clean and easy way to pull in common CentOS/RHEL yum repos from within Puppet. By wrapping each repo with its own class (e.g. yumrepos::epel and yumrepos::ius), we gain the ability to override default class parameters with Hiera configuration, making the module easy to use in most any environment. For example, if you have your own local mirror of a repo, you can override the default URL parameter either in Hiera, or from the class declaration without having to directly edit any files within the yumrepos module. This is as easy as:

  1. In your calling class, declare the yumrepo class you need. In this example, we'll use EPEL: class { 'yumrepos::epel': }
  2. In your Hiera configuration, you can configure the repo URL with: yumrepos::epel::epel_url: http://your.local.mirror/path/to/epel/

Currently the yumrepos module provides classes for the following yum repos:

  • Drupal Drush 5
  • Drupal Drush 6
  • EPEL
  • IUS Community (Optionally: IUS Community Archive)
  • Jenkins
  • Jpackage
  • Percona
  • PuppetLabs
  • RepoForge
  • Varnish 3
  • Zabbix 2.4

Each repo contains the GPG key for the repo (where available) and defaults to enabling GPG checks. Have another repo you'd like to see enabled? Feel free to file an issue or pull request at https://github.com/tag1consulting/puppet-yumrepos

Additionally, yumrepos classes accept parameters for package includes or excludes so that you can limit packages on a per-repo basis. These translate to the includepkgs and exclude options within a yum repo configuration. Similar to overriding the default repo URL, these options can be overridden by passing parameters within the class declaration or by setting the appropriate variables within Hiera.

Once we had the yumrepos module in place, we had an easy way to configure yum repos from within our other modules. Stay tuned to the blog; we'll have more information about the overall Puppet scripts coming soon.

Dec 15 2014
Dec 15

Bronwen Buswell, Drupal Newcomer This post is part of an ongoing series detailing the new personas that have been drawn up as part of our Drupal.org user research.

Bronwen Buswell is a newcomer to Drupal. Based out of Colorado Springs, Colorado, Bronwen works as a Conference and Communications Coordinator at a nonprofit called PEAK Parent Center, which is dedicated to supporting the families of children with disabilities. While Bronwen’s role isn’t technical, she needs to use her company’s website as part of getting her work done.

“We’re federally designated by the US Department of Education, so we try to be a total one-stop shop information and referral center,” Bronwen said. “Families can call us about any situation related to their child, and we will either refer them to the right agency or provide what they need. We’re focused on helping families navigate the education and special education systems, and we serve families with children ages birth through 26, with all sorts of disabilities, including autism, down syndrome, learning disabilities, and so on."

Keeping Up With Technology

In the past few years, PEAK Parent Center’s website became very outdated, and this was a problem. Bronwen’s clients were very dependent on being able to receive assistance over the phone, as many of the resources that the center provides are not readily available online. When updates needed to be made, Bronwen and her company were forced to rely on their tech vendors to make changes to the website, as they were working with a custom solution rather than a CMS.

“Our website was pre-cutting edge, made by local vendors, all in HTML code and SQL database. We had excellent tech vendors who helped us create what we needed, and this was before the CMS options came along so it was really good at first. However, in the past 5 to 6 years, it has gotten really archaic, and we’re super reliant upon our vendors for updating our website. What’s simple in a CMS is complex for us,” Bronwen said.

After doing lots of research and working with the federal government to find the best solution for PEAK Parent Center and other centers like it, Bronwen and her colleagues decided to explore using Drupal to create a site template that could be deployed for PEAK Parent Center  and for other similar centers that it supports across the country.

“We're the technical assistance center for parent centers like ours in a 12 state region,” said Bronwen. “When [Drupal Association Executive Director] Holly Ross was at NTEN we started going to their conferences, which led us to launch a tech leadership initiative where we supported participating parent centers across the nation. As part of that, we got connected with great consultants and thinkers in tech, and we were asked by the US Department of Education to participate in the creation of website templates in 2 content management systems — Wordpress and Drupal — that could be used in other parent centers in the future."

Getting Experienced Assistance

With help from Aaron Pava and Nikki Pava at Alegria Partners, the staff at PEAK Parent Center has been learning to use their new Drupal website. Aaron has advised Bronwen and her colleagues every step of the way, from proposing solutions in the discovery process to walking Bronwen and her coworkers through specific tasks.

Occasionally, Bronwen encounters small problems due to updates or little glitches with distributions, which is why Aaron has encouraged her to get involved and do some training on Drupal. Unfortunately, most of Bronwen’s time is spent trying to get the website ready to launch, as she’s under pressure from the federal government and her board of directors to deploy the new site. Though Bronwen isn’t working on the technical side of the website, she’s busy populating it with content and making sure that it will be a useful tool for her clients.

“What I haven’t done is specific Drupal training,” said Bronwen. “I know about Lynda and Build A Module, but I’ve only had time to do sessions one-on-one with Aaron, for example, ‘Here’s how to upload content in this template.’

"I have learned a lot on Drupal.org, but it’s been primarily through Aaron sending me a link— for example, he’ll send me links about Red Hen since we’re exploring our CRM options— but I haven’t surfed around it much,” Bronwen added.

Areas For Improvement

Bronwen wishes there was a recommended Drupal 101 section on Drupal.org, something that would help content editors like herself learn to use the CMS better, but for now, she is limited to relying on more educated ambassadors for Drupal to point her in the right direction.

“It’s delicate to recommend vendors,” said Bronwen, "but it seems that the community is really powerful, and is certainly one of the most unique aspects that sets Drupal aside from other CMS options. Even a few vendors recommended by the community, or a recommend Drupal 101 lesson where you can go through it, go off and work in Drupal, and come back and get Drupal 201 would be really valuable for me.

“I know that there are local Drupal meet-ups that happen all over the country” Bronwen added. “[One group we talked with] told us that nonprofits can go to these events and say “I need this or that,” and some hardcore Drupal techie will take the work on pro bono. That was another factor that helped draw us to using Drupal — the availability of the community. It would be useful if there was more information on how to tap into those meetups, perhaps, when they’re happening."

Bronwen knows that the Drupal community is really powerful, and considers it one of the most unique aspects that sets Drupal aside from other CMS options. She is excited by the availability of the Drupal community, and is looking forward to interacting with it and working with them as she continues to run and improve PEAK Parent Center’s website.

Dec 15 2014
Dec 15

I just posted a large excerpt from Ansible for DevOps over on the Server Check.in blog: Highly-Available Infrastructure Provisioning and Configuration with Ansible. In it, I describe a simple set of playbooks that configures a highly-available infrastructure primarily for PHP-based websites and web applications, using Varnish, Apache, Memcached, and MySQL, each configured in a way optimal for high-traffic and highly-available sites.

Here's a diagram of the ultimate infrastructure being built:

Highly Available Infrastructure

The configuration is similar to what many larger Drupal sites would use, and with the exception of the varnish default.vcl and the actual PHP script being deployed (in the example, it's just a PHP file that tests the rest of the infrastructure and outputs success/fail statuses), you could drop a Drupal site on the Apache servers and immediately start scaling up your traffic!

The example highlights the powerful simplicity of Ansible as a tool for not only configuration management (like Puppet, Chef, etc.), but also for provisioning and managing servers in different cloud providers. With under a hundred lines of YAML configuration, I can spin up the exact same infrastructure locally with Vagrant and VirtualBox, on DigitalOcean droplets, or on AWS EC2 instances!

Dec 15 2014
Dec 15

Angular.js is the hot new thing right now for designing applications in the client. Well, it’s not so new anymore but is sure as hell still hot, especially now that it’s being used and backed by Google. It takes the idea of a JavaScript framework to a whole new level and provides a great basis for developing rich and dynamic apps that can run in the browser or as hybrid mobile apps.

logo_drupal

In this article I am going to show you a neat little way of using some of its magic within a Drupal 7 site. A simple piece of functionality but one that is enough to demonstrate how powerful Angular.js is and the potential use cases even within heavy server-side PHP frameworks such as Drupal. So what are we doing?

We are going to create a block that lists some node titles. Big whoop. However, these node titles are going to be loaded asynchronously using Angular.js and there will be a textfield above them to filter/search for nodes (also done asyncronously). As a bonus, we will also use a small open source Angular.js module that will allow us to view some of the node info in a dialog when we click on the titles.

So let’s get started. As usual, all the code we write in the tutorial can be found in this repository.

Ingredients

In order to mock this up, we will need the following:

  • A custom Drupal module
  • A Drupal hook_menu() implementation to create an endpoint for querying nodes
  • A Drupal theme function that uses a template file to render our markup
  • A custom Drupal block to call the theme function and place the markup where we want
  • A small Angular.js app
  • For the bonus part, the ngDialog Angular module

The module

Let us get started with creating a custom module called Ang. As usual, inside the modules/custom folder create an ang.info file:

name = Ang
description = Angular.js example on a Drupal 7 site.
core = 7.x

…and an ang.module file that will contain most of our Drupal related code. Inside this file (don’t forget the opening tag), we can start with the hook_menu() implementation:

/**
 * Implements hook_menu().
 */
function ang_menu() {
  $items = array();

  $items['api/node'] = array(
    'access arguments' => array('access content'),
    'page callback'     => 'ang_node_api',
    'page arguments' => array(2),
    'delivery callback' => 'drupal_json_output'
  );

  return $items;
}
/**
 * API callback to return nodes in JSON format
 *
 * @param $param
 * @return array
 */
function ang_node_api($param) {

  // If passed param is node id
  if ($param && is_numeric($param)) {
    $node = node_load($param);
    return array(
      'nid' => $param,
      'uid' => $node->uid,
      'title' => check_plain($node->title),
      'body' => $node->body[LANGUAGE_NONE][0]['value'],
    );
  }
  // If passed param is text value
  elseif ($param && !is_numeric($param)) {
    $nodes = db_query("SELECT nid, uid, title FROM {node} n JOIN {field_data_body} b ON n.nid = b.entity_id WHERE n.title LIKE :pattern ORDER BY n.created DESC LIMIT 5", array(':pattern' => '%' . db_like($param) . '%'))->fetchAll();
    return $nodes;
  }
  // If there is no passed param
  else {
    $nodes = db_query("SELECT nid, uid, title FROM {node} n JOIN {field_data_body} b ON n.nid = b.entity_id ORDER BY n.created DESC LIMIT 10")->fetchAll();
    return $nodes;
  }
}

In hook_menu() we declare a path (api/node) which can be accessed by anyone with permissions to view content and which will return JSON output created in the callback function ang_node_api(). The latter gets passed one argument, that is whatever is found in the URL after the path we declared: api/node/[some-extra-param]. We need this argument because of we want to achieve 3 things with this endpoint:

  1. return a list of 10 most recent nodes
  2. return a node with a certain id (api/node/5 for example)
  3. return all the nodes which have the passed parameter in their title (api/node/chocolate for example, where chocolate is part of one or more node titles)

And this is what happens in the second function. The parameter is being checked against three cases:

  • If it exists and it’s numeric, we load the respective node and return an array with some basic info form that node (remember, this will be in JSON format)
  • If it exists but it is not numeric, we perform a database query and return all the nodes whose titles contain that value
  • In any other case (which essentially means the lack of a parameter), we query the db and return the latest 10 nodes (just as an example)

Obviously this callback can be further improved and consolidated (error handling, etc), but for demonstration purposes, it will work just fine. Let’s now create a theme that uses a template file and a custom block that will render it:

/**
 * Implements hook_theme().
 */
function ang_theme($existing, $type, $theme, $path) {
  return array(
    'angular_listing' => array(
      'template' => 'angular-listing',
      'variables' => array()
    ),
  );
}

/**
 * Implements hook_block_info().
 */
function ang_block_info() {

  $blocks['angular_nodes'] = array(
    'info' => t('Node listing'),
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function ang_block_view($delta = '') {

  $block = array();

  switch ($delta) {
    case 'angular_nodes':
      $block['subject'] = t('Latest nodes');
      $block['content'] = array(
        '#theme' => 'angular_listing',
        '#attached' => array(
          'js' => array(
            'https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js',
            'https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular-resource.js',
            drupal_get_path('module', 'ang') . '/lib/ngDialog/ngDialog.min.js',
            drupal_get_path('module', 'ang') . '/ang.js',
          ),
          'css' => array(
            drupal_get_path('module', 'ang') . '/lib/ngDialog/ngDialog.min.css',
            drupal_get_path('module', 'ang') . '/lib/ngDialog/ngDialog-theme-default.min.css',
          ),
        ),
      );
      break;
  }

  return $block;
}

/**
 * Implements template_preprocess_angular_listing().
 */
function ang_preprocess_angular_listing(&$vars) {
  // Can stay empty for now.
}

There are four simple functions here:

  1. Using hook_theme() we create our angular_listing theme that uses the angular-listing.tpl.php template file we will create soon.
  2. Inside the hook_block_info() we define our new block, the display of which is being controlled inside the next function.
  3. Using hook_block_view() we define the output of our block: a renderable array using the angular_listing theme and which has the respective javascript and css files attached. From the Google CDN we load the Angular.js library files, inside ang.js we will write our JavaScript logic and in the /lib/ngDialog folder we have the library for creating dialogs. It’s up to you to download the latter and place it in the module following the described structure. You can find the files either in the repository or on the library website.
  4. The last function is a template preprocessor for our template in order to make sure the variables are getting passed to it (even if we are actually not using any).

As you can see, this is standard boilerplate Drupal 7 code. Before enabling the module or trying out this code, let’s quickly create the template file so Drupal doesn’t error out. Inside a file called angular-listing.tpl.php, add the following:

        
        
           
        
             

Filter

  • Open {{ node.title }}

Here we have some simple HTML pimped up with Angular.js directives and expressions. Additionally, we have a tag used by the ngDialog module as the template for the dialog. Before trying to explain this, let’s create also our ang.js file and add our javascript to it (since the two are so connected):

angular.module('nodeListing', ['ngResource', 'ngDialog'])

  // Factory for the ngResource service.
  .factory('Node', function($resource) {
    return $resource(Drupal.settings.basePath + 'api/node/:param', {}, {
      'search' : {method : 'GET', isArray : true}
    });
  })

  .controller('ListController', ['$scope', 'Node', 'ngDialog', function($scope, Node, ngDialog) {
    // Initial list of nodes.
    $scope.nodes = Node.query();

    // Callback for performing the search using a param from the textfield.
    $scope.doSearch = function() {
      $scope.nodes = Node.search({param: $scope.search});
    };

    // Callback to load the node info in the modal
    $scope.open = function(nid) {
      $scope.loadedNode = Node.get({param: nid});
      ngDialog.open({
        template: 'loadedNodeTemplate',
        scope: $scope
      });
    };

}]);

Alright. Now we have everything (make sure you also add the ngDialog files as requested in the #attached key of the renderable array we wrote above). You can enable the module and place the block somewhere prominent where you can see it. If all went well, you should get 10 node titles (if you have so many) and a search box above. Searching will make AJAX calls to the server to our endpoint and return other node titles. And clicking on them will open up a dialog with the node title and body on it. Sweet.

But let me explain what happens on the Angular.js side of things as well. First of all, we define an Angular.js app called nodeListing with the ngResource (the Angular.js service in charge communicating with the server) and ngDialog as its dependencies. This module is also declared in our template file as the main app, using the ng-app directive.

Inside this module, we create a factory for a new service called Node which returns a $resource. The latter is in fact a connection to our data on the server (the Drupal backend accessed through our endpoint). In addition to the default methods on it, we define another one called .search() that will make a GET request and return an array of results (we need a new one because the default .get() does not accept an array of results).

Below this factory, we define a controller called ListController (also declared in the template file using the ng-controller directive). This is our only controller and it’s scope will apply over all the template. There are a few things we do inside the controller:

  1. We load nodes from our resource using the query() method. We pass no parameters so we will get the latest 10 nodes on the site (if you remember our endpoint callback, the request will be made to /api/node). We attach the results to the scope in a variable called nodes. In our template, we loop through this array using the ng-repeat directive and list the node titles. Additionally, we create a button for each with an ng-click directive that triggers the callback open(node.nid) (more on this at point 3).
  2. Looking still at the template, above this listing, we have an input element whose value will be bound to the scope using the ng-model directive. But using the ng-change directive we call a function on the scope (doSearch()) every time a user types or removes something in that textfield. This function is defined inside the controller and is responsible for performing a search on our endpoint with the param the user has been typing in the textfield (the search variable). As the search is being performed, the results populate the template automatically.
  3. Lastly, for the the bonus part, we define the open() method which takes a node id as argument and requests the node from our endpoint. Pressing the button, this callback function opens the dialog that uses a template defined inside of the tag with the id of loadedNodeTemplate and passes to it the current scope of the controller. And if we turn to the template file, we see that the dialog template simply outputs the title and the body of the node.

Conclusion

You can see for yourself the amount of code we wrote to accomplish this neat functionality. Most of it is actually boilerplate. A very fast node query block that delivers results asynchronously with all of its benefits. And if you know Angular.js, you can imagine the possibility of enhancing the Drupal experience further.

Now, are you interested to learn more about the love between Angular.js and Drupal? Would you have done anything differently? Let us know in the comments below!

Dec 15 2014
Dec 15

Today most of the websites have search functionality. With the help of Apache Solr the time spent on waiting for a search result can be radically reduced. In this article we are going to set up a basic searching infrastructure on a *nix-based system.

This tutorial is going to show an easy and fast way to set up a Solr search infrastructure powered by Jetty on an Ubuntu 14 or a Debian 7 or a Red Hat Enterprise Linux 7 server. Jetty is a pure Java-based webserver and Java servlet container shipped with Solr, so you do not need to install any third party servlet containers.

Apache Solr needs Java Runtime Environment 1.7 or higher. Check your system:

java -version

If you don't have Java, you can install it from package,

  1. # RHEL
    
  2. sudo yum install java-1.7.0-openjdk
    
  3. # Debian/Ubuntu
    
  4. sudo add-apt-repository ppa:webupd8team/java
    
  5. sudo apt-get update
    
  6. sudo apt-get install oracle-java7-set-default
    

...restart the terminal or reload your configuration,

source ~/.profile or source ~/.bashrc

...and give Java a try:

echo $JAVA_HOME

If you get an empty message, just insert the following lines into the ~/.profile or ~/.bashrc:

  1. # RHEL
    
  2. JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre
    
  3. PATH=$PATH:$JAVA_HOME/bin
    
  4. export JAVA_HOME
    
  5. export PATH
    
  6. # Debian/Ubuntu
    
  7. JAVA_HOME=/usr/lib/jvm/java-7-oracle
    
  8. PATH=$PATH:$JAVA_HOME/bin
    
  9. export JAVA_HOME
    
  10. export PATH
    

If you can not find Java's home folder, try locating it with

readlink -f "$( which java )"

...and on Debian/Ubuntu install the daemon package for the Solr service:

  1. # Just on Debian/Ubuntu
    
  2. sudo apt-get install daemon
    

After these prerequisites are installed, it's time to install and configure Apache Solr. The archives can be found here with all versions of Solrs: http://archive.apache.org/dist/lucene/solr/. I recommend using 4.3.1 or a higher version on a Drupal 7 site. First download and decompress Solr:

  1. wget https://archive.apache.org/dist/lucene/solr/4.3.1/solr-4.3.1.tgz
    
  2. tar -xzf solr-4.3.1.tgz -C /home/drupal/solr431
    

In case you are as lazy as I am, you will also need a service which can be easily managed like any other (httpd, mysql, memcached etc.) on your system.

On RHEL7, download the Jetty service startup script,
  1. sudo curl -o /etc/init.d/solr http://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk/jetty-distribution/src/main/resources/bin/jetty.sh
    
  2. sudo chmod 0755 /etc/init.d/solr
    

...change references from Jetty configuration to Solr,

sudo perl -pi -e 's/\/default\/jetty/\/sysconfig\/solr/g' /etc/init.d/solr

...set up variables by inserting the lines below (if you previously did not set JAVA_HOME, uncomment the first line in your configuration),

  1. sudo vi /etc/sysconfig/solr
    
  2. # JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.71-2.5.3.1.el7_0.x86_64/jre/bin
    
  3. JAVA_OPTIONS="-Djetty.port=8984 -Dsolr.solr.home=/home/drupal/solr431/example/multicore $JAVA_OPTIONS" 
    
  4. JETTY_HOME=/home/drupal/solr431/example
    
  5. JETTY_USER=drupal
    
  6. JETTY_LOGS=/var/log/solr
    

...and eventually enable the Solr service:

sudo chkconfig solr on

On Debian/Ubuntu, get the Jetty service startup script,
  1. sudo curl -o /etc/init.d/solr http://cheppers.com/sites/default/files/attachments/solr.sh
    
  2. sudo chmod 0755 /etc/init.d/solr
    

...edit the below part of our script that has just been downloaded (set up the install folder, the port and Solr home):

  1. start () {
    
  2.     echo -n "Starting solr..."
    
  3.  
    
  4. # Start the daemon
    
  5.     daemon --chdir='/home/drupal/solr431/example' --command "/usr/bin/java -Djetty.port=8984 -Dsolr.solr.home=multicore -jar start.jar" --respawn --output=/var/log/solr/solr.log --name=solr --verbose
    
  6.  
    
  7.  
    
  8.     RETVAL=$?
    

...and enable the Solr service (if we reboot our system, it will start automatically):

sudo update-rc.d solr defaults

Now with your last command you are going to start the service that you can easily manage with the well-known commands, and after from the admin page: http://yoursite.com:8984/solr

sudo service solr start

Because we want to use the Solr with Drupal, copy the Solr configuration files from Search API Solr Search module into your core:

  1. cp -Rf /your/drupal/site/folder/sites/all/modules/contrib/search_api_solr/solr-conf/4.x/* /home/drupal/solr431/solr/example/multicore/core0/conf/
    
  2. sudo service solr restart
    

And that's all folks!

If you need any other Solr cores (for example you have several staging sites which needs different cores), you can copy an existing core into a new folder next to it, configure your Solr to load the core when Solr (re)starts and set up the new one on the admin page:

  1. cp -R /home/drupal/solr431/example/multicore/core0/ /home/drupal/solr431/example/multicore/othercore/
    
  2. vi /home/drupal/solr431/example/multicore/solr.xml
    

Add a new line at the bottom:

core name="othercore" instanceDir="othercore" />

And add a new core:

If you need different Solr services on your server (one for your development sites, one for your production sites etc.), just copy the Solr and the init script, set up a new home folder and a new port in the config and start it as well:

  1. cp -R /home/drupal/solr431/ /home/drupal/solr431_live/
    
  2. sudo cp /etc/init.d/solr /etc/init.d/solr_live
    
  3. # Edit the config file (on Ubuntu/Debian the init script, on RHEL the also copied /etc/sysconfig/solr_live configuration file)
    
  4. sudo update-rc.d solr_live defaults
    
  5. sudo service solr_live start
    

Sources:

In our next blog post one of my colleagues will show you how you can set up Solr to search in uploaded files as well, so don't forget to check back later!

Dec 15 2014
Dec 15

Many people know that addressfield hasn’t been the easiest module to maintain. There are over 200 countries in the world, each with its own addressing requirements. Addressfield attempted to provide a sane default for all of them, along with a plugin architecture for handling per-country customizations. But with so many countries, the list of needed improvements became never-ending, and the customizations themselves started gathering in only one plugin (address.inc), which quickly became impossible to maintain.

A radical change was needed, so after a lot of research we introduced a new plan for Drupal 8, along with a brand new PHP library we can depend on from addressfield 8.x-2.x. The new plan resolves around two powerful ideas:

  • The introduction of address formats, which hold information on how a country’s address and its form need to be rendered and validated.
  • The use of Google’s addressing dataset, freely available and built for Chrome and Android, with address formats for 200 countries.

The introduced solutions were obviously superior to anything we had before that, but Drupal 8 is still far from production, and we needed improvements on our Drupal 7 sites today, so we decided to try and backport as many concepts as we could into the 7.x-1.x codebase. The result of that is addressfield 7.x-1.0-rc1:

  • Created the concept of an address format.
    An address format is an array which contains the per-country list of used fields, list of required fields, and the field labels.
    Imported address formats for 200 countries, derived from Google’s dataset.
  • Moved administrative areas out of address.inc, into their own include file (addressfield.administrative_areas.inc), added an alter hook.
  • Added administrative areas for 20 countries:
    Argentina, Chile, China, Colombia, Egypt, Hong Kong, India, Indonesia, Ireland, Jamaica, Japan, Malaysia, Mexico, Peru, Russia, South Korea, Spain, Turkey, United Arab Emirates, Venezuela.
  • The field can now be optional.
  • Added plugins for hiding the street address and/or the postal code.

For the first time we know precisely which fields we need, and which labels they should have. We also know which fields are required, instead of just requiring them all, which is a relief to citizens of 130 countries with optional postal codes, for example. Our contributors from all over the world (Russia, China, Australia, others) have already confirmed the big improvements. The best part is, these 50 commits did not result in a single backwards compatibility break.

What’s left? These improvements are still exclusive to the Drupal 8 version:

  1. A “format” string for each address format, showing the exact layout of the fields. The D7 version already has most of this data, derived from Google’s dataset, but it is not as precise.
  2. A more complete list of administrative areas (some still haven’t been imported).
  3. Postal code validation
  4. Predefined localities for Brazil and Chile, localities and dependent localities for China/Taiwan/South Korea.
  5. Switching between major-to-minor and minor-to-major field orderings for China/Japan/South Korea.

The good news is that 1-3 are also backportable, so the community could make it happen.

Please update to 7.x-1.0-rc1 and help us find any remaining issues, so that we can tag 1.0 in the near future.

Dec 15 2014
Dec 15

In the first part of this series, “Scalable & Sustainable Media Management for Drupal Websites”, I talked about media management solutions for Drupal. Specifically, I am interested in managing large amounts of files in a reusable manner. The solution I like best at the moment is Scald.

Just so we don't get confused with some phrasing, Scald stores all media items as custom entities called "atoms"; Scald "contexts" are very similar to view modes.

Setting up and configuring Scald for Drupal takes work and planning. However, if you've ever used the node reference or entity reference modules, you'll catch on very quickly.

Scald comes with a number of sub-modules. To get it working you will first need to install:

  • Scald core – the basic engine to drive the rest

  • Atom reference – a field type to reference (display) media on your page (like entity reference module)

  • DnD Library – so you can drag files from the media library and drop them on your page

  • MEE – if you want users to be able to define metadata on media embedded in textareas (such as copyright information)

These modules will get Scald working, but you'll need to add in some providers (other sub-modules) to define how you get your media assets to your page. Here's what I like:

  • Scald Audio – allows you to upload audio files

  • Scald SoundCloud – allows a SoundCloud URL to be an audio asset

  • Scald File – allows files to be media assets

  • Scald Image – allows image files to be media assets

  • Scald YouTube – allows a YouTube URL to be a video asset

  • Scald Vimeo – allows a Vimeo URL to be a video asset

There is a full list of "Scald providers" here, so you can extend it to include Facebook, Instagram, Pinterest, Twitter, Flickr, Vine, DailyMotion, and more ... up to and including Drupal Commerce products as atoms!

With this many modules installed (I know, it's a lot), you are ready to use Scald. This is what you will need to do:

  1. Add an “Atom reference” field to a content type

  2. Select what atom types can be referenced by this field, for example video, audio, image

  3. Set the representation of the atom on the edit page (this is how the atom will look when you are creating or editing pages with atoms displayed)

  4. Create a node and add an atom to it, like so:

    1. Click on one of the icons in the sidebar slider for the type of atom you want, for example image

      1. Use the file select UI to choose what image you want to upload

      2. Give the image a title (you will be able to use this when searching for it in future)

      3. Add an author or authors (you will be able to find images by author later on)

      4. Add some tags (as above, you will be able to filter images by tag)

      5. Click on the sidebar slider's menu button and a list of all your atoms will show up

      6. Drag and drop the atom you want onto the “dropbox”

    2. Or, you can search for an find an atom that has already been uploaded by clicking on the little circle button on the top of the sidebar

      1. This will bring up the exposed filters which you can use to filter your atoms

      2. As it is views powered, you can configure this any way you want

      3. Drag and drop the atom you want onto the “dropbox” 

Scald media library for Drupal

This will give you basic functionality, but the media being displayed is probably not as you want it just yet – more than likely it will only be displaying the title of the file. To change this you will need to go to your “Manage Display” settings and select a different display format; set it to editor representation or preview representation, then go back and refresh your page, and things should look better.

These “representations” that I mentioned are called “contexts” in Scald. You can think of them as view modes for other entities. So, it's quite similar to using entity reference fields, in that you reference the entity of the edit page, and then set what view mode (or context in this case) you want to use to display it.

If you go to the Scald configuration page (admin/structure/scald) you can see how each atom type is going to get displayed for each view mode that it is used on, but also for each context selected. This makes it a bit like a view mode inside a view mode, which makes it very configurable and customisable. And, you can create your own custom contexts here (I suggest you do). Creating your own contexts allows you to have different display types for different atom types on different view modes (you might have meta data, authors, publishers, etc showing on backend views, the atom with a thumbnail preview on teasers, and the atom with a large image preset on full nodes).

Scald drupal media management configuration page

Once you are that far, you can then create features of all of our Scald items to store them in configuration and export them to your test and production servers. You can also, then, reuse them on other sites.

So, that's a basic run through how to install, set up, and configure Scald to manage large amounts of media in Drupal websites. If you need some help to get up to speed with all of this, get in contact by clicking the button below.

Get me up to speed

Dec 15 2014
Dec 15

In the spirit of the computer video game Doom and its skill levels, we’ll review a few ways you can improve  your Drupal speed performance     and optimize for better results and server response time. These tips that we’ll cover may be at times specific to Drupal 6 versions, although     you can always learn the best practices from these examples and apply them on your own code base.

Doom

Doom skill levels: (easiest first)

1. I’m too young to die

2. Hey, not too rough

3. Hurt me plenty

4. Ultra-violence

5. Nightmare!

  This post is rated “I’m too young too die” difficulty level.

Drupal 6 shipped with all tables being MyISAM, and then Drupal 7 changed all that and shipped with all of its tables using the InnoDB database engine. Each one with its own strengths and weaknesses but it’s quite clear that InnoDB will probably perform better for your Drupal site (though it has quite a bit of fine tuning configuration to be tweaked on my.cnf).

Some modules, whether on Drupal 6, or those on Drupal 7 that simply upgraded but didn’t quite review all of their code, might ship with queries like SELECT COUNT() which if you have migrated your tables to InnoDB (or simply using Drupal 7) then this will hinder on database performance. That’s mainly because InnoDB and MyISAM work differently, and where-as this proved as quite a fast responding query being executed on a MyISAM database which uses the main index to store this information, for InnoDB the situation is different and will result in doing a full table scan for the count. Obviously, on an InnoDB configuration running such queries on large tables will result in very poor performance

drupal_perf-5

Note to ponder upon – what about the Views module which uses similar type of COUNT() queries to create the pagination for its views?

Series Navigation
Dec 14 2014
Dec 14

Start: 

2014-12-17 (All day) America/New_York

Organizers: 

The monthly security release window for Drupal 6 and Drupal 7 core will take place on Wednesday, December 17.

This does not mean that a Drupal core security release will necessarily take place on that date for either the Drupal 6 or Drupal 7 branches, only that you should prepare to look out 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 release on this date; the next window for a Drupal core bug fix release is Wednesday, January 7.

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.

tvn
Dec 14 2014
Dec 14


As part of our mission to reinvent Drupal.org, we’ve been digging deep to understand who uses the website and how. At DrupalCon Austin, we began the process of discovering the personas of users who visit Drupal.org: to do so, we interviewed numerous Drupal.org users and asked questions about how frequently they use Drupal.org, how they use the website, their frustrations with Drupal.org, the things they enjoy about the site, and how we can make it easier for people to learn, use, and connect on Drupal.org.

Once we had that data, we set about looking for patterns and common themes. We built categories where we grouped people's similar experiences and frustrations together, and at the end of the process we had come up with five distinct personas that can apply to everyone who visits Drupal.org. These personas detail our users’ familiarity with Drupal software and Drupal community, how they use Drupal.org, how they contribute (or don’t), and more.

The five personas that we drew up are based on proficiency in Drupal and the Drupal ecosystem. They are:

  • Newcomer: This person has heard of Drupal, but has never built a Drupal site and doesn’t know where to start.
  • Learner: This person knows a bit about Drupal and the general Drupal ecosystem. He or she may have built a Drupal website, but likely has used only a few contrib modules and hasn’t made any customizations.
  • Skilled: This person understands and is fluent in Drupal-specific terminology, can build a Drupal website themselves using contributed modules, themes or distributions, or with the help of Drupal service providers. She or he has spent a decent amount of time working with Drupal, and is lightly engaged with the community, often not directly, via some sort of liaison.
  • Expert: This person has a deep understanding of Drupal and the Drupal ecosystem, knows how to build advanced websites with Drupal. Expert typically has been working with Drupal for at least a couple of years, is actively engaged with the community online and via local/national events, and actively contributes back in a variety of ways.
  • Master: This person has pervasive knowledge of Drupal and the Drupal ecosystem. He or she knows how to build Drupal websites of great complexity, is deeply engaged in the Drupal community, knows and has access to other Masters. Usually this person has been using Drupal and been around the Drupal community for a long time.

Proficiency-based personas are a new facet through which we can look at our community. It’s important to note that these personas are NOT only about developers. All kinds of roles can be on different levels of this ladder — UX designers, project managers, and business owners can be Experts and Masters, just like developers and themers. Simultaneously, people can have different backgrounds and be experts in other areas, but when it comes to fluency in Drupal and Drupal ecosystem, they would be represented as Newcomers, or Learners, or any of the other personas.

How will we use personas?

User personas will guide feature prioritization and feature development for Drupal.org, as we improve the site to make it easier for our users to progress from Newcomers to Masters. There are a variety of different ways we can go about it, but since our resources are limited, we will focus on just a few critical areas that will have the biggest impact on the overall user experience. So, to start our work, we’ll be focused on removing barriers and helping our users move more easily from Learners to Skilled. We found that our users have great success moving from Newcomer to Learner today, whereas moving from Learner to Skilled is much more difficult, since so much of the project is focused on doing things “the Drupal way” and learning the processes. Our secondary focus will be on moving users from Skilled to Expert.

Growing our pool of Skilled users is crucial, because by doing so we grow the number of people who own and/or build websites using Drupal, thus grow Drupal adoption. On the path from Skilled to Expert is when our users begin to give back by contributing patches, writing documentation, building and sharing modules and themes, helping others in the issue queues, and bringing in their friends. By growing the number of Skilled and Expert users on Drupal.org, we’ll directly grow our community. It’s a win-win.

By growing Drupal adoption and growing our community, we directly support our mission and goals as an organization (you can read more about those in our 2015 Leadership plan and budget), and that’s why improving Drupal.org is one of our organizational imperatives in the coming year. The 2015 Drupal.org roadmap outlines the numerous ways we’re planning to do it.

As we use personas in our work, you may hear us refer to our “Primary” (Learner and Skilled), “Secondary” (Expert), and “Tertiary” (Master and Newcomer) personas — these distinctions correspond to the order of conversions we look to make easier, not to the users’ importance. Every Drupal.org user is important to us!

As we modify Drupal.org, we’ll be using the personas to help us make the experience for the whole community better. After all, that’s what these personas are — a representation of the entire Drupal community. To help bring our personas to life, we talked to five different community members, each representing one user persona. Over the next few days we’ll share the stories of each person’s unique Drupal journey so that we can see how they got to where they are now. We’d like to say a big thank you to each of our volunteers for sharing their personal stories — as always, they’ve reminded us how fantastic our community really is.

At the end of the series, we’ll close it all off with interviews with several prominent community members who will share their views on how personas can be used outside of Drupal.org development.

We enjoyed working on the user research project and are excited to share user personas with the Drupal community. As a reminder, you can view and download the full report. Take them, use them, go out and make great things!

Pages