Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough

Drupal 8 Entity Validation and Typed Data Demonstration

Mar 31 2016
Mar 31

Theming Views in Drupal 8 – Custom Style Plugins

Mar 23 2016
Mar 23
Jun 10 2015
Jun 10

One of the things that makes Drupal great is its flexible user permission system. The out of the box permissions grid we are all familiar with covers most uses cases of controlling what users can and cannot do. It is also very easy for module developers to create new permissions and roles that restrict the logic they implement.

Drupal logo

Nevertheless, I have encountered a practical use case where the default configuration options are not enough. Namely, if you need to have multiple users with access to edit a particular node of a given type but without them necessarily having access to edit others of the same type. In other words, the next great article should be editable by Laura and Glenn but not by their colleagues. However, out of the box, users of a particular role can be masters either of their own content or of all content of a certain type. So this is not immediately possible.

In this article I am going to show you my solution to this problem in the form of a simple custom module called editor_list. Article nodes will have a field where you can select users and only these users (or those who have full access) will be able to edit that particular node. You can find the module already in this git repository and you can install it on your site for a quick start. Do keep in mind that it has a dependency on the Entity Reference module as we will see in a minute.

I will keep the code comments to a minimum to save space but you can find them in the repository if you want. Basic knowledge of Drupal 7 is assumed in the remainder of this tutorial.


We first need the editor_list.info file for our module to get us going:

name = Editor List
description = Module illustrating a custom solution for having multiple editors on a node.
core = 7.x
dependencies[] = entityreference

Next, we need our editor_list.module file where most of our business logic will be located. So go ahead and create it and we will populate it as we go on.

Finally, though not covered here, we can have an editor_list.install file where we can implement hook_install() and hook_update hooks to create fields and/or deploy configuration. In the repository, you’ll find that I provided an install hook that already creates an entity reference field called field_editors and attaches it to the Article content type. If you are following along but not using the code in the repository, you should go ahead and create the field manually through the UI. It’s a simple field that references User entities and allows for unlimited selections. Nothing major.

Node access

Going back to our .module file, it’s time to implement our access logic. First though, to make things as flexible and reusable as possible, let’s have a simple function that returns an array of node types to which we apply our access logic:

