Drupal Planet Posts

Drupal update hooks with multiple passes

If you do a lot of Drupal development and need to deploy configuration I am sure that you are using update hooks to some extent at least. If you don't use Features and want to create a taxonomy vocabulary or something in code, the hook_update_N() hook is the way to go.

But have you ever needed to perform an update the size of which would exceed PHP's maximum execution time? If you need to create 1000 entities (let's just say as an example), it's not a good idea to trust that the production server will not max out and leave you hanging in the middle of a deploy. So what's the solution?

You can use the batch capability of the update hook. If you were wondering what the &$sandbox argument is for, it's just for that. You use it for two things mainly:

  • store data required for your operations across multiple passes (since it is passed by reference the values remain)
  • tell Drupal when it should stop the process by setting the $sandbox['#finished'] value to 1.

Let me show you how this works. Let's say we want to create a vocabulary and a bunch of taxonomy terms with names from a big array. We want to break this array into chunks and create the terms one chunk at the time so as to avoid the load on the server.

So here is how you do it:

/**
 * Create all the terms
 */
function my_module_update_7001(&$sandbox) {

  $names = array(
    'Fiona',
    'Jesse',
    'Michael',
    ...
    'Sam',
    'Nate',
  );

  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['limit'] = 5;
    $sandbox['max'] = count($names);

    // Create the vocabulary
    $vocab = (object) array(
      'name' => 'Names',
      'description' => 'My name vocabulary.',
      'machine_name' => 'names_vocabulary',
    );

    taxonomy_vocabulary_save($vocab);
    $sandbox['vocab'] = taxonomy_vocabulary_machine_name_load('names_vocabulary');
  }

  // Create the terms
  $chunk = array_slice($names, $sandbox['progress'], $sandbox['limit']);
  if (!empty($chunk)) {
    foreach ($chunk as $key => $name) {
      $term = (object) array(
        'name' => $name,
        'description' => 'The name is: ' . $name,
        'vid' => $sandbox['vocab']->vid,
      );

      taxonomy_term_save($term);
      $sandbox['progress']++;
    }
  }

  $sandbox['#finished'] = ($sandbox['progress'] / $sandbox['max']);


}

So what happens here? First, we are dealing with an array of names (can anybody recognise them by the way?) Then we basically see if we are at the first pass by checking if we had set already the progress key in $sandbox. If we are at the first pass, we set some defaults: a limit of 5 terms per pass out of a total of count($names). Additionally, we create the vocabulary and store it as a loaded object in the sandbox as well (because we need its id for creating the terms).

Then, regardless of the pass we are on, we take a chunk out of the names always offset by the progress of the operation. And with each term created, we increment this progress by one (so with each chunk, the progress increases by 5) and of course create the terms. At the very end, we keep setting the value of $sandbox['#finished'] to the ratio of progress per total. Meaning that with each pass, this value increases from an original of 0 to a maximum of 1 (at which point Drupal knows it needs to stop calling the hook).

And like this, we save a bunch of terms without worrying that PHP will time out or the server will be overloaded. Drupal will keep calling the hook as many times as needed. And depending on the operation, you can set your own sensible chunk sizes.

Hope this helps.

How to remove all the Voting API results for a given node type

Have you ever needed to remove in bulk a bunch of voting results for, let's say, a given content type? There is no option in the UI but you can find in the votingapi.module some handy functions that will allow you to write a customized update hook.

So let's say that we need to remove all the results for the article content type. If we look in the votingapi_vote table, we don't see any bundle or content type column, but we see an entity_id. So we need to get all the ids of our article nodes:

  $query = db_query("SELECT nid FROM node WHERE type = 'article'");
  foreach ($query as $res) {
    $nids[] = $res->nid;
  }

Now we have the $nids array containing all of our node IDs. Next, let's load all the votes for these IDs:

  module_load_include('module', 'votingapi', 'votingapi.module');

  $votes = votingapi_select_votes(array('entity_id' => $nids));

First we include the right module file and then we use one of its functions to select all the votes that match some criteria (in our case an array of IDs). Next, we need to worry also about the votingapi_cache table which contains the results of the voting per entity. We need to remove that as well. So we'll use another helper function from Voting API:

$results = votingapi_select_results(array('entity_id' => $nids));

Now we have also the result objects we need to delete so we can proceed with the actual removal. For this, we can use two more handy methods from the Voting API module:

votingapi_delete_votes($votes);
votingapi_delete_results($results);

And that's it. This will remove all the votes and their aggregated results from both tables. It may take some time so make sure you have enough server resources to perform this task.

To use this code, I recommend creating an update hook in a custom module that you run once. But make sure you properly test it on your test environment before deploying and running the code on production servers. Always keep in mind the possibility of the server running out of resources depending on how many votes you have in the database.

Do you have any better way of batch deleting votes/results? This is what I found and I'm curious if you know of any better ways. Let me know.

PHP: Using the usort / uasort functions

Have you ever had to sort an array in PHP? There are a bunch of functions available, the most common being sort(). This function does a default sorting of the values in your array. So if you have numbers or want to do alphabetical sorting, sort() will get the job done.

But what if you require a more complex sorting logic? Let's say you have an array of names that need to be sorted in a specific order. I don't know, because your client says so. Let me show you how.

Let's say your DB returns a list of names in an array:

$names = array("Christian", "Daniel", "Adrian");

And your client says they need to be arranged in the following order: Adrian, Christian, Daniel. You can use the usort() function together with a comparator function you write yourself. How does this system work?