function editor_list_node_types() {
  return array('article');

Since we are only targeting articles, this will suffice. But we will use this function in multiple places so in case we need to target other types as well, we just have to update this array.

Next, let’s write another helpful function that returns all the user IDs set in the editors field of a given node. We will also use this in multiple places:

function editor_list_uids_from_list($node) {
  $users = field_get_items('node', $node, 'field_editors');

  $allowed_uids = array();
  if ($users) {
    $allowed_uids = array_map(function($user) {
      return $user['target_id'];
    }, $users);

  return $allowed_uids;

I believe the function is quite self explanatory so I won’t go into details here. Instead, we can turn to our hook_node_access() implementation that gets called by Drupal whenever a user tries to do something with a node (view, edit or delete):

 * Implements hook_node_access().
function editor_list_node_access($node, $op, $account) {
  $node_types = editor_list_node_types();

  if ( ! is_object($node) || ! in_array($node->type, $node_types) || $op !== 'update') {

  $allowed_uids = editor_list_uids_from_list($node);

  if (empty($allowed_uids)) {

  if (in_array($account->uid, $allowed_uids)) {

So what’s happening here?

First, we use our previously declared helper function to get the list of node types we want to target, and we basically ignore the situation and return if the node type of the currently accessed node is not within our list or if the operation the user is attempting is not of the type “update”. Then we use our other helper function to check if there are any users in the editor list for this node and again ignore the situation if there aren’t. However, if there are, and our accessing user is among them, we return the NODE_ACCESS_ALLOW constant which basically gives the user access to perform the attempted operation. And that’s it.

You can check out the documentation for more information about how this hook works.

Let’s say you have admin users who can create and edit any type of content and regular authenticated users who cannot edit articles (apart from maybe the ones they created themselves). Adding one of these latter users to a node’s editor list would give them access to that particular node. And another great thing is that since this is all nicely integrated, contextual filters and tabs also take these dynamic permissions into account.

Field access

We now have a working module that does what I initially set out for it to do. But let’s say that your admin users are the only ones responsible for adding users to the editor lists. In other words, you are afraid that if your editors can edit their nodes and remove themselves from the list, they’ll get locked out of the node they are supposed to work on.

To account for this situation, we need to implement a field access check and remove the possibility that editors tamper with that field. Implementing hook_field_access should do the trick nicely. And if you are wondering, this hook is similar to hook_node_access() but is responsible for individual fields rather than the entire node (+ a couple of other small differences).

 * Implements hook_field_access().
function editor_list_field_access($op, $field, $entity_type, $entity, $account) {
  $node_types = editor_list_node_types();
  if ($entity_type === 'node' && is_object($entity) && in_array($entity->type, $node_types)) {
    return editor_list_control_field_access($op, $field, $entity_type, $entity, $account);

And here we have it. There are a few more parameters because this hook gets called for all entities, not just nodes. But again, we check if the currently accessed node is one of those we defined earlier (and that the entity is in fact a node) and this time delegate to another function to keep things tidier:

function editor_list_control_field_access($op, $field, $entity_type, $entity, $account) {
  if ($op !== 'edit') {

  $uids = editor_list_uids_from_list($entity);
  if (!in_array($account->uid, $uids)) {

  $deny = array('field_editors');
  if (in_array($field['field_name'], $deny)) {
    return false;

Since we only care if the user is trying to update a particular field, we return nothing if this is not the case. Keep in mind that the op string here is edit and not update as it was in the other hook. This is just one of those Drupal quirks of inconsistency we all came to love so much. And like before, we ignore the situation if the current user is not part of the editor list.

Then, we define an array of field names we want to deny access to (in our case only one but we can add to it depending on the use case). Finally, we return false if the currently accessed field is part of our $deny array. Yet another difference here in that we have to return a boolean instead of a constant like we did before.

Now the editors in the list of a given node cannot remove themselves or add anybody else to the list. But then again, in some cases you may want this functionality and in others not. It’s up to you.

Tidying up

The last thing I am going to show you here relates to organization and maybe a bit of user experience. With our current implementation, the editor list field on the Article nodes is present somewhere on the form (wherever you dragged-and-dropped it when editing the field settings). However, wouldn’t it be nice if it were automatically part of the Authoring information group at the bottom of the page? Something like this:

Drupal 7 multiple editors per node

I think so. Let’s see how we can do that.

First, we need to implement hook_form_alter or one of its variations. I prefer the most targeted one to avoid unnecessary calls to it and a bunch of conditional checks:

 * Implements hook_form_BASE_FORM_ID_alter().
function editor_list_form_article_node_form_alter(&$form, &$form_state, $form_id) {
  $form['#after_build'][] = 'editor_list_node_form_after_build';

We went with the BASE_FORM_ID of the article nodes here so if we extend our application to other types we would do the same for those as well. Inside, we just define an #after_build function to be triggered when the form has finished building. This is to ensure all the form alterations have been already done by contributed modules. All that is left to be done is to write the function responsible for making changes to the form:

function editor_list_node_form_after_build($form, &$form_state) {
  $field = field_info_field('field_editors');
  if ( ! field_access('edit', $field, 'node', $form['#entity'])) {
    return $form;

  if ($form['author']['#access'] === 0) {
    return $form;

  $field_editors = $form['field_editors'];
  $field_editors['#weight'] = 0;
  $form['author']['additional_authors'] = $field_editors;
  $form['field_editors'] = array();

  return $form;

This looks complicated but it really isn’t. We begin by loading the field definition of our editor list field. This is so that we can run the field_access check on it and just return the form array unchanged if the current user doesn’t have access to the field. Next, we do the same if the current user does not have access to the author group on the form (this is the Authoring information group we want to place the field into). And lastly, we make a copy of the field definition, change its weight and place it into the group, followed by unsetting the original definition to avoid having duplicates.

And that is pretty much it. Now the editors list field should be tucked in with the rest of the information related to authorship.


In this article, we created a solution to a content editing problem that Drupal 7 could not fix out of the box. However, it did provide us with the development tools necessary to make this an easy task inside of a custom module.

We now have an editor list field on the article node form by which we can specify exactly which users have access to that particular node. Though do keep in mind that in order for this to be of any use, the users you add to these lists must not have a role that allows them to edit all article nodes. Otherwise you won’t see much of a difference.

May 01 2015
May 01

In this article we are going to look at automated testing in Drupal 8. More specifically, we are going to write a few integration tests for some of the business logic we wrote in the previous Sitepoint articles on Drupal 8 module development. You can find the latest version of that code in this repository along with the tests we write today.

Drupal 8 logo

But before doing that, we will talk a bit about what kinds of tests we can write in Drupal 8 and how they actually work.

Simpletest (Testing)

Simpletest is the Drupal specific testing framework. For Drupal 6 it was a contributed module but since Drupal 7 it has been part of the core package. Simpletest is now an integral part of Drupal core development, allowing for safe API modifications due to an extensive codebase test coverage.

Right off the bat I will mention the authoritative documentation page for Drupal testing with Simpletest. There you can find a hub of information related to how Simpletest works, how you can write tests for it, what API methods you can use, etc.

By default, the Simpletest module that comes with Drupal core is not enabled so we will have to do that ourselves if we want to run tests. It can be found on the Extend page named as Testing.

Once that is done, we can head to admin/config/development/testing and see all the tests currently available for the site. These include both core and contrib module tests. At the very bottom, there is also the Clean environment button that we can use if any of our tests quit unexpectedly and there are some remaining test tables in your database.

How does Simpletest work?

When we run a test written for Simpletest, the latter uses the existing codebase and instructions found in the test to create a separate Drupal environment in which the test can run. This means adding additional tables to the database (prefixed by simpletest_) and test data that are used to replicate the site instance.

Depending on the type of test we are running and what it contains, the nature of this replication can differ. In other words, the environment can have different data and core functionality depending on the test itself.

What kinds of tests are there in Drupal 8?

There are two main types of tests that we can write for Drupal 8: unit tests using PHPUnit (which is in core now) and functional tests (using Simpletest). However, the latter can also be split into two different kinds: web tests (which require web output) and kernel tests (which do not require web output). In this article we will practically cover only web tests because most of the functionality we wrote in the previous articles is manifested through output so that’s how we need to test it as well.

Writing any type of test starts by implementing a specific class and placing it inside the src/Tests folder of the module it tests. I also encourage you to read this documentation page that contains some more information on this topic as I do not want to duplicate it here.

Our tests

As I mentioned, in this article we will focus on providing test coverage for some of the business logic we created in the series on Drupal 8 module development. Although there is nothing complicated happening there, the demo module we built offers a good example for starting out our testing process as well. So let’s get started by first determining what we will test.

By looking at the demo module, we can delineate the following aspects we can test:

That’s pretty much it. The custom menu link we defined inside the demo.links.menu.yml could also be tested but that should already work out of the box so I prefer not to.

For the sake of brevity and the fact that we don’t have too much we need to test, I will include all of our testing methods into one single class. However, you should probably group yours into multiple classes depending on what they are actually responsible for.

Inside a file called DemoTest.php located in the src/Tests/ folder, we can start by adding the following:


namespace Drupal\demo\Tests;

use Drupal\simpletest\WebTestBase;

 * Tests the Drupal 8 demo module functionality
 * @group demo
class DemoTest extends WebTestBase {

   * Modules to install.
   * @var array
  public static $modules = array('demo', 'node', 'block');

   * A simple user with 'access content' permission
  private $user;

   * Perform any initial set up tasks that run before every test method
  public function setUp() {
    $this->user = $this->drupalCreateUser(array('access content'));

Here we have a simple test class which for every test it runs, will enable the modules in the $modules property and create a new user stored inside the $user property (by virtue of running the setUp() method).

For our purposes, we need to enable the demo module because that is what we are testing, the block module because we have a custom block plugin we need to test and the node module because our logic uses the access content permission defined by this module. Additionally, the user is created just so we can make sure this permission is respected.

For the three bullet points we identified above, we will now create three test methods. Keep in mind that each needs to start with the prefix test in order for Simpletest to run them automatically.

Testing the page

We can start by testing the custom page callback:

 * Tests that the 'demo/' path returns the right content
public function testCustomPageExists() {


  $demo_service = \Drupal::service('demo.demo_service');
  $this->assertText(sprintf('Hello %s!', $demo_service->getDemoValue()), 'Correct message is shown.');

And here is the code that does it.

First, we log in with the user we created in the setUp() method and then navigate to the demo path. Simpletest handles this navigation using its own internal browser. Next, we assert that the response of the last accessed page is 200. This validates that the page exists. However, this is not enough because we need to make sure the text rendered on the page is the one loaded from our service.

For this, we statically access the \Drupal class and load our service. Then we assert that the page outputs the hello message composed of the hardcoded string and the return value of the service’s getDemoValue() method. It’s probably a good idea to write a unit test for whatever logic happens inside the service but for our case this would be quite redundant.

And that’s it with the page related logic. We can go to the testing page on our site, find the newly created DemoTest and run it. If all is well, we should have all green and no fails.

drupal 8 automatated tests

Testing the form

For the form we have another method, albeit more meaty, that tests all the necessary logic:

 * Tests the custom form
public function testCustomFormWorks() {

  $config = $this->config('demo.settings');
  $this->assertFieldByName('email', $config->get('demo.email_address'), 'The field was found with the correct value.');

  $this->drupalPostForm(NULL, array(
    'email' => '[email protected]'
  ), t('Save configuration'));
  $this->assertText('The configuration options have been saved.', 'The form was saved correctly.');

  $this->assertFieldByName('email', '[email protected]', 'The field was found with the correct value.');

  $this->drupalPostForm('demo/form', array(
    'email' => '[email protected]'
  ), t('Save configuration'));
  $this->assertText('This is not a .com email address.', 'The form validation correctly failed.');

  $this->assertNoFieldByName('email', '[email protected]', 'The field was found with the correct value.');

The first step is like before. We go to the form page and assert a successful response. Next, we want to test that the email form element exists and that its default value is the value found inside the default module configuration. For this we use the assertFieldByName() assertion.

Another aspect we need to test is that saving the form with a correct email address does what it is supposed to: save the email to configuration. So we use the drupalPostForm() method on the parent class to submit the form with a correct email and assert that a successful status message is printed on the page as a result. This proves that the form saved successfully but not necessarily that the new email was saved. So we redo the step we did earlier but this time assert that the default value of the email field is the new email address.

Finally, we need to also test that the form doesn’t submit with an incorrect email address. We do so again in two steps: test a form validation failure when submitting the form and that loading the form again will not have the incorrect email as the default value of the email field.

Testing the block

 * Tests the functionality of the Demo block
public function testDemoBlock() {
  $user = $this->drupalCreateUser(array('access content', 'administer blocks'));

  $block = array();
  $block['id'] = 'demo_block';
  $block['settings[label]'] = $this->randomMachineName(8);
  $block['theme'] = $this->config('system.theme')->get('default');
  $block['region'] = 'header';
  $edit = array(
    'settings[label]' => $block['settings[label]'],
    'id' => $block['id'],
    'region' => $block['region']
  $this->drupalPostForm('admin/structure/block/add/' . $block['id'] . '/' . $block['theme'], $edit, t('Save block'));
  $this->assertText(t('The block configuration has been saved.'), 'Demo block created.');

  $this->assertText('Hello to no one', 'Default text is printed by the block.');

  $edit = array('settings[demo_block_settings]' => 'Test name');
  $this->drupalPostForm('admin/structure/block/manage/' . $block['id'], $edit, t('Save block'));
  $this->assertText(t('The block configuration has been saved.'), 'Demo block saved.');

  $this->assertText('Hello Test name!', 'Configured text is printed by the block.');

For this test we need another user that also has the permission to administer blocks. Then we create a new instance of our custom demo_block with no value inside the Who field and assert that a successful confirmation message is printed as a result. Next, we navigate to the front page and assert that our block shows up and displays the correct text: Hello to no one.

Lastly, we edit the block and specify a Test name inside the Who field and assert that saving the block configuration resulted in the presence of a successful confirmation message. And we close off by navigating back to the home page to assert that the block renders the correct text.


In this article, we’ve seen how simple it is to write some basic integration tests for our Drupal 8 business logic. It involves creating one or multiple class files which simply make use of a large collection of API methods and assertions to test the correct behavior of our code. I strongly recommend you give this a try and start testing your custom code early as possible in order to make it more stable and less prone to being broken later on when changes are made.

Additionally, don’t let yourself get discouraged by the slow process of writing tests. This is mostly only in the beginning until you are used to the APIs and you become as fluent as you are with the actual logic you are testing. I feel it’s important to also mention that this article presented a very high level overview of the testing ecosystem in Drupal 8 as well as kept the tests quite simple. I recommend a more in depth look into the topic going forward.

Apr 20 2015
Apr 20

In this article, we are going to look at how we can create a Drupal module which will allow your users to like your posts. The implementation will use jQuery to make AJAX calls and save this data asynchronously.


Creating your Drupal like module

Let’s start by creating the new Drupal module. To do that we should first create a folder called likepost in the sites\all\modules\custom directory of your Drupal installation as shown below:

Initial folder structure

Inside this folder, you should create a file called likepost.info with the following contents:

name = likepost
description = This module allows the user to like posts in Drupal.
core = 7.x

This file is responsible for providing metadata about your module. This allows Drupal to detect and load its contents.

Next, you should create a file called as likepost.module in the same directory. After creating the file, add the following code to it:

 * @file
 * This is the main module file.

 * Implements hook_help().
function likepost_help($path, $arg) {

    if ($path == 'admin/help#likepost') {
        $output = '<h3>' . t('About') . '</h3>';
        $output .= '<p>' . t('This module allows the user to like posts in Drupal.') . '</p>';
        return $output;

Once you have completed this you can go to the modules section in your Drupal administration and should be able to see the new module. Do not enable the module yet, as we will do so after adding some more functionality.

Creating the schema

Once you have created the module file, you can create a likepost.install file inside the module root folder. Inside, you will define a table schema which is needed to store the likes on each post for each user. Add the following code to the file:


* Implements hook_schema().
function likepost_schema() {
    $schema['likepost_table_for_likes'] = array(
        'description' => t('Add the likes of the user for a post.'),
        'fields' => array(
            'userid' => array(
                'type' => 'int',
                'not null' => TRUE,
                'default' => 0,
                'description' => t('The user id.'),

            'nodeid' => array(
                'type' => 'int',
                'unsigned' => TRUE,
                'not null' => TRUE,
                'default' => 0,
                'description' => t('The id of the node.'),


        'primary key' => array('userid', 'nodeid'),
    return $schema;

In the above code we are are implementing the hook_schema(), in order to define the schema for our table. The tables which are defined within this hook are created during the installation of the module and are removed during the uninstallation.

We defined a table called likepost_table_for_likes with two fields: userid and nodeid. They are both integers and will store one entry per userid – nodeid combination when the user likes a post.

Once you have added this file, you can install the module. If everything has gone correctly, your module should be enabled without any errors and the table likepost_table_for_likes should be created in your database. You should also see the help link enabled in the module list next to your likepost module. If you click on that you should be able to see the help message you defined in the hook_help() implementation.

Help Message

Creating a menu callback to handle likes

Once we have enabled the module, we can add a menu callback which will handle the AJAX request to add or delete the like. To do that, add the following code to your likepost.module file

* Implements hook_menu().
function likepost_menu() {
    $items['likepost/like/%'] = array(
        'title' => 'Like',
        'page callback' => 'likepost_like',
        'page arguments' => array(2),
        'access arguments' => array('access content'),
        'type' => MENU_SUGGESTED_ITEM,
    return $items;

function likepost_like($nodeid) {
    $nodeid = (int)$nodeid;
    global $user;

    $like = likepost_get_like($nodeid, $user->uid);

    if ($like !== 0) {
        ->condition('userid', $user->uid)
        ->condition('nodeid', $nodeid)
        //Update the like value , which will be sent as response
        $like = 0;
    } else {
        'userid' => $user->uid,
        'nodeid' => $nodeid
        //Update the like value , which will be sent as response
        $like = 1;

    $total_count = likepost_get_total_like($nodeid);
        'like_status' => $like,
        'total_count' => $total_count


* Return the total like count for a node.
function likepost_get_total_like($nid) {
    $total_count = db_query('SELECT count(*) from {likepost_table_for_likes} where nodeid = :nodeid',
    array(':nodeid' => $nid))->fetchField();
    return (int)$total_count;

* Return whether the current user has liked the node.
function likepost_get_like($nodeid, $userid) {
    $like = db_query('SELECT count(*) FROM {likepost_table_for_likes} WHERE
    nodeid = :nodeid AND userid = :userid', array(':nodeid' => $nodeid, ':userid' => $userid))->fetchField();
    return (int)$like;

In the above code, we are implementing hook_menu() so that whenever the path likepost/like is accessed with the node ID, it will call the function likepost_like().

Inside of likepost_like() we get the node ID and the logged in user’s ID and pass them to the function likepost_get_like(). In the function likepost_get_like() we check our table likepost_table_for_likes to see if this user has already liked this post. In case he has, we will delete that like, otherwise we will insert an entry. Once that is done, we call likepost_get_total_like() with the node ID as a parameter, which calculates the total number of likes from all users on this post. These values are then returned as JSON using the drupal_json_output() API function.

This menu callback will be called from our JQuery AJAX call and will update the UI with the JSON it receives.

Displaying the Like button on the node

Once we have created the callback, we need to show the like link on each of the posts. We can do so by implementing hook_node_view() as below:

 * Implementation of hook_node_view
function likepost_node_view($node, $view_mode) {
    if ($view_mode == 'full'){
        $node->content['likepost_display'] =  array('#markup' => display_like_post_details($node->nid),'#weight' => 100);

        $node->content['#attached']['js'][] = array('data' => drupal_get_path('module', 'likepost') .'/likepost.js');
        $node->content['#attached']['css'][] = array('data' => drupal_get_path('module', 'likepost') .'/likepost.css');


* Displays the Like post details.
function display_like_post_details($nid) {

    global $user;
    $totalLike =  likepost_get_total_like($nid);
    $hasCurrentUserLiked = likepost_get_like($nid , $user->uid);

    return theme('like_post',array('nid' =>$nid, 'totalLike' =>$totalLike, 'hasCurrentUserLiked' => $hasCurrentUserLiked));
* Implements hook_theme().
function likepost_theme() {
    $themes = array (
        'like_post' => array(
            'arguments' => array('nid','totalLike','hasCurrentUserLiked'),
    return $themes;

function theme_like_post($arguments) {
    $nid = $arguments['nid'];
    $totalLike = $arguments['totalLike'];
    $hasCurrentUserLiked = $arguments['hasCurrentUserLiked'];
    global $base_url;
    $output = '<div class="likepost">';
    $output .= 'Total number of likes on the post are ';
    $output .= '<div class="total_count">'.$totalLike.'</div>';

    if($hasCurrentUserLiked == 0) {
        $linkText = 'Like';
    } else {
        $linkText = 'Delete Like';

    $output .= l($linkText, $base_url.'/likepost/like/'.$nid, array('attributes' => array('class' => 'like-link')));

    $output .= '</div>'; 
    return $output;

Inside likepost_node_view() we check for when the node is in the full view mode and we add the markup returned by the function display_like_post_details(). We also attached our custom JS and CSS file when the view is rendered using the attached property on the node content. In function display_like_post_details() we get the total number of likes for the post and whether or not the current user has liked the post. Then we call the theme function which will call the function theme_like_post() which we have declared in the implementation of ‘hook_theme’ but will allow the designers to override if required. In theme_like_post(), we create the HTML output accordingly. The href on the link is the $base_url and the path to our callback appended to it. The node ID is also attached to the URL which will be passed as a parameter to the callback.

Once this is done, add a file likepost.css to the module root folder with the following contents:

.likepost {
    border-style: dotted;
    border-color: #98bf21;
    padding: 10px;

.total_count {
    font-weight: bold;

.like-link {

.like-link:hover {
    color: red;

Now if you go to the complete page of a post you will see the Like post count as shown below.

Adding the jQuery logic

Now that we see the like link displayed, we will just have to create the likepost.js file with the following contents:

jQuery(document).ready(function () {

    jQuery('a.like-link').click(function () {
            type: 'POST', 
            url: this.href,
            dataType: 'json',
            success: function (data) {
                if(data.like_status == 0) {
                else {
                    jQuery('a.like-link').html('Delete Like');

            data: 'js=1' 

        return false;

The above code binds the click event to the like link and makes an AJAX request to the URL of our callback menu function. The latter will update the like post count accordingly and then return the new total count and like status, which is used in the success function of the AJAX call to update the UI.

Updated UI with Like count


jQuery and AJAX are powerful tools to create dynamic and responsive websites. You can easily use them in your Drupal modules to add functionality to your Drupal site, since Drupal already leverages jQuery for its interface.

Have feedback? Let us know in the comments!

Jun 13 2014
Jun 13

How to Build a Drupal 8 Module

Drupal 8 brings about a lot of changes that seek to enroll it in the same club other modern PHP frameworks belong to. This means the old PHP 4 style procedural programming is heavily replaced with an object oriented architecture. To achieve this, under the initiative of Proudly Found Elsewhere, Drupal 8 includes code not developed specifically for Drupal.

One of the most important additions to Drupal are Symfony components, with 2 major implications for Drupal developers. First, it has the potential to greatly increase the number of devs that will now want to develop for Drupal. And second, it gives quite a scare to some of the current Drupal 7 developers who do not have much experience with modern PHP practices. But that’s ok, we all learn, and lessons taken from frameworks like Symfony (and hopefully Drupal 8), will be easily extensible and applicable to other PHP frameworks out there.

In the meantime, Drupal 8 is in a late stage of its release cycle, the current version at the time of writing being alpha11. We will use this version to show some of the basic changes to module development Drupal 7 devs will first encounter and should get familiar with. I set up a Git repo where you can find the code I write in this series so you can follow along like that if you want.

How do I create a module?

The first thing we are going to look at is defining the necessary files and folder structure to tell Drupal 8 about our new module. In Drupal 7 we had to create at least 2 files (.info and .module), but in Drupal 8, the YAML version of the former is enough. And yes, .info files are now replaced with .info.yml files and contain similar data but structured differently.

Another major change is that custom and contrib module folders now go straight into the root modules/ folder. This is because all of the core code has been moved into a separate core/ folder of its own. Of course, within the modules/ directory, you are encouraged to separate modules between custom and contrib like in Drupal 7.

Let’s go ahead and create a module called demo (very original) and place it in the modules/custom/ directory. And as I mentioned, inside of this newly created demo/ folder, all we need to begin with is a demo.info.yml file with the following required content:

name: Drupal 8 Demo module
description: 'Demo module for Drupal 8 alpha11'
type: module
core: 8.x

Three out of four you should be familiar with (name, description and core). The type is now also a requirement as you can have yml files for themes as well. Another important thing to keep in mind is that white spaces in yml files mean something and proper indentation is used to organize data in array-like structures.

You can check out this documentation page for other key|value pairs that can go into a module .info.yml file and the change notice that announced the switch to this format.

And that’s it, one file. You can now navigate to the Extend page, find the Demo module and enable it.

As I mentioned, we are no longer required to create a .module file before we can enable the module. And architecturally speaking, the .module files will be significantly reduced in size due to most of the business logic moving to service classes, controllers and plugins, but we’ll see some of that later.

What is ‘routing’ and what happened to hook_menu() and its callbacks?

In Drupal 7, hook_menu() was probably the most implemented hook because it was used to define paths to Drupal and connect these paths with callback functions. It was also responsible for creating menu links and a bunch of other stuff.

In Drupal 8 we won’t need hook_menu() anymore as we make heavy use of the Symfony2 components to handle the routing. This involves defining the routes as configuration and handling the callback in a controller (the method of a Controller class). Let’s see how that works by creating a simple page that outputs the classic Hello world!.

First, we need to create a routing file for our module called demo.routing.yml. This file goes in the module root folder (next to demo.info.yml). Inside this file, we can have the following (simple) route definition:

  path: '/demo'
    _content: '\Drupal\demo\Controller\DemoController::demo'
    _title: 'Demo'
    _permission: 'access content'

The first line marks the beginning of a new route called demo for the module demo (the first is the module name and the second the route name). Under path, we specify the path we want this route to register. Under defaults, we have two things: the default page title (_title) and the _content which references a method on the DemoController class. Under requirements, we specify the permission the accessing user needs to have to be able to view the page. You should consult this documentation page for more options you can have for this routing file.

Now, let’s create our first controller called DemoController that will have a method named demo() getting called when a user requests this page.

Inside the module directory, create a folder called src/ and one called Controller/ inside of it. This will be the place to store the controller classes. Go ahead and create the first one: DemoController.php.

The placement of the Controllers and, as we will see, other classes, into the src/ folder is part of the adoption of the PSR-4 standard. Initially, there was a bigger folder structure we had to create (PSR-0 standard) but now there is a transition phase in which both will work. So if you still see code placed in a folder called lib/, that’s PSR-0.

Inside of our DemoController.php file, we can now declare our class:

 * @file
 * Contains \Drupal\demo\Controller\DemoController.

namespace Drupal\demo\Controller;

 * DemoController.
class DemoController {
   * Generates an example page.
  public function demo() {
    return array(
      '#markup' => t('Hello World!'),

This is the simplest and minimum we need to do in order to get something to display on the page. At the top, we specify the class namespace and below we declare the class.

Inside the DemoController class, we only have the demo() method that returns a Drupal 7-like renderable array. Nothing big. All we have to do now is clear the caches and navigate to http://example.com/demo and we should see a Drupal page with Hello World printed on it.

In Drupal 7, when we implement hook_menu(), we can also add the registered paths to menus in order to have menu links showing up on the site. This is again no longer handled with this hook but we use a yml file to declare the menu links as configuration.

Let’s see how we can create a menu link that shows up under the Structure menu of the administration. First, we need to create a file called demo.menu_links.yml in the root of our module. Inside this yml file we will define menu links and their position in existing menus on the site. To achieve what we set out to do, we need the following:

  title: Demo Link
  description: 'This is a demo link'
  parent: system.admin_structure
  route_name: demo.demo

Again we have a yml structure based on indentation in which we first define the machine name of the menu link (demo) for the module demo (like we did with the routing). Next, we have the link title and description followed by the parent of this link (where it should be placed) and what route it should use.

The value of parent is the parent menu link (appended by its module) and to find it you need to do a bit of digging in *.menu_links.yml files. I know that the Structure link is defined in the core System module so by looking into the system.menu_links.yml file I could determine the name of this link.

The route_name is the machine name of the route we want to use for this link. We defined ours earlier. And with this in place, you can clear the cache and navigate to http://example.com/admin/structure where you should now see a brand new menu link with the right title and description and that links to the demo/ path. Not bad.


In this article we began exploring module development in Drupal 8. At this stage (alpha11 release), it is time to start learning how to work with the new APIs and port contrib modules. To this end, I am putting in writing my exploration of this new and exiting framework that will be Drupal 8 so that we can all learn the changes and hit the ground running when release day comes.

For starters, we looked at some basics: how you start a Drupal 8 module (files, folder structure etc), all compared with Drupal 7. We’ve also seen how to define routes and a Controller class with a method to be called by this route. And finally, we’ve seen how to create a menu link that uses the route we defined.

In the next tutorial, we will continue building this module and look at some other cool new things Drupal 8 works with. We will see how we can create blocks and how to work with forms and the configuration system. See you then.

Cool Drupal modules - Table Field

Nov 17 2013
Nov 17
Nov 17 2013
Nov 17

It’s hard to imagine life without mobile devices. While a developer controls the display of the site and its structure, editors are the ones adding content to a site on a regular basis. One tool that developers can use with editors in mind is Responsive Preview.

Difficulties during content creation can range from complex interfaces to performance problems. Each of these problems can be multiplied when you add in responsive design.  

Responsive Preview is a module that provides you with a quick way to preview how the website's pages will appear with various screen dimensions.


Response Preview helps editors when they need to try out new layouts or add new content to preview the page. This means they can make sure everything works on the most commonly used devices before publishing on the live site. The module provides a quick approximation of how the page and the layout will look on any device.

How it works

From the development perspective, the module creates an iFrame with provided configs. This means it doesn't have to go through the trouble of getting all the frontend code and all the styles compiled and rendered in the backend to show a preview. Instead, we just load the iFrame which displays the frontend view.

The module provides a config entity “Preset” with the fields that describe “device” including  “width”, “height”, “rotation”, and more. On a node view page, there is a select with our options. Selecting an option opens an overlay with a preview of the current page.



width: width,

          height: height


This way we get a preview of everything we need. Simply create a controller and put a link to the source attribute of the iFrame.

Responsive Preview Module Screenshot


When creating a site, developers should think not only about end users but about editors who will need to work on the site daily. Drupal is a great solution for content management, but sometimes it lacks ease of use.

It’s not enough to only have a mobile, tablet, and desktop design anymore, as many devices fall in between those dimensions. Phones can be the same size as small tablets and the new iPad Pros have a larger screen than some laptops. Responsive Preview provides the flexibility to configure the module as an admin. This makes it easy to add new presets when new devices are released.

Got a project that needs editor-friendly responsive design? Get in touch with us today!

Jun 14 2013
Jun 14

The people who use any given web site are all different in terms of geography, past behavior, intent, device, time of day, the temperature of the climate they’re currently in…and the list goes on. Developing for the web is anything but easy, so, over the last few years, the Drupal community has been focusing on keeping up with the various mobile device sizes, design patterns and browser technologies, putting a lot of attention on responsive design, and doing it well. So, we’ve since been doing fairly well on adapting to various devices, but what about the aforementioned traits such as intent, past behavior and the like?

We often create personas to plan and design web sites, but the content does not embody or respond to these fictional-turned-real characters. Marketers spend a lot of time producing content that could be better-tailored to each individual. An individual’s browsing history can be cookied, if they are an anonymous user, or logged in analytics and tied to their account as an authenticated user.

Amazon.com has been a leader in this domain. Just look at all the recommendations and custom-tailored content you receive when logged in to amazon.com. The site even informs the anonymous, uncookied user when there is no browsing history to act upon, encouraging further activity on the site.

Amazon.com with no browsing history

Think about a woman in her late 60s – based purely on statistics, she might opt-out if she receives an email that contains offers for power tools and pro athlete products. Or a man who receives an email with women’s clothing. Similar consequences are in play on web sites.

Another example of a leader in context is Netflix. New videos are recommended based on your viewing habits, ratings, and even your Facebook friends’ activity on Netflix.

Screen Shot 2013-06-14 at 4.39.50 PM

The buzzword for this context is called Web Experience Management (WEM). Vendors have been developing proprietary, expensive, closed-source solutions. It is to the great benefit of the Drupal community to engage in WEM as part of What Drupal Does. There is already work being done with the WEM project that allows one to track user events as they occur throughout the site. By so doing, one can customize a user’s experience so that it is unique and relevant to the user. The WEM module also integrates with Google Analytics to further track events. Any event you track in WEM can also be sent to Google Analytics.

Events are tracked via the included  Engagement API. You can track an event via PHP on your page or during a certain hook in a custom module. The PHP would look something like this:

engagement_event_track($event_name, $event_value, $event_data, $uid);

An event can also be tracked via Javascript, like so:

Drupal.engagement.track(event_type, val, data)

An event can also be tracked via HTML, such as in an HTML email.

The WEM project is currently under active development, but already usable. It needs people to help with integration into Views, Rules, and similar Drupal architecture patterns. With that, let’s close with a few screen shots of the WEM module in action, running on on Drupal 7. One can see that UI for assigning points to events within categories is simple yet effective. User segments can be built from these categories and corresponding point totals to deliver a customized, contextual experience to your user. This effort will hopefully make WEM much less of a concept of its own, and lead to the expectations of what Drupal does as a CMS. WEM is really just a CMS, with context.

Screen Shot 2013-06-12 at 3.33.41 PM Screen Shot 2013-06-12 at 3.34.33 PM Screen Shot 2013-06-12 at 3.34.44 PM

Web Experience Management: User interface in Drupal 7

Web Experience Management: User interface in Drupal 7

May 02 2013
May 02
Drupal 7 Features 2 screen

Drupal 7 Features 2 screen

Until we can override the enabled module/theme/library list dynamically in Drupal 8 via configuration, we can bundle up our environment-specific development modules and Strongarm variables in a feature and enable the feature on a per-environment basis in settings.php (or even better, local.settings.php) via a project called Environment Modules. For example, one could create a feature for the development environment, enable the devel module, and set environment-specific Strongarm variables such as those that leave Drupal core caching disabled or environment-specific settings for Domain Access domains. Additionally, whenever refreshing the development, integration or staging environment databases from the production database as part of a release cycle, doing a simple Features revert reenables the correct environment-specific modules and sets the right environment-specific variables.

As the Environment Modules project states, $conf[‘environment_modules’] should not be set on your production site in its settings.php, however the module itself can still remain enabled on production without a performance hit — it just doesn’t do anything in that particular environment.

Oct 17 2012
Oct 17

After a little over 9 months and with an impressive 1290 sites reporting they use it, Menu Views has undergone a little nip and tuck! Today, I have finally released in hopes to squash the ever so annoying bugs and wonderful feature requests that were made! This module has been an invaluable tool in the mega-menu creation process. It has solved a problem for many people: how to insert a view into the Drupal menu system.

Many Drupal sites I've seen through out the years (those that have complex mega-menus) left me perplexed at how to accomplish this task. I could never really imagine it happening effectively, unless it was rendered using views. After being able to finally see how some of these sites actually accomplished this great feat, I was also a little baffled at the shear complexity of making it happen.

Often times, the theme is the unsuspecting and unfortunate victim. Being hacked, sliced and injected with arbitrary code to succeed in rendering the desired result. Some prefer to do it this way and to them I say "be my guest". However, when a more dynamic approach is needed, it is far better to utilize the awesome power of Drupal. Which begs me to reiterate what the purpose of a CMS is for: letting the system actually manage the content (hmm novel idea).

Menu Overview Form

Eureka! Let Drupal's own menu system and administrative user interface handle this complex problem! When I first released Menu Views (1.x) that is what it solved: inserting a view into the menu. However, it also introduced quite a few other problems that were unforeseen and rather complicated to fix. Namely these involved other contributed modules and the biggest native one: breadcrumbs!

Over the past few months, I really started digging into the complexity that is the menu system in Drupal. Trying to figure out what exactly I could do to help simplify how the replacement of links were intercepted and rendered. After pouring over the core menu module and several contributed modules, I began noticing several commonalities in the best approach: theme_menu_link().

In Menu Views-1.x I was intercepting theme_link() instead. In hindsight, I can't believe how incredibly stupid that was! So essentially, the old method intercepted every link on the site with the off chance it might be a menu link that had Menu Views configuration in the link's options array. Whoa... major performance hit and a big no-no! For this reason alone, that is why I decided to do a full version bump on Menu Views. Part of this decision was to consider existing sites and how they may have already compensated for view were popping up everywhere. An additional deciding factor involved refactoring the entire administrative user interface experience.

Menu Item TypeIn Menu Views (1.x), there seemed to be a lot of confusion around "attaching" a view and optionally hiding the link using <view> in the link path. I thought about this for a while. Ultimately I decided that the best way to solve this would to separate the view form from the link form and give the administrator the option to choose what type of menu item this should be. In this way, menu views can more accurately determine when to intercept the menu item and render either the link or a view.

There are now a couple options to better manage what the breadcrumb link actually outputs as well. Along with rendering a title outside of the view if desired. Both of which can use tokens! No longer are we left with stuff extraneous markup in the view's header. Last but not least, one feat of UI marvel: node add/edit forms can control menu views and you're no longer limited to just the menu overview form!

Menu View Form

Per some user requests, I have also set up a demonstration site so you can firebug to your heart's content: http://menuviews.leveltendesign.com. I push blocks on the left and right to show that it integrates well with Menu Block, Nice Menus and Superfish.

Overall, I think Menu View's new face lift will allow this module to reach a new level of maturity and stability that has been greatly needed. Thank you all for your wonderful suggestions in making this module a reality and truly a joy to code!

Stay tuned for next week: Theming Menu Views in Drupal 7

Jun 29 2012
Jun 29

Many of you might be familiar with the module Skinr (http://drupal.org/project/skinr). It gained a lot of support back in Drupal 6 by providing an easier, albeit somewhat verbose, way of dynamically configuring how elements on your site are styled.

When I first started using Skinr, it worked as advertised; however, it ultimately left me with a bitter taste in my mouth. I felt like I was constantly trying to navigate an endless maze while blind-folded. There were options upon options and fieldsets within fieldsets. It had almost everything but the kitchen sink in it.

I never really have been one who enjoys feeling like I’m just wasting my time. So I eventually scrapped this module as being a potential long term candidate for managing customizable styling. Apparently I wasn’t the only one who had these concerns either.

Then the 2.x branch was born. I only started using the 2.x branch because it was the only one available for Drupal 7. They had completely scrapped the old interface and did an amazing amount of work to make Skinr easily maintainable. You can view a list of changes here: http://groups.drupal.org/node/53798.

So if any of you are like me, you probably were thinking: “Skinr, in Drupal 7? I don’t want to make this any more confusing than it has to be!” Well fear not! You can learn how to start Skinr-ing in just 7 easy steps!

Let us know if you're using this module and leave us a comment below!

Oct 12 2011
Oct 12

CTools is a powerful toolbox for Drupal developers, but there are many features of this huge module that aren't well known or used. I would like to share some of my experience with using one of those lesser-known features: CTools Access Rulesets.

In this article you'll learn how to utilize the nice CTools Access Rulesets GUI in combination with some custom code to limit file downloads based on certain criteria. This promotes generic code and separates the access logic out to a place where it is customizable by a site administrator.

This gives you the ability to use flexible and powerful Panels selection rules outside of Panels.


CTools Access Rulesets allow you to create access rules based on different contexts. It is widely used in page manager when we define rules for access to the page. When we enable the ctools_access_ruleset module, we use a UI to create our own access rules (admin/structure/ctools-rulesets/list).

One way we recently used this functionality was to limit private file downloads. I wanted to have a flexible rule that was customizible via UI, one that I would be able to extend if client's requirements changed (and I knew they would). To manage this, we wrote our own module and used hook_file_download to trigger our ctools access ruleset to determine whether we should allow the user to download the file or not.

We decided to base access control on taxonomy terms linked to the node that have the file attached. To do this we can create a ruleset that will have the context as nodes and there we check for the condition of whether or not the specified taxonomy terms are attached to these nodes.

Setting up the rule (in the GUI)

The screenshots below (click to enlarge) will allow us to see the UI interface to see the how to set it up.

First we need to open the list of access rulesets: admin/structure/ctools-rulesets/list

Each rule consists of three parts: basic infomation, contexts, and rules. Basic information is the name and description. I will skip this part.

For the Contexts we add the required context Node.

We also add the Relation to the taxonomy term we want to use. In my case, the term is from the Category vocabulary.

Now lets look at the settings of the Rules.

We have only one Rule based on a taxonomy term. The settings are as follows:

Creating the code

Now let's see how we can execute the ctools ruleset in our own module.

The key function is ctools_access($access, $context). $context is the array of contexts that we pass to the ruleset. $access is the configuration array. The machine name of my ruleset is document_download_rule.

// Prepare arguments for ctools_access().
  // Name of created ruleset is document_download_rule.
$access = array('plugins' => array(
0 => array(
'name' => 'ruleset:document_download_rule',
'settings' => NULL,
'context' => array('node_context'),
'not' => FALSE,
'logic' => 'and',
'type' => 'none',
'settings' => NULL,
$node_context = ctools_context_create('entity:node', $node);
$contexts = array('node_context' => $node_context);   if (ctools_access($access, $contexts)) {
// Allow access.
  else {
// Deny access.

$node is the fully loaded node object that we find based on the file $uri. I will skip this part as it is not too important here. However you can take a look at a full example that is attached to this post here: Download Example

If we will decide to extend the ruleset in the future, the only things we will need to do is add new rules and contexts via the UI.

In order to understand how to prepare the $access configuration array, I would recommend doing what I did: enable module page manager, play with access rules by creating rulesets, and debug the $access variable in ctools_access function.


By using CTools Access Rulesets we created a custom module, which allowed us to limit file downloads based on certain criteria. We showed that this method is a way to quickly write really flexible code that can adapt to changing needs.

It should give you a great perspective on what is possible using CTools Access Rulesets and stir your imagination. Have you used CTools Access Rulesets in a clever way in the past? Please share your experiences in the comments.

Thanks for reading!

AttachmentSize 38.52 KB 55.3 KB 50.13 KB 57.51 KB 53.14 KB 61.6 KB 1.06 KB
Aug 02 2011
Aug 02

We would like to announce the creation of the Webform Bonus Pack module which allows you to do email routing and to send submissions digests in specific formats to a configured set of emails on cron.

This blog post aims to show different approaches of email routing (i.e.conditional emailing), to explain pros and cons of these approaches, and to show how to handle email routing efficiently using Webform Bonus Pack module.

Task statement

Let's assume we have a simple order webform for a Drupal webshop. It has four fields: Name, Email, What are you interested in, and Order details.

The What are you interested in field uses a multiple select component which have the following key-value pairs:

graphic_design|Graphic design
web_design|Web design
website_support|Website support
website_performance|Website performance optimization
internet_marketing|Internet marketing
seo|Search engine optimization

Assume we have following email routing rules:

Well known solutions

1. Webform's built in abilities

It is easy to send email to a custom address on every submission. Also we are able to send E-mail to an address which is coming from any of the webform components.

In our case we need to assign available values for the What are you interested in component to be like this:

[email protected]|Graphic design
[email protected]|Web design
[email protected]|Website performance optimization
[email protected]|Search engine optimization

As you can see it is easy to configure simple routing, however there are some limitations:

  • The key should be unique, hence it is impossible to use same email address for two or more keys.
  • It is impossible to send emails to multiple email addresses if a single item is selected.
  • Email addresses will be used instead of proper keys when viewing submission or downloading webform results.

As we can see, this is a fast solution, but it is not very configurable.

The Webform PHP module allows you to create a PHP component, which could be used to assign E-mail addresses to values (or whatever you want). In a PHP component you need to add specific PHP code that makes custom routing. Obviously in code you could read data from other components and use complex conditions. Although this is a highly configurable solution, it is very dangerous, so the module maintainer recommends against using this module unless the developer knows what he is doing.

3. Custom module

Using custom PHP code in your module for Webform validation or submission is more safe, and is also highly configurable, but it is more difficult to update routing rules and cannot be done easily by non-technical people.

Email routing using Webform Bonus Pack module

The Webform Bonus Pack module provides a mapping component, which can be easily used for email routing. Configuration is easy: you need to select the What are you interested in component as a mapped component and then add mapping key-pair values. Keys are the mapped component (e.g. What are you interested in) keys and values are emails. When items of the What are you interested in component are selected our routing component will return appropriate set of emails.

You need to select newly created Routing component as the E-Mail to address. And also don't forget to add [email protected] as custom email address to E-mails setting form.

Now you can test how it works: When you are submitting the form select the check-boxes for Website performance optimization and Hosting. Emails should then be sent to [email protected], [email protected], [email protected] and [email protected].

What's next?

I think that the mapping component will be evolving in the future. It would be good to have some functionality of or integration with the Rules module. Also, of course, I will be porting this to Drupal 7. In the next blog post about Webform Bonus module I am going to talk about another interesting feature, a submodule called Webform Digest, which already has integration with the mapping component.

Mar 26 2011
Mar 26
Drupad App and Module

I recently downloaded the Drupad module and purchased the Drupad App from the iTunes store. The two have changed the speed at which I can monitor, control, and promote my, and my client's Drupal sites. The module is a companion to the iPhone app (cost $4.99). The module was easy to install and configure the features you want your site to expose to the application. For example, you can select to manage comments, content, users, and more. Additionally you can choose which content types to exclude such as pages or Weblinks. You can even run cron with this handy set of tools. I highly recommend site users invest in the Drupad App and Drupad module.

Anyone else have experience with this module and App?

Apr 27 2010
Apr 27
my vertical bar graphs from google charts

For my recent post comparing compression methods for database dumps I had some very simple data, and wanted to present some very simple charts. None of the many charting modules for drupal seemed to be simple enough for me, so I borrowed some code I found on the web and made my own drupal module.

There are lots of charting solutions for Drupal - several of them described and compared in two very comprehensive posts linked to from the Comparison of Charting Modules page on drupal.org. However, most of these modules seem to cater for situations where data is coming from the Views module and / or stored in CCK fields. My requirements were simpler still; I had two very small tables of data which I wanted to chart, and when I say tables I mean little HTML tables, not tables in the database.

My web searches soon threw up a couple of ways to do this using javascript on the client side. The most interesting of which included auto-table-to-chart which uses open flash charts, more than one blog post giving examples of HTML tables to Open Flash Chart using jQuery, and variations on a fairly old (2008) post by Chris Heilmann titled Generating charts from accessible data tables and vice versa using the Google Charts API.

I decided to settle on the simple, lightweight approach of using javascript to examine the HTML table, and generate the request URL to generate a chart using google chart api. 90% of the work had been done for me by Martin Hawksey in a post he made building on Chris Heilmann's original. The javascript in the example given there dealt with more than one column of data, and added line graphs to the original's support for pie charts.

I wanted vertical bar graphs, and to build the javascript into the drupal framework. This was pretty easy. First I made some simple (and pretty crude) changes to the JS. I made it a little more jquery-friendly using document.ready:

< (table2graph = function(){

> $(document).ready(function(){

... then I made a couple of tiny changes to the JS to accommodate vertical bar graphs (bvg); to this section:

if (cht=='lc'){

charturl += '|1:|'+yMarks.join('|')+'&chxp=1,'+yMarks.join(',');

charturl += addDataPoints(tData,'o',dpt);

charturl += '&chco='+niceCol.slice(0,tData[0].length).join(',');

charturl += '&chg=0,16.666667';


var chart = document.createElement('img');

... I added the following (using a line of code which was already there to give my bar graphs nice colours like the line charts which were already supported):

if (cht=='lc'){

charturl += '|1:|'+yMarks.join('|')+'&chxp=1,'+yMarks.join(',');

charturl += addDataPoints(tData,'o',dpt);

charturl += '&chco='+niceCol.slice(0,tData[0].length).join(',');

charturl += '&chg=0,16.666667';


if (cht=='bvg'){

charturl += '&chco='+niceCol.slice(0,tData[0].length).join(',');


var chart = document.createElement('img');

I also needed to add my bvg charts to an if statement which was dealing with the axis for line charts differently than for pie graphs, like so:

< if (cType=="lc"){ stringOut += tArray[0].join('|').replace(/ /gi, '+');}

> if (cType=="lc" || cType=="bvg"){ stringOut += tArray[0].join('|').replace(/ /gi, '+');}


Now all that remained was getting my revised JS code into my drupal site. One easy way would be using drupal_add_js from within the theme. However I decided, as this is (arguably) more about functionality than themeing, to create a very simple drupal module to add the JS. I called the module chartfromhtml and pretty much all it does is this:


 * Implementation of hook_init().


function chartfromhtml_init() {

  drupal_add_js(drupal_get_path('module', 'chartfromhtml') . '/chartfromhtml.js', 'module', 'footer');


With this module enabled, I could use the google chart functionality from anywhere in my drupal site the same way as in the demos this is all based on. So to get charts generated from my small HTML tables, I simply added the following self-explanatory classes to the markup:

<table class="tochart typebvg size700x250">

If you think you might find this useful, you're welcome to download the chartfromhtml module (as a simple tarball for the moment). I believe Chris Heilmann's original code was creative commons, and I don't see why this couldn't become a proper GPL'ed drupal module if there's any demand for it.

My list of to do's would include rewriting the JS to be more jquery-esque, and adding support for more of the many chart types that google's API supports. I suppose there's no reason why open flash charts couldn't be an option as well.

AttachmentSize 2.61 KB
May 15 2008
May 15

A couple of weeks ago we announced a Drupal module, then this week I spotted another Piwik module being developed by Hass. I immediately sent the following contact message

"We already released a piwik module and have it under active development to include reporting etc. http://drupal.org/project/piwikanalytics , we should really merge these projects if possible rather than duplicating effort, what do you think? "

The response I got within 24 hours was : "Yes, we definitively shouldn't work on both projects. :-) "

Within a few hours Hass had committed some of our code into CVS and given us access to his project.

Whats my point? Its easy to collaborate and combine efforts if you are willing to make the first move and leave your ego at the door so you can focus on what makes the most commercial sense.

I have seen so many different modules on Drupal.org that do almost the same thing or actually do the same thing but for different versions that it saddens me as I see it as a waste of scarce time and resources. Even worse it becomes very confusing for newbies and inevitably complicates development of other modules that need to talk to these modules.

Commercial benefits of collaborating with another developer rather rewriting / releasing a module to do almost the same thing

  1. They may have a version that does what you want and just not committed it yet

  2. They may need what you want and be delighted to change their module to do what you want

  3. They may be happy to provide an interface that allows you to achieve what you need without the need for a full blown module

  4. They may have tried what you are intending and have very good reasons for not doing it e.g. security issue

  5. They may be looking for a co-maintainer or to hand over maintainership completely

  6. One module will probably be maintained better

  7. One module will probably be evolved better and of a higher quality due to more eyes checking for issues

  8. Its cheaper to work with a partner than do it all yourself

  9. Developing a module to suit multiple people normally makes it better as a contrib module as its inherently more flexible

  10. Its easier for other modules to build on top of one rather than having to try to extend two modules, inevitably they will choose one, are you certain they will choose yours?

  11. Its shows a mature community to the outside world, one where active collaboration is the norm, not forking and infighting

There are lots of valid reasons for having similar modules and even more invalid reasons, so if your developing a module that is similar to an already released module I would seriously encourage you to take a few minutes to contact the developer of the other module and see if you can collaborate.

The whole community benefits if we combine our efforts, even if you have valid reasons, think commercially which is worth more sharing development and maintenance costs or getting exactly what you want. Frequently you will find that actually the difference is not worth the ongoing costs/efforts and actually developing on your own will hamper you in the future.

Bookmark/Search this post with

About Drupal Sun

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

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

See the blog post at Evolving Web

Evolving Web