As a second argument of the usort() function, we pass in the name of our custom comparator function. The way this gets processed is that all the values in the array that needs sorting are passed to this function 2 at the time (usually you'll see them as $a and $b). This is done to determine which one takes precedence over which. The comparator has to return 0 if the 2 values are considered equal, a negative integer if the first value is less than the second value or a positive integer if the second value is less than the first. What less means is up to you to determine. So let's put this in practice with our example:

function _name_comparer($a, $b) {
    $correct_order = array("Adrian", "Christian", "Daniel");

    $a_key = array_search($a, $correct_order);
    $b_key = array_search($b, $correct_order);

    if ($a_key == $b_key) {
        return 0;
    }

    return ($a_key < $b_key) ? -1 : 1;
}

usort($names, "_name_comparer");

So what happens in my comparator function? First, I create an array that contains the proper order of the names. This means that each value has an integer key that can be easily compared (and that I store in the $a_key and $b_key variables). After comparing these, I return 0, a negative or positive integer. The result is that the $names array gets resorted in the order they appear in the $correct_order local variable I created. And that's it.

If the $names variable is associative and you need to maintain the keys as they were, you can use the uasort() function:

$names = array(
    "christian" => "Christian", 
    "daniel" => "Daniel", 
    "adrian" => "Adrian",
);
usort($names, "_name_comparer");

The comparator function can stay the same, but the uasort() function will take into account and maintain the index association of your values.

And that's it. Hope this helps.

Drupal 8 Dependency Injection, Service Container And All That Jazz

With the move from a mostly procedural to a mostly OOP based architecture in Drupal 8, many Drupal developers have been introduced to new concepts we don't fully understand. I myself was terrified of notions such as dependency injection and service container, making me worry about the future of my Drupal development.

So I took it to Symfony (from where many components have been borrowed) and then Drupal 8 alpha releases and turns out it's not a big deal. All you need in order to understand them is to know basic OOP principles. Check out Larry Garfield's timeless introductory article to Object Oriented Programming on Drupal Watchdog for a good start.

In this article I am going to talk a bit about what dependency injection is and why one would use a container for managing these dependencies. In Symfony and Drupal 8 this is called a service container (because we refer to these global objects as services). Then, we will take a look at how these are applied in Drupal 8. Briefly, because you don't need much to understand them.

So what is dependency injection?

Take the following simple class:

class Car {

  protected $engine;

  public function __construct() {
    $this->engine = new Engine();
  }

  /* ... */

}

When you instantiate a new class Car you go like this:

$car = new Car();

And now you have an object handler ($car) that has an $engine property containing the handler of another object. But what if this car class needs to work with another engine? You'd have to extend the class and overwrite its constructor for each new car with a different engine. Does that make sense? No.

Now consider the following:

class Car {

  protected $engine;

  public function __construct($engine) {
    $this->engine = $engine;
  }

  /* ... */

}

To instantiate an object of this class, you go like this:

$engine = new Engine();
$car = new Car($engine);

Much better. So now if you need to create another car using another engine, you can do so easily without caring about the Car class too much since it is supposedly equipped to work with all the engines in your application.

$turbo = new TurboEngine();
$car2 = new Car($turbo);

And that is dependency injection. The Car class depends on an engine to run (dooh), so we inject one into its constructor which then does what it needs to do. Rather than hardcoding the engine into the Car class which would not make the engine swappable. Such constructor injections are the most common but you'll also find other types such as the setter injection by which we would pass in the engine through a setter method.

So what is this container business?

So far we've seen a very simple class example. But imagine (rightfully) that the Car has many other potentially swappable components (dependencies), like a type of gear shift, breaks or wheels. You have to manually instantiate all these dependent objects just so you can pass them to the one you actually need. This is what the container is for, to do all that for you.

Basically it works like this. You first register with the container your classes and their dependencies. And then at various points of your application, you can access the container and request an instance of a particular class (or service as we call them in Symfony and Drupal 8). The container instantiates an object of that class as well as one of each of its dependencies, then returns you that service object. But what is the difference between services that we usually access through the container and other PHP classes?

A very good definition that makes this distinction comes from the Symfony book:

As a rule, a PHP object is a service if it is used globally in your application. A single Mailer service is used globally to send email messages whereas the many Message objects that it delivers are not services. Similarly, a Product object is not a service, but an object that persists Product objects to a database is a service.

Understanding how the container works under the hood is I believe not crucial for using it. It's enough to know how to register classes and how to access them later. There are multiple ways to register services but in Drupal 8 we use YAML files. In Symfony, you can use directly PHP, YAML or even XML. To know more about how to do this in Drupal 8, check out this documentation page. Accessing the services in Drupal 8, on the other hand, is done in one of two ways: statically and using, yet again, dependency injection.

Statically, it's very simple. We use the global \Drupal namespace to access its service() method that returns the service with the name we pass to it.

$service = \Drupal::service('my service');

This approach is mostly used for when we need a service in our .module files where we are still working with procedural code. If we are in a class (such as a form, controller, entity, etc), we should always inject the service as a dependency to the class. Since I covered it elsewhere and the Drupal documentation mentioned provides a good starting point, I won't go into the exact steps you need to take in order to inject dependent services into your Drupal 8 classes. However, you can check out my introductory series on Drupal 8 module development, on Sitepoint.com, where I covered the process of creating services and injecting them as dependencies (in the third part, published soon if not already).

Conclusion

So there you go. Dependency injection is a very simple concept that has to do with the practice of decoupling functionality between classes. By passing dependencies to objects we can isolate their purpose and easily swap them with others. Additionally, it make is much easier to unit test the classes individually by passing mock objects.

The service container is basically there to manage some classes when things get overwhelming. That is, when the number grows and the number of their dependencies also increases. It keeps track of what a certain service needs before getting instantiated, does it for you and all you have to do is access the container to request that service.

Hope its clear.

4 tools you should definitely use for Drupal development

Developing Drupal sites can be quite a challenge and adventure. And this comes from those who call themselves Drupal developers. Men and women of PHP who work with other frameworks and applications most likely find it even more cumbersome to understand. However, Drupal is fostered by a big community of enthusiastic people who love it, myself included. But in all honesty, the more you work with it, the more you develop this love/hate relationship with all the quirks of Drupal development.

But one thing is certain, and this is applicable to other areas of web development as well: the tools you use for the job can make a big difference in the experience you have. And Drupal makes no exception. I mean, remember when we were writing PHP in Notepad and that one missing semicolon added 2 hours of debugging that day?

In this article I would like to share with you 4 tools that I use for Drupal development. I heavily rely on them to minimise frustration, increase productivity and lower development time. And I can guarantee you that if you are serious about Drupal development and you are not using them, you are missing out. But if you are, kudos, do share some of your experiences that further demonstrate their power.

So here we are, I guess in order of complexity, the 4 tools in my belt when I run vagrant up to spin up a project on my local environment. I will say a few words about each, but I can't go into all of their features. That's for you to explore after I give you a taste of what they can offer.

Devel and Search Krumo modules

Devel is the most used Drupal development module built for aiding with debugging code, generating content and all sorts of other dev tasks. Search Krumo is yet another cool module that plugs into it in order to give us a hand with navigating through huge array structures. And if you know Drupal 7, it is all about big arrays.

These modules are probably the first solution for debugging variables in Drupal. Using Devel's dsm(), dpm(), and krumo() functions in your code you can print out arrays, objects and whatever you need for a great overview of what you have in scope at that moment of execution. And they are not the only ones...

Another great use for the Devel module is content generation. It has a series of submodules that can generate nodes, taxonomy terms, users and more. Sometimes you need 500 nodes on the site to test something out. Additionally, you can use it to execute PHP code in the Drupal environment, switch between users on the site and other awesome functionality. So it's a must have on any Drupal development environment.

Drush

Drush is an awesome command line tool for Drupal that speeds up many tasks. Some people call it the swiss army knife of Drupal and you can't really argue the opposite.

Drush allows you to perform a host of Drupal tasks from the command line. You can download and enable/disable/uninstall/update modules or Drupal core and all sorts of other helpful jobs. This great list of core commands can give you an overview of what you can do with Drush. And if you are looking for some help with setting Drush up on your server, you can read this article I wrote on the subject.

Another great thing about Drush is that aside from all the awesome core commands, you can declare your own. This way, you can expose some of your custom functionality to the command line. This goes behind development and can help with maintenance or even production jobs that need to run with cron. So it truly is versatile.

A good IDE like PHPStorm

I mentioned before the good ol' times (not really) when Notepad was the editor of choice for many developers. Luckily nowadays we don't have to suffer through that as we can use IDEs for coding. I myself use PHPStorm and is of great help.

An IDE can speed up your development time by preventing code mistakes, highlighting syntax for great readability, code hinting for classes and functions in your project and many others. And with Drupal, all of these are important. Since Drupal 7 is mostly procedural you need to be aware of many functions and parameters. The IDE great reduces the time you spend online researching these APIs. And not to mention the integrations you can create with these API documentation resources.

Another great use of IDEs (which for me is the most important) is debugging. Integrating PHPStorm with XDebug on my local server really changed things around. But more on that in the next point.

Xdebug

As great as the Devel module is for printing out variables to the screen, it does not come close to Xdebug when we talk about debugging. After setting it up, all you have to do is place a breakpoint in your code and load your site page. The execution stops at the breakpoint (that was hopefully supposed to be executed) and you have access to a wealth of contextual information. You get all the global and scope variables that you can navigate through, a great callstack of what functions/methods have been triggered so far and many others.

Another cool feature is that you can play forward the execution line by line and jump inside of to be called functions to see where the code is heading. This is great for debugging where your code fails, at which point does that exception get thrown, or why that variable is null. So I do recommend checking it out.

Conclusion

And there you have it: 4 tools you can start using today to make you Drupal development experience more efficient. Using Drush and the Devel module are really only specifically for Drupal, but the use of a good IDE and XDebug is applicable to all other PHP projects as well. And I can guarantee you they are all worth using.

How to use Drush Make in your daily routine

This is a guest post from Kate Marshalkina, a Russian Drupal developer who works for Licel LLC. Enjoy the read and check out some of her other work.

Drush Make is well-known as an advanced tool for Drupal distribution building. But it also can be very useful for those who have never dealt with distributions. One great example is applying patches like a boss.

In this article I’ll show you how I use Drush Make to automate some of my routine tasks and help me to discover great Drupal stuff.

Drush Make commands

Drush Make includes 2 commands which are already built in Drush itself:

  1. make — Turns a .makefile into a Drupal codebase.
  2. make-generate — Generates a .makefile from the current Drupal site.

Both commands are related to a .makefile — flat text file with Drush Make instructions. You can read more about .makefile syntax here.

But for now, let's go deeper and see Drush Make in action.

Rebuild your development environment

How often do you install a new and clean Drupal site for development, testing or demonstration purposes? Additionally to Drupal core, developers usually have a predefined list of favorite modules like Administration Menu, Views or something more special. With Drush Make you can automate this process greatly by combining all the projects you need into one file and lettting Drush Make build it for you.

Here is an example .makefile for a multilingual testing site:

; Drush Make API version.
api = 2
; Drupal core.
core = 7.x

;Common modules.
projects[admin_menu][subdir] = "contrib"
projects[ctools][subdir] = "contrib"
projects[token][subdir] = "contrib"
projects[views][subdir] = "contrib"

; Development modules.
projects[devel][subdir] = "development"

; Multilingual modules.
projects[fallback_language_negotation][subdir] = "contrib"
projects[variable][subdir] = "contrib"
projects[i18n][subdir] = "contrib"
projects[i18nviews][subdir] = "contrib"

; Load some translations.
translations[] = de
translations[] = ru

This file can be saved locally (in ~/.drush/make-files/d7_i18n.make for example) or hosted on a remote server like GitHub.

To use it, let’s run the make command to prepare our custom build on our server (in /var/www/drupal_test.local for example):

$ drush make d7_i18n.make /var/www/drupal_test.local

The first run can be quite long, but the next time Drush will take most of projects from its cache.

As a result, the latest Drupal core, contrib modules and translations from the .makefile will be downloaded and placed in appropriate folders. Now you can go to your site's URL and run the install.php or run the installation process directly with Drush:

$ drush si --db-url="mysql://user:password@localhost/databasename" --site-name="Drupal Multilingual"

Additionally, you can also generate a tarball from the .makefile with --tar option:

$ drush make d7_i18n.make drupal_multilingual --tar

Add to that a couple of features (based on Features module) and you’ll end up with your own distro.

Download dependencies

Have you ever noticed that some contrib modules provide .make or .make.example file? These usually contain a list of specific external libraries (like the jQuery Colorbox plugin for the Colorbox module). These file can be built inside existing Drupal codebases using the --no-core flag. As an example, let’s say you want to download the Chosen module:

$ drush dl chosen
Project chosen (7.x-2.0-beta4) downloaded to sites/all/modules/contrib/chosen.

$ drush make sites/all/modules/contrib/chosen/chosen.make.example --no-core
chosen downloaded from https://github.com/harvesthq/chosen/releases/download/v1.1.0/chosen_v1.1.0.zip

In this case, the proper jQuery plugin was downloaded and unzipped into the proper directory inside the libraries/ folder. Isn’t that handy?

Module developers, please, add a .make.example file into your Drupal.org projects if you are using any external libraries. Instead of building custom Drush commands like chosen-plugin, we can use Drush Make. Just compare 117 lines to 7.

Generate makefile from existing site

You can easily share a custom Drupal build with Drush Make. First run generate-makefile command from Drupal root to generate a skeleton:

$ drush generate-makefile drupal_custom_build.make

The generated file drupal_custom_build.make will contain instructions for all enabled projects with specific versions. If a project has .git folder, Drush Make will automatically set appropriate properties:

projects[redirect][type] = "module"
projects[redirect][download][type] = "git"
projects[redirect][download][url] = "http://git.drupal.org/project/redirect.git"
projects[redirect][download][branch] = "7.x-1.x"
projects[redirect][download][revision] = "0b7b8dc2d58cb277874d87c91c45f0a361e148f7"

This file still needs a quick manual review. For example, you can add patch references. In my project, 2 patches are applied to the Redirect module:

projects[redirect][patch][] = "https://drupal.org/files/issues/redirect-global-905914-145.patch"
projects[redirect][patch][] = "https://drupal.org/files/issues/redirect.circular-loops.1796596-146.patch"

The resulting .makefile may be very useful if you want to share your working environment with a colleague or to provide definitive info for troubleshooting.

Bonus! Explore Drupal world!

Finally, the Drush Make file itself is a good read for discovering new cool contrib projects. Check out well-tested Commerce Kickstart or OpenScholar .makefiles with plenty of interesting projects inside.

I hope this article will help you use Drush more widely, to automate some of your tasks or to even build your first distribution!

About the Author

Kate is a passionate web developer from Russia who fell in love with Drupal in 2011.

She cares about multilingual stuff, usability and performance.

 

Connect with Kate:
Twitter | drupal.org | Google +

New features for Block Inject

I've worked recently on some new features for my contrib module Block Inject and I thought I'd share with you what's new.

Based on some feature requests from the community, I've implemented two new things that make this module more flexible. They are available in the 7.x-1.2alpha5 release onwards.

Theming

First, the injected region is now wrapped in a <div> with some default classes on it for easy styling. I've also created an alter hook for this so you can add easily your own classes there depending on the $node object the region is injected in.

An example implementation of this hook:

function hook_block_inject_attributes_alter($attributes) {
  if ($attributes['node']->type == 'article') {
    $attributes['attributes']['class'][] = 'article-block-inject';
  }
}

The $attributes parameter is an array with two values: the node object and another attributes array that gets transformed into HTML attributes by the drupal_attributes() function.

Site building

The second new feature of the module is the possibility to specify default paragraph offsets for an inject region depending on some conditions related to the node body field.

For example, when creating the inject region you can set it so that the region gets injected 5 paragraphs lower than the middle if the total number of paragraphs is over 20. Or move the region higher by 2 paragraphs if the total number of paragraphs equals 6.

Feel free to check it out and let me know what you think.

Sending HTML Emails with Webform in Drupal 7

Have you ever wondered how you can include HTML markup in the emails you send with Webform? Out of the box, you cannot. But I am going to show you a simple way to achieve this using the Mime Mail module and some simple theming. Additionally, I will show you how to control which webforms should send HTML emails and which should not.

First though, make sure you install and enable the Mime Mail and Mail System modules (the latter is a dependency of the former). With Drush, all you have to do is use this command:

drush en mimemail -y

It will take care of all you need to do. If you commit the module to your repo, don't forget that the Mail System module also gets downloaded, so make sure you include it as well.

Next, edit your theme's template.php file and paste this block of code (explained after):

function your_theme_webform_mail_headers($variables) {

  $headers = array();

  $headers = array(
    'Content-Type'  => 'text/html; charset=UTF-8; format=flowed; delsp=yes',
    'X-Mailer'      => 'Drupal Webform (PHP/'. phpversion() .')',
  );

  return $headers;

}

Make sure you change your_theme with the name of your theme. So what happens here? We override the theme_webform_mail_headers() declared by the Webform module. We do this in order to add a content type to the mail headers, and set it to HTML. And that's pretty much it.

If you now clear your caches and test a webform, you'll see that you can add anchor tags and other basic HTML tags.

One problem you might run into though is that all your webforms are now sending emails in HTML format - a result only partially desired. You'll notice that the default email that you send no longer provides any spacing and all the text gets put on one line - as HTML in fact.

So what you can do is make a selection of webforms for which you'll want HTML emails. A handy way of doing this is by adding a field to your webform content type that will be used to swith HTML emails on/off for a given node. So to illustrate this, let's say we added a new field to the relevant content type called HTML Emails (with the machine name: field_html_email). This field is a boolean type (a single checkbox basically) with the values of 1 for on and 0 for off.

It follows to adapt the theme override above and replace it with something like this:

function your_theme_webform_mail_headers($variables) {

  $headers = array(
    'X-Mailer' => 'Drupal Webform (PHP/' . phpversion() . ')',
  );

  // Get the HTML Email field
  $html_email_field = field_get_items('node', $variables['node'], 'field_html_email');

  // Check if this webform node needs to send HTML emails
  if (!empty($html_email_field)) {
    $html = $html_email_field[0]['value'] == 1 ? TRUE : FALSE;
  }

  if ($html === TRUE) {
    $headers['Content-Type'] = 'text/html; charset=UTF-8; format=flowed; delsp=yes';
  }

  return $headers;
} 

If you consult the documentation for this theme function, you'll know that the $variables parameter contains also the node object which uses Webform to send the email. So we basically check for the value of our field and if it is 1, we add the HTML information to the mail headers. Otherwise, we return the $headers array containing the value it does by default (essentially making no changes).

You can now clear the caches and test it out. Edit a node of the respective content type and check the box. You'll see that it now sends HTML emails. However, if you uncheck the box, it will fallback to the default format that comes with the Webform module.

Hope this helps.

3 ways to prompt for user input in Drush

Drush is awesome. It makes Drupal development much easier. Not only that it comes already packed with a bunch of useful commands, but you can declare your own with great ease. So if you need to call some of your module's functionality from Drush, all you have to do is declare a simple command that integrates with it.

In this tutorial I am going to show you how to get user feeback for such a command. I do not refer to arguments or options in this case. But how you can ask for confirmation on whether or not the command should proceed as requested and how you can ask for a choice. Additionally we'll quickly look at how to get free text back from the user.

So let's dive in with an example command callback function called drush_module_name_example_command():

/**
 * Callback function for the example command
 */
function drush_module_name_example_command() {
  // Command code we will look at
  drush_print('Hello world!');
}

Confirmation

The first thing we'll look at is how to get the user to confirm the action. So in our case, we'll ask the user if they really want this string to be printed to the screen. Drush provides a great API for this:

if (drush_confirm('Are you sure you want \'Hello world\' printed to the screen?')) {
  drush_print('Hello world!');
}
else {
  drush_user_abort();
}

You'll notice 2 new functions. The drush_confirm() function prints a question to the screen with the intent of getting one of two answers back form the user: y or n. If the response is y, the function returns true which means our print statement proceeds. If the answer is n, the drush_user_abort() function gets called instead. This is the recommended way to stop executing a Drush command.

Select option

Now let's see how you can make the user choose an option from a list you provide. For our super Hello world use case, we will give the user the choice to select from a list who Drush should say hello to. It can be implemented like this:

$options = array(
 'world' => 'World',
 'univers' => 'Univers',
 'planet' => 'Planet',
);

$choice = drush_choice($options, dt('Who do you want to say hello to?'));

if ($choice) {
  drush_print(dt('Hello @choice!', array('@choice' => $options[$choice])));
}

So what happens above? First, we create an array to store the choices called $options. The array keys are the machine name and the values are the human friendly versions. Then, we call the drush_choice() function to which we pass 2 arguments: the $options array and the question we ask from the user.

When the command is run, this function is called and returns the machine name of the option the users chooses. Then we check if this value exists and print to the screen the concatenated string. We do use the human readable value by extracting it from the $options array using the key returned.

Free text values

A third type of user input is in the form of free text that you can ask the user to input. Of course the validation of this kind of input must be much stricter so as to not break your application somehow. But let's ask our user exactly who they want to say hello to.

$value = drush_prompt(dt('Who do you want to say hello to?'));

drush_print(dt('Hello @value!', array('@value' =>  $value)));

This one is very simple. When the command is run, the drush_prompt() function is called to which we pass a string of text to be displayed in the terminal. The return value is given by the user and we use that for concatenation. But do remember that this is example code only so if you do use this function, make sure you validate the user input properly.

Conclusion

So there you have it. Three different ways to get user input in the terminal using Drush. The first two are the most common ones I believe but it's good to know there is also the last one available in case we need it.

Drush safely!

Adding Facebook Open Graph tags to your Drupal site

In this article we are going to look at implementing the Facebook Open Graph (OG) tags on a Drupal site. It involves a bit of coding but nothing too major so bear with me. All the code we are going to write goes into the theme's template.php file so no need to to create a module for it. And if your theme does not yet have this file, go ahead and create it.

The purpose of this article is to demonstrate doing this in code (because its fun and you might need it depending on the logic you need to perform). Alternatively, of course, you can use the Metatag module for this.

Why use Open Graph tags?

I'm sure by now you know that people share pages on Facebook and you want your site to be shared as much as possible. You also know that a little teaser information is made available on Facebook when you share these pages (title, image, short description).

But have you ever noticed that with some sites, when you share pages on Facebook, or like/recommend them, some random, unintented image gets used in this teaser. Or the description is not correct, or even the title is not right. Facebook is quite good at picking the right elements to show there but sometimes it doesn't manage by default. And you can't expect the random user who shares your page to make adjustments to the text or title. So what do you do? You use Open Graph meta tags.

What are the Open Graph meta tags?

These are simple <meta> tags that you put in the head of your site to specify which elements should be used by Facebook for various purposes. For instance, you specify a link to an image and then Facebook knows exactly which image to use when building the teasers. The same goes with the title, description and many others.

The tag is quite simply structured. It contains a property attribute in which you specify what this tag is for and a content attribute where you specify what should be used for this property. Let's see an example for the title:

<meta property="og:title" content="This is the article title" />

Simple. You'll also notice that the property attribute value is preceeded by og:. This stands for Open Graph and Facebook will recognize it as such. Here are some examples for other more common OG tags:

<meta property="og:url" content="http://webomelette.com/article-url" />
<meta property="og:site_name" content="Web Omelette" />
<meta property="og:type" content="blog" />

The first one is the canonical URL for the page, the second is the site title and the third is the type of site.

But how do we add them to Drupal?

I wrote a while back an article on this site in which I looked at how you can add your own custom tags into the <head> of the site. And there we learned that we use the drupal_add_html_head() function inside of a preprocess one to achieve this.

So let's say that our Article nodes don't show up properly in the Facebook teasers and we would like to specify OG tags for the title, image and description. We will do this in the theme's template.php file inside of the template_preprocess_node() function:

function theme_name_preprocess_node(&$vars) {

}

Inside this function we get access to the node information being loaded and we can test to make sure we are adding our OG tags only to the pages that load these nodes:

// If the node is of type "article", add the OG tags
if ($vars['type'] == 'article') {
  // Inside this conditional, we define and add our OG tags
}

First, let's create the title tag, the simplest of them all. It will be represented by the node title:

$og_title = array(
  '#tag' => 'meta',
  '#attributes' => array(
    'property' => 'og:title',
    'content' => $vars['title'],
  ),
);

drupal_add_html_head($og_title, 'og_title');

If you remember from the other article, this is how we create a new meta tag in the site header. We define a renderable array that describes the tag (type and attributes) and we use the drupal_add_html_head() function to set it. Simple. Now if you clear the cache and go to an article page you'll notice in its source a new tag:

<meta property="og:title" content="The title of the article" />

This was simple. Let's see how we can extract the image URL and specify it inside a new tag for the image Facebook will use:

$img = field_get_items('node', $vars['node'], 'field_image');
$img_url = file_create_url($img[0]['uri']);

$og_image = array(
  '#tag' => 'meta',
  '#attributes' => array(
    'property' => 'og:image',
    'content' => $img_url,
  ),
);

drupal_add_html_head($og_image, 'og_image');

So what happens here? First, we use the field_get_items() function to retrieve the field called field_image from the loaded node. This will return an array of one or more images (depending on how the field is set up and how many images are in it).

Next, we use the image file URI inside the file_create_url() function to turn it into an absolute URL. Then, just like above, we create the renderable array with the og:image property and the image URL as the content. The result will be:

<meta property="og:image" content="http://your-site.com/sites/all/files/your-image.jpg" />

Finally, let's see how we can get a small chunk of our body field and use that as a description for Facebook:

$body_field  = field_view_field('node', $vars['node'], 'body', array('type' => 'text_plain'));

$og_description = array(
 '#tag' => 'meta',
 '#attributes' => array(
   'property' => 'og:description',
   'content' => text_summary($body_field[0]['#markup']),
 ),
);

drupal_add_html_head($og_description, 'og_description');    

Instead of using the same function as when we retrieved the image field earlier, we use field_view_field() in this case. The reason is that it already prepares the body for output and we can specify a text format to use. We want to use plain text to avoid printing all the HTML markup that is usually found in the body field.

Next, like above, we create our renderable array. Only this time, we also use the text_summary() function to trim the text down to a reasonable default of 600 words (the defaul teaser length on the site). If you want to specify a different length, you could pass it as the third argument, like so:

text_summary($body_field[0]['#markup'], NULL, 100),

This will trim it to 100 words. One thing I noticed about this function however is that it doesn't trim nicely. It will end the chunk in the middle of the sentence even if its API says it will try to find a sensible place. For this purpose it doesn't really matter because Facebook will trim it down anyway to a shorter version.

Conclusion

So there you have it. Now you can use the Open Graph meta tags on your Drupal site to let Facebook know about your content. It's a handy social helper that can greatly improve your social presence by making your site more appealing on Facebook.