Oct 02 2015
Oct 02

cTools is one of those critical Drupal 7 modules many others depend on. It provides a lot of APIs and functionality that makes life easier when developing modules. Views and Panels are just two examples of such powerhouses that depend on it.

cTools makes available different kinds of functionality. Object caching, configuration exportability, form wizards, dialogs and plugins are but a few. A lot of the credit you would normally attribute to Views or Panels is actually owed to cTools.

Drupal logo

In this article, we are going to take a look at cTools plugins, especially how we can create our very own. After a brief introduction, we will immediately go hands on with a custom module that will use the cTools plugins to make defining Drupal blocks nicer (more in tune to how we define them in Drupal 8).

Introduction

cTools plugins in Drupal 7 (conceptually not so dissimilar to the plugin system in Drupal 8) are meant for easily defining reusable bits of functionality. That is to say, for the ability to define isolated business logic that is used in some context. The goal is to set up that context and plugin type once, and allow other modules to then define plugins that can be used in that context automatically.

If you’ve been developing Drupal sites for more than a year you’ve probably encountered cTools plugins in one shape or form. I think the first plugin type we usually deal with is the content_type plugin which allows us to create our own custom panel panes that display dynamic content. And that is awesome. Some of the others you may have encountered in the same realm of Panels are probably context and access (visibility rules). Maybe even relationships and arguments. These are all provided by cTools. Panels adds to this list by introducing layouts and styles that we normally use for creating Panels layouts and individual pane styles. These are I think the more common ones.

However, all of the above are to a certain extent a black box to many. All we know is that we need to define a hook to specify a directory and then provide an include file with some definition and logic code and the rest happens by magic. Going forward, I would like us to look into how a plugin type is defined so that if the case arises, we can create our own plugins to represent some reusable bits of functionality. To demonstrate this, we will create a module that turns the pesky hook system of defining custom Drupal blocks into a plugin based approach similar to what Drupal 8 is using.

The final code (+ a bit more) can be found in this repository if you want to follow along. And I do expect you are familiar with the steps necessary for defining custom Drupal blocks.

The block_plugin module

As I mentioned, I would like to illustrate the power of cTools plugins with a custom plugin type that makes defining Drupal 7 blocks saner. Instead of implementing the 2 main hooks (hook_block_info() and hook_block_view()) necessary to define a block, we’ll be able to have separate plugin files each responsible for all the logic related to their own block. No more switch cases and changing the hook implementation every time we need a new block. So how do we do this?

First, let’s create our block_plugin.info file to get started with our module:

name = Block Plugin
description = Using cTools plugins to define Drupal core blocks
core = 7.x
dependencies[] = ctools

Simple enough.

The plugin type

In order to define our news plugin type, inside the block_plugin.module file we need to implement hook_ctools_plugin_type() which is responsible for defining new plugin types cTools will recognize:

function block_plugin_ctools_plugin_type() {
  return array(
    'block' => array(
      'label' => 'Block',
      'use hooks' => FALSE,
      'process' => 'block_plugin_process_plugin'
    )
  );
}

In this hook we need to return an associative array of all the plugin type definitions we need keyed by the machine name of the plugin type name. Today we are only creating one called block. For more information on all the options available here, feel free to consult the plugins-creating.html help file within the cTools module. No use repeating all that information here.

The process key defines a function name that gets triggered every time cTools loads for us a plugin and is responsible for shaping or massaging the plugin data before we use it. It’s sort of a helper function that prepares the plugin for us each time so we don’t have to bother. So let’s see what we can do inside that function:

function block_plugin_process_plugin(&$plugin, $info) {
  // Add a block admin title
  if (!isset($plugin['admin title'])) {
    $exploded = explode('_', $plugin['name']);
    $name = '';
    foreach ($exploded as $part) {
      $name .= ucfirst($part) . ' ';
    }
    $plugin['admin title'] = $name;
  }

  // By default we also show a block title but this can be overwritten
  if (!isset($plugin['show title'])) {
    $plugin['show title'] = TRUE;
  }

  // Add a block view function
  if (!isset($plugin['view'])) {
    $plugin['view'] = $plugin['module'] . '_' . $plugin['name'] . '_view';
  }

  // Add a block form function
  if (!isset($plugin['configure'])) {
    $plugin['configure'] = $plugin['module'] . '_' . $plugin['name'] . '_configure';
  }

  // Add a block save function
  if (!isset($plugin['save'])) {
    $plugin['save'] = $plugin['module'] . '_' . $plugin['name'] . '_save';
  }
}

This callback receives the plugin array as a reference and some information about the plugin type. The task at hand is to either change or add data to the plugin dynamically. So what do we achieve above?

First, if the developer hasn’t defined an admin title for the block plugin, we generate one automatically based on the machine name of the plugin. This is so that we always have an admin title in the Drupal block interface.

Second, we choose to always display the title of the block so we mark the show title key of the plugin array as TRUE. When defining the block plugin, the developer has the option of setting this to FALSE in which case we won’t show a block title (subject).

Third, fourth and fifth, we generate a callback function for the block view, save and configure actions (if they haven’t already been set by the developer for a given plugin). These callbacks will be used when implementing hook_block_view(), hook_block_configure() and hook_block_save(), respectively. We won’t be covering the latter two in this article but feel free to check out the repository to see what these can look like.

And that’s pretty much all we need for defining our custom plugin type. We should, however, also implement hook_ctools_plugin_directory() which, as you may know, is responsible for telling cTools where a plugin of a certain type can be found in the current module:

function block_plugin_ctools_plugin_directory($module, $plugin) {
  if ($module == 'block_plugin' && in_array($plugin, array_keys(block_plugin_ctools_plugin_type())) ) {
    return 'plugins/' . $plugin;
  }
}

This will need to be implemented also by any other module that wants to define block plugins.

Drupal blocks

Now that we have the plugin type, let’s write the code which turns any defined block plugin into a Drupal block. Will start with the hook_block_info() implementation:

function block_plugin_block_info() {
  $blocks = array();

  $plugins = block_plugin_get_all_plugins();
  foreach ($plugins as $plugin) {
    $blocks[DELTA_PREFIX . $plugin['name']] = array(
      'info' => $plugin['admin title'],
    );
  }

  return $blocks;
}

Here we load all of the plugins using a helper function and define the minimum required information for the block. Here you can add also more information but we are keeping it simple for brevity.

We know each plugin will have a machine name (the name of the include file basically) and an admin title because we generate one in the processing phase if one doesn’t exist. The DELTA_PREFIX is a simple constant in which we define the prefix we want for the block machine name because we need to reuse it and should be able to easily change it if we want to:

define('DELTA_PREFIX', 'block_plugin_');

Our helper function we saw earlier looks like this:

function block_plugin_get_all_plugins() {
  return ctools_get_plugins('block_plugin', 'block');
}

It’s a simple wrapper around the respective cTools function. And for that matter, we also have the following function responsible for loading a single plugin by its machine name:

function block_plugin_get_plugin($name) {
  return ctools_get_plugins('block_plugin', 'block', $name);
}

This is very similar to the one before.

In order to make our Drupal block definitions complete, we need to implement hook_block_view():

function block_plugin_block_view($delta = '') {
  $plugin = block_plugin_plugin_from_delta($delta);
  if (!$plugin) {
    return;
  }

  $block = array();

  // Optional title
  if (isset($plugin['title']) && $plugin['show title'] !== FALSE) {
    $block['subject'] = $plugin['title'];
  }

  // Block content
  $block['content'] = $plugin['view']($delta);

  return $block;
}

So what’s happening here?

First, we use another helper function to try to load a plugin based on the delta of the current block and do nothing if we are not dealing with a plugin block.

Second, we build the block. If the user specified a title key on the plugin and the show title key is not false, we set the subject of the block (its title basically) as the former’s value. As for the actual block content, we simply call the view callback defined in the plugin. And that’s it.

Let us quickly see also the helper function responsible for loading a plugin based on a block delta:

function block_plugin_plugin_from_delta($delta) {
  $prefix_length = strlen(DELTA_PREFIX);
  $name = substr($delta, $prefix_length);
  $plugin = block_plugin_get_plugin($name);
  return $plugin ? $plugin : FALSE;
}

Nothing complicated going on here.

Defining block plugins

Since we told cTools that it can find block plugins inside the plugins/block folder of our module, let’s go ahead and create that folder. In it, we can add our first block inside a file with the .inc extension, for example my_block.inc:

<?php

$plugin = array(
  'title' => t('This is my block'),
);

/**
 * Returns a renderable array that represents the block content
 */
function block_plugin_my_block_view($delta) {
  return array(
    '#type' => 'markup',
    '#markup' => 'Yo block!'
  );
}

Like we do with all other plugins (content_type, context, etc), the plugin definition is in the form of an array inside a variable called $plugin. And for our case all we need at this point is a title (and not even that since without it the block simply won’t show a title).

Below it, we defined our callback function to display the block. The naming of this function is important. It matches the pattern we used for it during the processing phase (module_name_plugin_name_view). If we want to name it differently, all we have to do is reference the function name in the view key of the $plugin and it will use that one instead.

And that is basically it. We can now clear our caches and go to the Block administration screen where we can find our block and add it to a region. Showing that block on the page should trigger the view callback for that block plugin and render the contents.

Conclusion

In this article we’ve talked a bit about cTools plugins and saw how we can define our own type of plugin. We used the latter for transforming the Drupal block system into a rudimentary plugin system. This can be extended further to allow also for the block related configuration hooks to be replaced by callbacks inside the plugin include file. Additionally, as mentioned earlier, you can also make sure all the data available in hook_block_info() can be defined inside the plugin. I leave these tasks up to you.

Daniel Sipos

Meet the author

Daniel Sipos is a Drupal developer who lives in Brussels, Belgium. He works professionally with Drupal but likes to use other PHP frameworks and technologies as well. He runs webomelette.com, a Drupal blog where he writes articles and tutorials about Drupal development, theming and site building.
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.

Scaffolding

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') {
    return NODE_ACCESS_IGNORE;
  }

  $allowed_uids = editor_list_uids_from_list($node);

  if (empty($allowed_uids)) {
    return NODE_ACCESS_IGNORE;
  }

  if (in_array($account->uid, $allowed_uids)) {
    return NODE_ACCESS_ALLOW;
  }
}

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') {
    return;
  }

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

  $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.

Conclusion

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.

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.

logo_drupal

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:

<?php

/**
* 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) {
        db_delete('likepost_table_for_likes')
        ->condition('userid', $user->uid)
        ->condition('nodeid', $nodeid)
        ->execute();
        //Update the like value , which will be sent as response
        $like = 0;
    } else {
        db_insert('likepost_table_for_likes')
        ->fields(array(
        'userid' => $user->uid,
        'nodeid' => $nodeid
        ))
        ->execute();
        //Update the like value , which will be sent as response
        $like = 1;
    }

    $total_count = likepost_get_total_like($nodeid);
    drupal_json_output(array(
        '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 {
    color:red;
}

.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 () {
        jQuery.ajax({
            type: 'POST', 
            url: this.href,
            dataType: 'json',
            success: function (data) {
                if(data.like_status == 0) {
                    jQuery('a.like-link').html('Like');
                }
                else {
                    jQuery('a.like-link').html('Delete Like');
                }

                jQuery('.total_count').html(data.total_count);
            },
            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

Conclusion

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!

Apr 10 2015
Apr 10

A Silex and Elasticsearch app powered by Drupal 7 for content management

In the previous article I started exploring the integration between Drupal 7 and the Elasticsearch engine. The goal was to see how we can combine these open source technologies to achieve a high performance application that uses the best of both worlds. If you’re just now joining us, you should check out this repository which contains relevant code for these articles.

esdrupalsilex

We’ll now create a small Silex application that reads data straight from Elasticsearch and returns it to the user.

Silex app

Silex is a great PHP micro framework developed by the same people that are behind the Symfony project. It is in fact using mainly Symfony components but at a more simplified level. Let’s see how we can get started really quickly with a Silex app.

There is more than one way. You can add it as a dependency to an existent composer based project:

"silex/silex": "~1.2",

Or you can even create a new project using a nice little skeleton provided by the creator:

composer.phar create-project fabpot/silex-skeleton

Regardless of how your project is set up, in order to access Elasticsearch we’ll need to use its PHP SDK. That needs to be added to Composer:

"elasticsearch/elasticsearch": "~1.0",

And if we want to use Twig to output data, we’ll need this as well (if not already there of course):

"symfony/twig-bridge": "~2.3"

In order to use the SDK, we can expose it as a service to Pimple, the tiny Silex dependency injection container (much easier than it sounds). Depending on how our project is set up, we can do this in a number of places (see the repository for an example). But basically, after we instantiate the new Silex application, we can add the following:

$app['elasticsearch'] = function() {
  return new Client(array());
};

This creates a new service called elasticsearch on our app that instantiates an object of the Elasticsearch Client class. And don’t forget we need to use that class at the top:

use Elasticsearch\Client;

Now, wherever we want, we can get the Elasticsearch client by simply referring to that property in the $app object:

$client = $app['elasticsearch'];

Connecting to Elasticsearch

In the previous article we’ve managed to get our node data into the node index with each node type giving the name of an Elasticsearch document type. So for instance, this will return all the article node types:

http://localhost:9200/node/article/_search

We’ve also seen how to instantiate a client for our Elasticsearch SDK. Now it’s time to use it somehow. One way is to create a controller:

<?php

namespace Controller;

use Silex\Application;
use Symfony\Component\HttpFoundation\Response;

class NodeController {

  /**
   * Shows a listing of nodes.
   *
   * @return \Symfony\Component\HttpFoundation\Response
   */
  public function index() {
    return new Response('Here there should be a listing of nodes...');
  }
  
  /**
   * Shows one node
   *
   * @param $nid
   * @param \Silex\Application $app
   * @return mixed
   */
  public function show($nid, Application $app) {
    $client = $app['elasticsearch'];
    $params = array(
      'index' => 'node',
      'body' => array(
        'query' => array(
          'match' => array(
            'nid' => $nid,
          ),
        ),
      )
    );
    
    $result = $client->search($params);
    if ($result && $result['hits']['total'] === 0) {
      $app->abort(404, sprintf('Node %s does not exist.', $nid));
    }
    
    if ($result['hits']['total'] === 1) {
      $node = $result['hits']['hits'];
      return $app['twig']->render('node.html.twig', array('node' => reset($node)));
    }
  }
}

Depending on how you organise your Silex application, there are a number of places this controller class can go. In my case it resides inside the src/Controller folder and it’s autoloaded by Composer.

We also need to create a route that maps to this Controller though. Again, there are a couple of different ways to handle this but in my example I have a routes.php file located inside the src/ folder and required inside index.php:

<?php

use Symfony\Component\HttpFoundation\Response;

/**
 * Error handler
 */
$app->error(function (\Exception $e, $code) {
  switch ($code) {
    case 404:
      $message = $e->getMessage();
      break;
    default:
      $message = 'We are sorry, but something went terribly wrong. ' . $e->getMessage();
  }

  return new Response($message);
});

/**
 * Route for /node
 */
$app->get("/node", "Controller\\NodeController::index");

/**
 * Route /node/{nid} where {nid} is a node id
 */
$app->get("/node/{nid}", "Controller\\NodeController::show");

So what happens in my example above? First, I defined an error handler for the application, just so I can see the exceptions being caught and print them on the screen. Not a big deal. Next, I defined two routes that map to my two controller methods defined before. But for the sake of brevity, I only exemplified what the prospective show() method might do:

  • Get the Elasticsearch client
  • Build the Elasticsearch query parameters (similar to what we did in the Drupal environment)
  • Perform the query
  • Check for the results and if a node was found, render it with a Twig template and pass the node data to it.
  • If no results are found, abort the process with a 404 that calls our error handler for this HTTP code declared above.

If you want to follow this example, keep in mind that to use Twig you’ll need to register it with your application. It’s not so difficult if you have it already in your vendor folder through composer.

After you instantiate the Silex app, you can register the provider:

$app->register(new TwigServiceProvider());

Make sure you use the class at the top:

use Silex\Provider\TwigServiceProvider;

And add it as a service with some basic configuration:

$app['twig'] = $app->share($app->extend('twig', function ($twig, $app) {
  return $twig;
}));
$app['twig.path'] = array(__DIR__.'/../templates');

Now you can create template files inside the templates/ folder of your application. For learning more about setting up a Silex application, I do encourage you to read this introduction to the framework.

To continue with our controller example though, here we have a couple of template files that output the node data.

Inside a page.html.twig file:

        <!DOCTYPE html>
        <html>
        <head>
            {% block head %}
                <title>{% block title %}{% endblock %} - My Elasticsearch Site</title>
            {% endblock %}
        </head>
        <body>
        <div id="content">{% block content %}{% endblock %}</div>
        </body>
        </html>

And inside the node.html.twig file we used in the controller for rendering:

{% extends "page.html.twig" %}

{% block title %}{{ node._source.title }}{% endblock %}

{% block content %}

    <article>
        <h1>{{ node._source.title }}</h1>

        <div id="content">

            {% if node._source.field_image %}
                <div class="field-image">
                    {% for image in node._source.field_image %}
                        <img src="http://www.sitepoint.com/integrate-elasticsearch-silex//{{ image.url }}" alt="img.alt"/>
                    {% endfor %}
                </div>
            {% endif %}

            {% if node._source.body %}
                <div class="field-body">
                    {% for body in node._source.body %}
                        {{ body.value|striptags('<p><div><br><img><a>')|raw }}
                    {% endfor %}
                </div>
            {% endif %}
        </div>
    </article>


{% endblock %}

This is just some basic templating for getting our node data printed in the browser (not so fun otherwise). We have a base file and one that extends it and outputs the node title, images and body text to the screen.

Alternatively, you can also return a JSON response from your controller with the help of the JsonResponse class:

use Symfony\Component\HttpFoundation\JsonResponse;

And from your controller simply return a new instance with the values passed to it:

return new JsonResponse($node);

You can easily build an API like this. But for now, this should already work. By pointing your browser to http://localhost/node/5 you should see data from Drupal’s node 5 (if you have it). With one big difference: it is much much faster. There is no bootstrapping, theming layer, database query etc. On the other hand, you don’t have anything useful either out of the box except for what you build yourself using Silex/Symfony components. This can be a good thing or a bad thing depending on the type of project you are working on. But the point is you have the option of drawing some lines for this integration and decide its extent.

One end of the spectrum could be building your entire front end with Twig or even Angular.js with Silex as the API backend. The other would be to use Silex/Elasticsearch for one Drupal page and use it only for better content search. Somewhere in the middle would probably be using such a solution for an entire section of a Drupal site that is dedicated to interacting with heavy data (like a video store or something). It’s up to you.

Conclusion

We’ve seen in this article how we can quickly set up a Silex app and use it to return some data from Elasticsearch. The goal was not so much to learn how any of these technologies work, but more of exploring the options for integrating them. The starting point was the Drupal website which can act as a perfect content management system that scales highly if built properly. Data managed there can be dumped into a high performance data store powered by Elasticsearch and retrieved again for the end users with the help of Silex, a lean and fast PHP framework.

Apr 03 2015
Apr 03

A Silex and Elasticsearch app powered by Drupal 7 for content management

In this tutorial I am going to look at the possibility of using Drupal 7 as a content management system that powers another high performance application. To illustrate the latter, I will use the Silex PHP microframework and Elasticsearch as the data source. The goal is to create a proof of concept, demonstrating using these three technologies together.

esdrupalsilex

The article comes with a git repository that you should check out, which contains more complete code than can be presented in the tutorial itself. Additionally, if you are unfamiliar with either of the three open source projects being used, I recommend following the links above and also checking out the documentation on their respective websites.

The tutorial will be split into two pieces, because there is quite a lot of ground to cover.

In this part, we’ll set up Elasticsearch on the server and integrate it with Drupal by creating a small, custom module that will insert, update, and delete Drupal nodes into Elasticsearch.

In the second part, we’ll create a small Silex app that fetches and displays the node data directly from Elasticsearch, completely bypassing the Drupal installation.

Elasticsearch

The first step is to install Elasticsearch on the server. Assuming you are using Linux, you can follow this guide and set it up to run when the server starts. There are a number of configuration options you can set here.

A very important thing to remember is that Elasticsearch has no access control so, once it is running on your server, it is publicly accessible through the (default) 9200 port. To avoid having problems, make sure that in the configuration file you uncomment this line:

network.bind_host: localhost

And add the following one:

script.disable_dynamic: true

These options make sure that Elasticsearch is not accessible from the outside, nor are dynamic scripts allowed. These are recommended security measures you need to take.

Drupal

The next step is to set up the Drupal site on the same server. Using the Elasticsearch Connector Drupal module, you can get some integration with the Elasticsearch instance: it comes with the PHP SDK for Elasticsearch, some statistics about the Elasticsearch instance and some other helpful submodules. I’ll leave it up to you to explore those at your leisure.

Once the connector module is enabled, in your custom module you can retrieve the Elasticsearch client object wrapper to access data:

$client = elastic_connector_get_client_by_id('my_cluster_id');

Here, my_cluster_id is the Drupal machine name that you gave to the Elasticsearch cluster (at admin/config/elasticsearch-connector/clusters). The $client object will now allow you to perform all sorts of operations, as illustrated in the docs I referenced above.

Inserting data

The first thing we need to do is make sure we insert some Drupal data into Elasticsearch. Sticking to nodes for now, we can write a hook_node_insert() implementation that will save every new node to Elasticsearch. Here’s an example, inside a custom module called elastic:

/**
 * Implements hook_node_insert().
 */
function elastic_node_insert($node) {
  $client = elasticsearch_connector_get_client_by_id('my_cluster_id');
  $params = _elastic_prepare_node($node);

  if ( ! $params) {
    drupal_set_message(t('There was a problem saving this node to Elasticsearch.'));
    return;
  }

  $result = $client->index($params);
  if ($result && $result['created'] === false) {
    drupal_set_message(t('There was a problem saving this node to Elasticsearch.'));
    return;
  }

  drupal_set_message(t('The node has been saved to Elasticsearch.'));
}

As you can see, we instantiate a client object that we use to index the data from the node. You may be wondering what _elastic_prepare_node() is:

/**
 * Prepares a node to be added to Elasticsearch
 *
 * @param $node
 * @return array
 */
function _elastic_prepare_node($node) {

  if ( ! is_object($node)) {
    return;
  }

  $params = array(
    'index' => 'node',
    'type' => $node->type,
    'body' => array(),
  );

  // Add the simple properties
  $wanted = array('vid', 'uid', 'title', 'log', 'status', 'comment', 'promote', 'sticky', 'nid', 'type', 'language', 'created', 'changed', 'revision_timestamp', 'revision_uid');
  $exist = array_filter($wanted, function($property) use($node) {
    return property_exists($node, $property);
  });
  foreach ($exist as $field) {
    $params['body'][$field] = $node->{$field};
  }

  // Add the body field if exists
  $body_field = isset($node->body) ? field_get_items('node', $node, 'body') : false;
  if ($body_field) {
    $params['body']['body'] = $body_field;
  }

  // Add the image field if exists
  $image_field = isset($node->field_image) ? field_get_items('node', $node, 'field_image') : false;
  if ($image_field) {
    $params['body']['field_image'] = array_map(function($img) {
      $img = file_load($img['fid']);
      $img->url = file_create_url($img->uri);
      return $img;
    }, $image_field);
  }

  return $params;
}

It is just a helper function I wrote, which is responsible for “serializing” the node data and getting it ready for insertion into Elasticsearch. This is just an example and definitely not a complete or fully scalable one. It is also assuming that the respective image field name is field_image. An important point to note is that we are inserting the nodes into the node index with a type = $node->type.

Updating data

Inserting is not enough, we need to make sure that node changes get reflected in Elasticsearch as well. We can do this with a hook_node_update() implementation:

/**
 * Implements hook_node_update().
 */
function elastic_node_update($node) {
  if ($node->is_new !== false) {
    return;
  }

  $client = elasticsearch_connector_get_client_by_id('my_cluster_id');
  $params = _elastic_prepare_node($node);

  if ( ! $params) {
    drupal_set_message(t('There was a problem updating this node in Elasticsearch.'));
    return;
  }

  $result = _elastic_perform_node_search_by_id($client, $node);
  if ($result && $result['hits']['total'] !== 1) {
    drupal_set_message(t('There was a problem updating this node in Elasticsearch.'));
    return;
  }

  $params['id'] = $result['hits']['hits'][0]['_id'];
  $version = $result['hits']['hits'][0]['_version'];
  $index = $client->index($params);

  if ($index['_version'] !== $version + 1) {
    drupal_set_message(t('There was a problem updating this node in Elasticsearch.'));
    return;
  }
  
  drupal_set_message(t('The node has been updated in Elasticsearch.'));
}

We again use the helper function to prepare our node for insertion, but this time we also search for the node in Elasticsearch to make sure we are updating and not creating a new one. This happens using another helper function I wrote as an example:

/**
 * Helper function that returns a node from Elasticsearch by its nid.
 *
 * @param $client
 * @param $node
 * @return mixed
 */
function _elastic_perform_node_search_by_id($client, $node) {
  $search = array(
    'index' => 'node',
    'type' => $node->type,
    'version' => true,
    'body' => array(
      'query' => array(
        'match' => array(
          'nid' => $node->nid,
        ),
      ),
    ),
  );

  return $client->search($search);
}

You’ll notice that I am asking Elasticsearch to return the document version as well. This is so that I can check if a document has been updated with my request.

Deleting data

The last (for now) feature we need is the ability to remove the data from Elasticsearch when a node gets deleted. hook_node_delete() can help us with that:

/**
 * Implements hook_node_delete().
 */
function elastic_node_delete($node) {
  $client = elasticsearch_connector_get_client_by_id('my_cluster_id');

  // If the node is in Elasticsearch, remove it
  $result = _elastic_perform_node_search_by_id($client, $node);
  if ($result && $result['hits']['total'] !== 1) {
    drupal_set_message(t('There was a problem deleting this node in Elasticsearch.'));
    return;
  }

  $params = array(
    'index' => 'node',
    'type' => $node->type,
    'id' => $result['hits']['hits'][0]['_id'],
  );

  $result = $client->delete($params);
  if ($result && $result['found'] !== true) {
    drupal_set_message(t('There was a problem deleting this node in Elasticsearch.'));
    return;
  }

  drupal_set_message(t('The node has been deleted in Elasticsearch.'));
}

Again, we search for the node in Elasticsearch and use the returned ID as a marker to delete the document.

Please keep in mind though that using early returns such as illustrated above is not ideal inside Drupal hook implementations unless this is more or less all the functionality that needs to go in them. I recommend splitting the logic into helper functions if you need to perform other unrelated tasks inside these hooks.

This is enough to get us started using Elasticsearch as a very simple data source on top of Drupal. With this basic code in place, you can navigate to your Drupal site and start creating some nodes, updating them and deleting them.

One way to check if Elasticsearch actually gets populated, is to disable the remote access restriction I mentioned above you need to enable. Make sure you only do this on your local, development, environment. This way, you can perform HTTP requests directly from the browser and get JSON data back from Elasticsearch.

You can do a quick search for all the nodes in Elasticsearch by navigating to this URL:

http://localhost:9200/node/_search

…where localhost points to your local server and 9200 is the default Elasticsearch port.

For article nodes only:

http://localhost:9200/node/article/_search

And for individual articles, by the auto generated Elasticsearch ids:

http://localhost:9200/node/article/AUnJgdPGGE7A1g9FtqdV

Go ahead and check out the Elasticsearch documentation for all the amazing ways you can interact with it.

Conclusion

We’ve seen in this article how we can start working to integrate Elasticsearch with Drupal. Obviously, there is far more we can do based on even the small things we’ve accomplished. We can extend the integration to other entities and even Drupal configuration if needed. In any case, we now have some Drupal data in Elasticsearch, ready to be used from an external application.

That external application will be the task for the second part of this tutorial. We’ll be setting up a small Silex app that, using the Elasticsearch PHP SDK, will read the Drupal data directly from Elasticsearch. As with part 1, above, we won’t be going through a step-by-step tutorial on accomplishing a given task, but instead will explore one of the ways that you can start building this integration. See you there.

Mar 20 2015
Mar 20

Not so long ago, many of us were satisfied handling deployment of our projects by uploading files via FTP to a web server. I was doing it myself until relatively recently and still do on occasion (don’t tell anyone!). At some point in the past few years, demand for the services and features offered by web applications rose, team sizes grew and rapid iteration became the norm. The old methods for deploying became unstable, unreliable and (generally) untrusted.

So was born a new wave of tools, services and workflows designed to simplify the process of deploying complex web applications, along with a plethora of accompanying commercial services. Generally, they offer an integrated toolset for version control, hosting, performance and security at a competitive price.

Platform.sh is a newer player on the market, built by the team at Commerce Guys, who are better known for their Drupal eCommerce solutions. Initially, the service only supported Drupal based hosting and deployment, but it has rapidly added support for Symfony, WordPress, Zend and ‘pure’ PHP, with node.js, Python and Ruby coming soon.

It follows the microservice architecture concept and offers an increasing amount of server, performance and profiling options to add and remove from your application stack with ease.

I tend to find these services make far more sense with a simple example. I will use a Drupal platform as it’s what I’m most familiar with.

Platform.sh has a couple of requirements that vary for each platform. In Drupal’s case they are:

  • An id_rsa public/private key pair
  • Git
  • Composer
  • The Platform.sh CLI
  • Drush

I won’t cover installing these here; more details can be found in the Platform.sh documentation section.

I had a couple of test platforms created for me by the Platform.sh team, and for the sake of this example, we can treat these as my workplace adding me to some new projects I need to work on. I can see these listed by issuing the platform project:list command inside my preferred working directory.

Platform list

Get a local copy of a platform by using the platform get ID command (The IDs are listed in the table we saw above).

This will download the relevant code base and perform some build tasks, any extra information you need to know is presented in the terminal window. Once this is complete, you will have the following folder structure:

Folder structure from build

The repository folder is your code base and here is where you make and commit changes. In Drupal’s case, this is where you will add modules, themes and libraries.

The build folder contains the builds of your project, that is the combination of drupal core, plus any changes you make in the repository folder.

The shared folder contains your local settings and files/folders, relevant to just your development copy.

Last is the www symlink, which will always reference the current build. This would be the DOCROOT of your vhost or equivalent file.

Getting your site up and running

Drupal is still dependent on having a database present to get started, so if we need it we can get the database from the platform we want by issuing:

platform drush sql-dump > d7.sql

Then we can import the database into our local machine and update the credentials in shared/settings.local.php accordingly.

Voila! We’re up and working!

Let’s start developing

Let’s do something simple: add the views and features modules. Platform.sh is using Drush make files, so it’s a different process from what you might be used to. Open the project.make file and add the relevant entry to it. In our case, it’s:

projects[ctools][version] = "1.6"
projects[ctools][subdir] = "contrib"

projects[views][version] = "3.7"
projects[views][subdir] = "contrib"

projects[features][version] = "2.3"
projects[features][subdir] = "contrib"

projects[devel][version] = "1.5"
projects[devel][subdir] = "contrib"

Here, we are setting the projects we want to include, the specific versions and what subfolder of the modules folder we want them placed into.

Rebuild the platform with platform build. You should notice the devel, ctools, features and views module downloaded, and we can confirm this by making a quick visit to the modules page:

Modules list page in Drupal

You will notice that each time we issue the build command, a new version of our site is created in the builds folder. This is perfect for quickly reverting to an earlier version of our project in case something goes wrong.

Now, let’s take a typical Drupal development path, create a view and add it to a feature for sharing amongst our team. Enable all the modules we have just added and generate some dummy content with the Devel Generate feature, either through Drush or the module page.

Now, create a page view that shows all content on the site:

Add it to a feature:

Uncompress the archive created and add it into the repository -> modules folder. Commit and push this folder to version control. Now any other team member running the platform build command will receive all the updates they need to get straight into work.

You can then follow your normal processes for getting modules, feature and theme changes applied to local sites such as update hooks or profile based development.

What else can Platform.sh do?

This simplifies the development process amongst teams, but what else does Platform.sh offer to make it more compelling than other similar options?

If you are an agency or freelancer that works on multiple project types, the broader CMS/Framework/Language support, all hosted in the same place and with unified version control and backups, is a compelling reason.

With regards to version control, platform.sh provides a visual management and record of your git commits and branches, which I always find useful for reviewing code and status of a project. Apart from this, you can create snapshots of your project, including code and database, at any point.

When you are ready to push your site live, it’s simple to allocate DNS and domains all from the project configuration pages.

Performance, Profiling and other Goodies

By default, your projects have access to integration with Redis, Solr and EntityCache / AuthCache. It’s just a case of installing the relevant Drupal modules and pointing them to the built-in server details.

For profiling, Platform.sh has just added support for Sensiolabs Blackfire, all you need to do is install the browser companion, add your credentials, create an account and you’re good to go.

Backups are included by default as well as the ability to restore from backups.

Team members can be allocated permissions at project levels and environment levels, allowing for easy transitioning of team members across projects and the roles they undertake in each one.

Platform.sh offers some compelling features over it’s closest competition (Pantheon and Acquia) and pricing is competitive. The main decision to be made with all of these SaaS offerings is if the restricted server access and ‘way of doing things’ is a help or a hindrance to your team and its workflows. I would love to know your experiences or thoughts in the comments below.

Mar 07 2015
Mar 07

Previously we read how to be a webmaster at drupal.org , Now I became the git administer at drupal.org. So I think to write a blog post so that others can benefit and also get to know how to become git administer.

In simple words: "Start Contributing". Git Administer privileges are granted to the users with proven record of contributions in the Project Applications issue queue. A solid history of consistent contributions on drupal.org is a must to get consideration for an elevated role.

How to start contributing & where you can contribute :

  1. Join the code review group
  2. Read How to review full project applications
  3. Some helpful tools for reviewing :
  4. Learning Sources : 
  5. if you found any problem while contributing,just comment on the below post/ if you need immediate answer you can try and find one of the git administer on IRC - #drupal-codereview IRC channel on Freenode.

Benifits of becoming git administer :

  1. You will see a new challenging case in every new project application.
  2. Your drupal apis knowledge will become sharp.
  3. Many more....

I would encourage you to learn more about that process and join the group of reviewers.
Next article:  A guide to review project applications
Feb 23 2015
Feb 23

Security of the Drupal website is a important stuff for the site owners, site developers.This blog post has my presentation at the Drupal Camp Mumbai that  intended for Drupalers who want to avoid security loop holes while writing code or architecting solutions. We delved into common security issues that ails custom code and has both vulnerable and secure code snippets.This is mostly about my encounters and experience after doing 50+ project application reviews and also a good guideline for new contributors.

[embedded content]

Hack Proof Your Drupal Site from Naveen Valecha

Next article:  A guide to review Project Applications.


Jan 23 2015
Jan 23

Was looking out some good English Speaking training course website for my cousinto become a fluent English speaker.


On opening the homepage I found the section "Free trial".

I did the same thing as all guys do.Click on the Free trial link,created my account.I personally feeling happy to get the 5 free audio English lessons.
I clicked on one of my lessons link and come to the page, found the download link of the audio file.



Copied and pasted the url in the browser and the downloaded the file. https://www.dailystep.com/en/download/file/fid/13531 Just change the fid in the url and tried to download some random file with file id. I thought what the Shit!   I then look around which drupal module has provided this route.After checking I got to know that this is the download file module which provides this route.After checking I assume that it might be permission stuff problem.
I found the similar permission problem on the drupal.org as well https://www.drupal.org/node/2394993
Trust is the Major Strategy in Security of any web application.We should be sure which user role we should assign which permissions.
Note: Published the post after suggesting the fix to the site owner Jane
Dec 15 2014
Dec 15

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

logo_drupal

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

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

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

Ingredients

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

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

The module

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  return $blocks;
}

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

  $block = array();

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

  return $block;
}

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

There are four simple functions here:

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

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

        <div ng-app="nodeListing">
        
           <div ng-controller="ListController">
        
             <h3>Filter</h3>
             <input ng-model="search" ng-change="doSearch()">
        
              <ul>
                <li ng-repeat="node in nodes"><button ng-click="open(node.nid)">Open</button> {{ node.title }}</li>
              </ul>
        
             <script type="text/ng-template" id="loadedNodeTemplate">
             <h3>{{ loadedNode.title }}</h3>
             {{ loadedNode.body }}
             </script>
        
            </div>
        
        </div>

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

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

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

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

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

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

}]);

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

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

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

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

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

Conclusion

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

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

Aug 18 2014
Aug 18

In this article, we’ll discuss how you can leverage various Drupal API functions to achieve more fine grained theming. We’ll cover template preprocessing and alter hooks using path patterns, types and args(). We’ll use the arg() function which returns parts of a current Drupal URL path and some pattern matching for instances when you want to match a pattern in a URL. We’ll also take a look at creating a variable for an array of content types.

Template preprocessing is a means to define variables for use within your page. For example, you can define a body class variable. In turn you can use the resulting class in your Sass or CSS. An alter or build hook is something that’s run before the page renders so you can do things such as adding JS or CSS to specific pages or content types.

I’ll explain and demonstrate these hooks and how you can use them to:

  • Add a <body> class to a specific page for better theming
  • Add Javascript or CSS to specific pages and paths
  • Use wildcard path arguments
  • URL pattern matching using preg_match
  • Create an array of content types to use as a variable in your argument
  • Using path arguments as parameters

The functions we discuss here will be added to your theme’s template.php file. Although you can also use these functions in a custom module, you’ll need to specify that the functions are not for admin pages unless that’s your intent, and I’ll cover how to do that.

Getting Started

When using preprocess or alter functions within your theme, you’ll want to be sure template.php exists but if not, you can go ahead and create this file in the root of your theme. So if my theme name is foobar, the path to template.php will be:

/sites/all/themes/foobar/template.php

API functions are prefaced by the machine name of your theme. For example, if you are using hook_page_alter and your theme name is foobar, we’d write it as function foobar_page_alter(). (The machine name is simply the theme’s folder name.)

Custom Body Classes Using a Content Types Array

A body class is a class that’s added to your HTML <body> tag. For example, on a blog page, you might see something like this:

<body class="page-node page-node-blog">

You can leverage that class in your Sass or CSS to fine tune your theming by doing something like this just for blog pages on your site:

.page-node-blog h1 {
// custom Sass here
}

Out of the box, Drupal 7 comes with some pretty good body classes and usually these are fine for most use cases. In addition, Drupal contribution or Contrib themes such as Zen add enhanced and expanded classes.

In our case, we want to add a class to some pages which share some common attributes but may not necessarily derive from the same content type. Let’s say we have two content types that we want to add a specific class to in order to theme those alike but perhaps different from other pages on our website. We can build an array of Drupal content types we want to target and then use that array to add the class. Once we’ve defined the array, we just check to ensure that a given node exists and then pass the array in.

<?php

/**
 * Implements template_preprocess_html().
 *
 * Define custom classes for theming.
 */
function foobar_preprocess_html(&$vars) {

  // Build a node types array from our targeted content types.
  $foo_types = array(
    'landing_page',
    'our_services',
  );

    // Define the node.
    $node = menu_get_object();
  
  // Use the array to add a class to those content types.
  if (!empty($node) && in_array($node->type, $foo_types)) {
    $vars['classes_array'][] = 'page-style-foobar';
    }
  }

This function preprocesses variables for anything that would typically be before the ending HTML </head> tag which is in Drupal’s core template, html.tpl.php. We add the body class using $vars['classes_array']. This variable gets rendered with <?php print $classes; ?> in the <body> tag. In our case, this class will only render in landing_page and our_services content types. Now we can use .page-style-foobar in our Sass or CSS to style these pages.

URL Pattern Matching

You can also use URL pattern matching for adding useful custom classes. Let’s say we have an “Our Services” landing page and then some sub-pages under that path. The URL architecture might look like this:

example.com/our-services
- example.com/our-services/subpage-1
- example.com/our-services/subpage-2

We’ll add a custom body class to those pages using preg_match, regex, PHP matches and Drupal’s request_uri function. Once again, we’d put this in a foobar_preprocess_html as above.

 <?php
function foobar_preprocess_html(&$vars) {

  // Define the URL path.
  $path = request_uri();

  // Add body classes to various pages for better theming.
  if (preg_match('|^/our-services((?:/[a-zA-Z0-9_\-]*)*)?|', $path, $matches)) {
    $vars['classes_array'][] = 'page-services';
  }
}

Now you can use .page-services .some-common-element for theming these “our-services” pages. Obviously this method has pitfalls if your URL structure changes so it may only fit some use cases.

Path Arguments

Another clever way of custom theming specific parts of your site is to partition those off using arg(). Drupal tends to get script and CSS heavy so ideally if you’re adding extra CSS or JS and you don’t need it for every page (which is normally done using your theme’s .info file), you can use path arg() to add these only to pages where they’re needed. For example, if I want to add a custom script to just the Drupal registration page, I can create a path arg() if statement and then add the script within that. The URL path we’ll focus on here is /user/register and you’ll see how the arg() breaks down the URL structure.

We’ll be using hook_page_alter here which can apply alterations to a page before it’s rendered. First we define the theme path and use Drupal’s attached function.

<?php

/**
 * Implements hook_page_alter().
 *
 * Add custom functions such as adding js or css.
 */
function foobar_page_alter(&$page, $form) {

  // Define the module path for use below.
  $theme_path = drupal_get_path('theme', 'foobar');

  if (arg(0) == "user" && arg(1) == "register") {
     $foobar_js = array(
      '#attached' => array(
        'js' => array(
          $theme_path . '/js/custom.js' => array(
            'group' => JS_THEME,
          ),
        ),
      ),
    );
    drupal_render($foobar_js);
  
  }
}

In this function, note that we’ve substituted our theme name for hook so hook_page_alter becomes foobar_page_alter. The arg() number signifies the position in the URL path. Zero is first, one is second and so on. You can get pretty creative with these adding more parameters. Let’s say you wanted to add JS to just the user page but no paths underneath it. You could add a NULL arg() after the initial arg().

if (arg(0) == "user" && arg(1) == NULL) {
// code here
}

In the examples above, we’ve implemented various functions in our theme’s template.php file. You can also use these in a custom module as well and in that case you’d just preface your module name in the function rather than the theme name. When theming from a module, you’ll probably want to exclude admin paths since a module can target anywhere in your site. You can do that excluding admin paths.

if (!path_is_admin(current_path())) {
// code here
}

Conclusion

As you can see, leveraging the Drupal API Toolbox for theming extends your reach as a developer. The examples above are not definitive but they do give you a feel for what’s possible. As a Drupal Themer, using these has helped me expand my bag of tricks when theming and building a site. Comments? Feedback? Leave them below!

Resources

Jun 23 2014
Jun 23

In this article we will continue exploring the powers of Views and focus on how to use relationships, contextual filters and rewrite field outputs. In a previous tutorial I showed you how to create a new View and perform basic customizations for it. We’ve seen how to select a display format, which fields to show and how to filter and sort the results.

In this article we will go a bit further and see what relationships and contextual filters are – the two most important options found under the Advanced fieldset at the right of the View edit page. Additionally, we’ll rewrite the output of our fields and combine their values into one.

To begin with, I have a simple article View that just shows the titles. Very easy to set up if you want to follow along. And there are three things I want to achieve going forward:

  1. Make it so that the View shows also the username of the article author
  2. Make is so that the View shows only articles authored by the logged in user
  3. Make it so that the author username shows up in parenthesis after the title

Relationships

First, let’s have the View include the author of the articles. If the View is displaying fields (rather than view modes or anything else), all we have to do is find the field with the author username, right? Wrong. The problem is the following: the node table only contains a reference to the user entity that created the node (in the form of a user ID – uid). So that’s pretty much all we will find if we look for user related fields: Content: Author uid.

What we need to do is use a relationship to the user entity found in the user table. Relationships are basically a fancy way of saying that table A (in our case node) will join with table B (in our case user) in order to retrieve data related to it from there (such as the name of the user and many others). And the join will happen in our case on the uid field which will match in both tables.

So let’s go ahead and add a new relationship of the type Content: Author. Under Identifier, we can put a descriptive name for this relationship like Content Author. The rest we can leave as default.

Now if you go and add a new field, you’ll notice many others that relate to the user who authored the content. Go ahead and add the User: Name field. In its settings, you’ll see a Relationship select list at the top where the relationship identifier we just specified is automatically selected. That means this field is being pulled in using that relationship (or table join). Saving the field will now add the username of the author, already visible in the View preview.

relationships

You can also chain relationships. For instance, if the user entity has a reference to another table using a unique identifier, you can add a second relationship. It will use the first one and bring in fields from that table. So the end result will be that the View will show fields that relate to the node through the user who authored the node but not strictly from the user table but somewhere else connected to the author. And on and on you can join tables like this.

Contextual filters

Contextual filters are similar to regular filters in that you can use mainly the same fields to filter the records on. Where contextual filters differ greatly is that you do not set the filtering value when you create the View, but it is taken from context.

There are many different contexts a filter value can come from, but mainly it comes from the URL. However, you can instruct Views to look elsewhere for contexts as well – such as the ID of the logged in user.

What we’ll do now is add a contextual filter so that the View shows only the articles authored by the logged in user. So go ahead and add a new contextual filter of the type Content: Author uid. Next, under the WHEN THE FILTER VALUE IS NOT IN THE URL fieldset, select the Provide default value radio. Our goal here is to have Views look elsewhere if it does not find the user ID in the URL.

contextual filters

You then have some options under the Type select list, where you should choose User ID from logged in user. This will make Views take the ID of the user that is logged in and pass it to the View as a filter. The rest you can leave as is and save the filter. You’ll immediately notice in your preview that only articles authored by you show up. The filtering is taking place dynamically. If you log in with another user account, you should see only the articles authored by that user account.

A great thing about contextual filters is that if you are displaying a View programatically in a custom module, you can pass the filtering value in code, which opens the door to many possibilities.

Rewriting fields

The last thing we will do in this tutorial is look at rewriting fields in order to concatenate their values. We will illustrate this technique by changing the title field to include the author username in parenthesis.

We’ll start by rearranging the order of the fields and move the title to be the last one showing. The reason we want to do this is that when you rewrite fields, you can use tokens that get values only from fields that are added before the one being rewritten. And since we want to rewrite the title field, we want the token for the username value to be present so we need to move it before the title field.

Now that the title field is last, edit the author username field and uncheck the box Create a label and then check the box Exclude from display. You can now save the field. The reason we are excluding this field from being displayed in our View is so that we don’t duplicate it once we concatenate it to the title field.

rewriting fields

Next, edit the title field and under REWRITE RESULTS, check the box Rewrite the output of this field. A new textarea should appear below where we will write the new contents of this field. If you write some gibberish in there and save the field, you’ll notice the title gets replaced by that gibberish.

Below this textarea, you’ll notice also some REPLACEMENT PATTERNS. These represent tokens of all the fields in the View loaded before this one (and including this one as well). So if you followed along, you’ll see there [name] and [title], among others.

What we need to do now is put these tokens in this box, wrapped with the text or markup we want. Having said that we want the username to be in parenthesis after the node title, we can add the following to the text box to achieve this:

[title] ([name])

Save the field and check out the result. Now you should have the author user in parenthesis. However, it’s still not perfect. We left the title field’s Link this field to the original piece of content box checked and this is breaking the output for us a bit due to also the username having a link to the user profile page. What we want is a clean link to the node title and in parenthesis (which themselves do not link to anything), the username linking to the user profile page.

So first up, add a new field called Content: Path (the path to the node). Make sure you exclude it from display, remove its label and move it before the title field. Then, edit the title field, uncheck the Link this field to the original piece of content box and replace the REWRITE RESULTS text with this:

 href="[path]">[title] ([name])

The [path] token is available from the new field we just added. And after you save, you should see already in the preview a much cleaner display of title nodes and usernames in parenthesis.

Conclusion

In this tutorial we’ve looked at three main aspects of building Views in Drupal 7: relationships, contextual filters and rewriting fields. We’ve seen how with the use of relationships we can use information also from related entities, not just those on the base table a View is built on. Contextual filters are great for when the View needs to display content dynamically depending on various contextual conditions (such as a URL or logged-in user). Lastly, we’ve learned how to rewrite fields and build more complex ones with values taken from multiple fields. As you can see, this technique is very powerful for theming Views as it allows us to output complex markup.

Views is pretty much the most popular Drupal module and it is highly complex. Despite its complexity, building views as a site administrator is very easy. All you need to understand is a few basic concepts and you are good to go. Developing for Views to extend its functionality or expose data to it is also an enjoyable experience. If you’d like to know more about that, you can read my tutorial on exposing your own custom module table to Views right here on Sitepoint.com.

Oct 29 2013
Oct 29
Here are some of the Performance tips for the Drupal site.

  1. APC : APC (Alternative PHP Cache) is a PHP OP code cache. It is a very quick win when working with PHP and can offer a great performance boost when using Drupal. It is very much a “set it and forget it” type of application which can just be installed, enabled and left to do it’s thing.
  2. Memcache : Drupal's support for memcache is really good and easy to implement.There is a memcache drupal module(https://drupal.org/project/memcache) to integerate the memcache on the site.
  3. Varnish : When you have a lot of anonymous users reverse proxy cache can save you a lot of server load. Varnish is one of the more popular solutions within the Drupal world. Varnish sits in front of your web server application, for example Apache, Nginx or lighttpd, and can run on the same server or a remote server.Use the varnish module to integrate the varnish on your site https://drupal.org/project/varnish
  4. Boost : Boost provides static page caching for Drupal enabling a very significant performance and scalability boost for sites that receive mostly anonymous traffic. For shared hosting this is your best option in terms of improving performance. On dedicated servers, you may want to consider Varnish instead. When the page is then requested it is loaded quickly, because it is coming straight from the disk and no PHP or MySQL processing is needed.See the Boost module here https://drupal.org/project/boost
  5. CDN : A CDN is used to distribute static assets such as images, documents, CSS and JavaScript across many locations.The goal of a CDN is to serve content to end-users with high availability and high performance.There is a CDN drupal module(https://drupal.org/project/cdn) to use the Content delivery Network.
  6. Disable Database logging module : This module logs the action performed on the site to the database.Use syslog module which is also in drupal core.Using syslog you can also write the more technical log entires to the server's standard log on the file system and save the database queries.
  7. Enable Page & Block Cache : Enable Drupal caching (Administer > Configuration > Performance). When enabled, Drupal will render the page and associated blocks once, and then save that result in the database. This can drastically reduce the number of database calls run on a page since the results are pre-rendered. Drupal’s caching engine is most effective for anonymous visitors – if your site is mostly “read only” and doesn’t have visitors logging in, caching can make a dramatic improvement in site load speed.
  8. Increase Cache Lifetime : An option for some sites may be to increase the cache lifetime. This determines how long Drupal will hold onto a cached result before it will re-generate the page. If you have frequently changing content, you may want to set the cache lifetime to only 5 minutes, but if your content doesn’t change often, an acceptable value may be several hours.The cache lifetime depends on your site usage.
  9. Optimize JavaScript and CSS Files : Enable the option of optimize javascript and CSS files in the performance settings. When enabled, Drupal will consolidate all CSS and JS files included on each page into a minimum files, and compress the code by removing whitespace. This will reduce the overall file size and improve page load speeds.if you need more aggeration of css and js files then use Advanced CSS/JS Aggregation module https://drupal.org/project/advagg
  10. Disable Un-used Modules from the site .

if you have done all the performance tips written above and you are still getting the performance problems then either get the suggestions from the High performance drupal group https://groups.drupal.org/high-performance

There are also some of the related performance related articles.See there links below

  1. http://www.creativebloq.com/web-design/drupal-performance-tips-9122837
Jul 11 2013
Jul 11
How to create the node programmatically in drupal 7 with Reference field modules either References or Entity Reference(that is in drupal 8 core now).

Also find the below example of creating a simple node with page type with Title,Description and a Reference(References or Entity Reference) fields.

$node = new stdClass();
$node->uid = 1;
$node->title = 'Title of the Field';
$node->status = 1;
$node->comment = 1; //Hidden the Comment on the node
$node->promote = 1;
$node->sticky = 0;
$node->type = 'article';
$node->created = '';
$node->changed = '';
$node->timestamp = '';
$node->body['und'][0]['value'] = 'Full Story';
$node->body['und'][0]['summary'] = 'Summary';
$node->body['und'][0]['format'] = 'full_html';
$node->revision = 0;
$node->field_entity_reference['und'][0]['target_id'] = 50;
//Here field_entity_reference is the name of the Entity Reference Field and 50 is the nid of the reference node.
$nid = node_save($node); Here field_entity_reference is the name of the Entity Reference Field and 50 is the nid of the reference node.
you will get the $nid after saving the node
Oct 19 2012
Oct 19

Average: 4 (2 votes)

TechWell logoDrupalEasy was fortunate enough to be be hired to develop version 2.0 of TechWell.com - a software development news site by Software Quality Engineering (SQE). TechWell.com covers a wide range of topics including agile development, software testing, quality assurance, and project management. This mini case study will detail some of the modules and techniques we've used to build the site.

The site is built using Drupal 7 along with a number of contributed and custom modules and a custom theme built on top of the Omega base theme. This mini case study will provide a brief overview of the techniques used to build the site.

The main navigation of the site is based on a single "topics" vocabulary that categorizes each story into one of nine topics. The Taxonomy Menu module is used to translate that vocabulary into the main menu. There are several other vocabularies in place, used mainly for further classification of stories.

Stories on the site utilize a combination of Image Styles and the Imagefield Crop module to display different versions of their main photo depending on the context. In lists, a scaled and (manually) cropped version of the photo is used while in the full node view a scaled and uncropped version of the photo is used. This will accomplished with a small bit of custom theming code.

TechWell home pageThe Radioactivity module is used to populate the "trending" carousel on the home page. Radioactivity allows popular stories slowly decay over time so that only "recently popular" stories will appear in the carousel. The carousel is generated by a custom Views module based on the Elastislide jQuery plugin - mainly because Elastislide is responsive, and the carousel needed to stretch and shrink depending on the device size it is being viewed on.

Flag module is used for content editors to mark stories for the "featured" block. This block appears on the various topic pages as well, and different stories appear in the block based on the current topic.

Several content types were created to handle site "partner" information and content. Partners can have their own section of the web site populated with content they provide. In addition, individual site topics can be sponsored as well, a custom content type to help manage that process as well.

The "events" block is mainly populated with training events from SQE. Again, a custom content type and view is used to enable this functionality. Similarly, content types for "web seminars" and "featured resources" were created, and the Draggable Views module is utilized to give content editors the ability to arbitrarily re-arrange the order of the "featured resources".

Custom modules are used to help manage the "TechWell To Go" newsletter functionality, both for capturing subscriber information and for generating newsletter templates (with current site content) for use in a separate customer relationship management (CRM) system. Several patches were created and contributed back to the community for the Eloqua module as well

TechWell Share URL functionalityThe "Share URL" functionality found on all story pages is made possible by a number of modules as well as a custom URL shortening site powered by the Shurly module. The Shorten URLs module is used in conjunction with a custom module to and custom theming to complete this functionality.

Additional custom modules were created to capture various parts of the site configuration in code, to generate some custom blocks, for improved search (indexing of RealName data), and some custom administrative functionality. 

TechWell on mobileThe site is fully responsive, with a significant amount of work that went into making sure it delievered an efficient experience on mobile devices. Use of the Omega theme combined with the Delta module helped keep costs down and implementation speed up.

Overall, this project was designed with speed and sustainability in mind. The only logged-in users will be administrators (comments are outsourced using Disqus), and a minimum of custom code was created (most of the custom modules are less than 150 lines of code). The client has been thrilled with their new site, and we look forward to watching their business grow using this new resource.

Trackback URL for this post:

http://drupaleasy.com/trackback/537

Apr 30 2012
Apr 30

Average: 4.6 (5 votes)

As the explosive growth of Drupal continues, so does the eco-system of vendors and products around it. Included is the plethora of Drupal books that continues at a somewhat unbelievable pace. It seems that there are at least two to three new releases each month. Unfortunately, in the rush to quench the tech community's thrist for Drupal knowledge, sometimes less-than-stellar books are being served up before they're fully baked (cooking pun #1).

J. Ayen Green's Drupal 7 Views Cookbook needed a little more time in the oven (cooking pun #2), as I found numerous inconsistancies, minor errors, and not-best-practice advice. It's unfortunate, as Mr. Green has written some tasty (cooking pun #3) books in the past (Drupal 6 Attachment Views, Drupal 6 Content Adminstration), as well as numerous articles in Drupal Watchdog. Drupal 7 Views Cookbook isn't a total loss though, as aspiring Drupalists who struggle to learn Views will definitely be able to gain knowledge from the book if they can get past the sometimes obvious inconsistancies and bad advice.

Granted, Mr. Green started writing the book during a very dynamic time in the Views project - the migration from Drupal 6 to Drupal 7, as well as the interface update introduced in Views 3.x, so he was working with a moving target. This doesn't explain why "contextual filters" are often referred to in the book as "dynamic filters" - a simple search and replace could have solved this problem in about 30 seconds. I can imagine readers of the book who are new to Drupal frantically searching the Views interface for the "dynamic filters" options.

I also put some blame on the book's editors - in this case there weren't enough cooks in the kitchen (cooking pun #4). I found a bunch of simple mistakes that should have been found and corrected that will certainly lead to confusion for aspiring Drupalists. For example, on page 36, one of the recipes calls for the user to "Click on the Add link next to Fields". In the next several steps it was obvious that it should read "...next to Filters" - but for readers new to Drupal, I fear will be terribly confusing. Little things like this can spoil the soup (cooking pun #5), and there's no excuse for the book's editors to miss obvious errors like this. As I was reading the book, it was also clear to me that many sections could have been vastly improved with additional screenshots. Portions of the book were really text-heavy, and a few screenshots to break things up (and provide sanity checks for users going through the exercises) would have really sweetened the pie (cooking pun #6).

There are also numerous recipes that exercise bad judgement - and encourage the reader to do the same - including hacking core. In one example, I fully understood what Mr. Green was getting at (he was introducing the concept of overriding a CSS style), but having the user make changes to a core theme sets a bad example for readers. At the very least, he should have included a warning that this is not a "best practice" and only included for brevity (and maybe include a link to the right way to override a style). The "Creating Views Programmatically" chapter has a similar issue. The first part of the chapter talks about writing a view by hand - literally typing in a view's object description line-by-line instead of using the UI - has anyone ever actually done this? A much better option would have been to describe the process for making a minor change to the view in the object code - something that is not unheard of.

Then there were the obvious errors. The most obvious was for a recipe description that was completely different than the actual recipe. I suspect that at one time during the production of the book the recipe did exist as the description states, but it must have been modifed at a later point in the writing process, but the description didn't get updated along with it. As a seasoned Drupal developer and trainer, I was thrown by this and ended up re-reading the section three or four times before I figured out that it was just plain wrong. Imagine how confused newbie readers will be.

To top things off, the final section of the final chapter was titled, "Cloning a View" - I found this short section oddly placed, as the recipes in the book had been instructing the user to clone views literally from the first recipe. This stuck out to me like a sore thumb. Why wasn't this section in the first chapter?

I realize that I'm piling on a bit - I hesitated writing a review for this book at all, knowing that it wasn't going to be all cookies and candy (cooking pun #7), but I really think that authors and publishers of some Drupal books need to step it up a bit. It took me about 4 hours to go through the book and find these (in my opinion) obvious errors. If Packt is charging $40 for this book, shouldn't they at least do the same? It scares me a little bit that people new-ish to Drupal will read books like this with obvious issues and assume that this is the way things are done in the Drupal community.

As I said at the outset, the book may help some aspiring Drupal site builders learn Views. The book offers a gentle introduction to the various concepts of Views, slowing adding complexity as the reader progresses through the book. The way Mr. Green introduces and explains Views Relationships is especially effective - and one of the best I've seen. Can I recommend this book - not at this time. Perhaps the publisher will take the time to make improvements and offer a version 2.

I just finished listening to the Modules Unraveled podcast with J. Ayen Green and he mentioned that some of the early chapters didn't get updated properly as he was making changes based on Views 3.x. An errata page is available.

Trackback URL for this post:

http://drupaleasy.com/trackback/494

Jan 05 2012
Jan 05

Have you ever had to create a conditional input field? For example, one field is a checkbox that reads "Do you have children?" and if the user selects "Yes", we want to show an additional input field that asks "How many?" (and if the user selects "No" the field disappears).

I ran into this in a recent project and, as usual, added some custom javascript using #after_build that did exactly that. I'm pretty sure this is a widespread practice.

Don't do it!

Despite not being techically wrong, the aforementioned solution is, as of Drupal 7, outdated. Changes in the Form API have introduced the same functionality natively, which is a lot easier to implement and requires zero custom javascript!

To accomplish this, we use #states.

Just so we're on the same page here, this is what our form looked like before:

1
2
3
4
56
7
8
9
$form['haskids'] = array(
  '#type' => 'checkbox',
  '#title' => t('Do you have children?'),
);
$form['numkids'] = array(
  '#type' => 'textfield',
  '#title' => t('How many?'),
);

The secret is to use the new "container" type to wrap our conditional elements and control their visibility through the #states attribute:

1
2
3
4
56
7
8
9
1011
12
13
14
1516
17
18
$form['haskids'] = array(
  '#type' => 'checkbox',
  '#title' => t('Do you have children?'),
);
$form['kids_container'] = array(
  '#type' => 'container',
  '#states' => array(
    'invisible' => array(
      'input[name="haskids"]' => array('checked' => FALSE),    ),
  ),
);
 
$form['kids_container']['numkids'] = array(  '#type' => 'textfield',
  '#title' => t('How many?'),
);

Explanation

Using #states, we defined an invisible state for the container, which is triggered when the value of the "checked" attribute of the input specified by the selector is FALSE. It might at first seem a little confusing to mix in jQuery selector in PHP, but this is just how Drupal rolls and manages to bind the javascript event automatically. If in dobut, simply replace name="haskids" with your field's "name" attribute!

To learn more about states and how to use them, read about drupal_process_states().

There!

That was easy, right? It took absolutely no javascript and no #after_build callbacks!

Hope you enjoyed this and catch you next time!

Jul 10 2011
Jul 10

The way Drupal have been handling css styles up until recently have been to say it nice "Problematic" Theres been a lot of unessasey barries for new & experienced frontend developers alike, fiddeling with the css files can even caused functionality to break.
Now in D7 theres a hidden gem in the very core that needs to some spotlight on it: the filenaming rules of drupals css files.
Hopefully this post can help module developers & Themers alike understand the beauty of the new css naming rules, and why its so importent to follow these, now and in the future. But first a run down of what the problems actually are both for the frontend & backend Developer, and why this change is extremely importent for the future of Drupal.

css in Drupal is simply wrong

Drupal core & the contrip modules have a habbit of always including at least one css file to define the styles used by the module so it can
* make fancy javascript thingies (ajax, accordians, sliders etc)
* fix the layout for the administration of the module
* fix the layout for the theme (we need more float left & right style definitions)
* add some design styles like colors, margin, padding, fonts or borders, just as good defaults for the theme
All of this so it works outta the box.

Lets not to forget a favorite re defining a couple of common classname like

.user{background:#900}, .odd{margin:4px}

foo module's foo.css

.foomodule div{border:1px dashed red; margin: 1em; font-size:0.889 em}
.foomodule-fancy-ajaxy-thing-container{display:none}
.anotherclassjustbecausewemightneeditsomeday{background: green}
.block div{border-bottom:2px groove pink}

Now when drupal spits out the final page theres a good amount of css files & styles (Drupal alone comes with XXXX out of the box & then add the contrip modules css files) Chances are that the theme will probably have to overwrite, reset and at least take into consideration all these styles, that drupal is pushing out to the frontend.
This has been a HUGE irritation problem for us who define ourself as frontend developers in drupal for years, and there is actually reasons for that:

separation of logic & presentation

There isnt any file system or namescheme that can tells us if the .foomodulestuff style is essential or not to the modules functionality. This makes its actually easy to destroy modules functionality - if youre a bit to aggressive with the resets, or overwrites the wrong styles.

IE file limitations

The number of css files made IE choke because of its limitations of css files that can be added, so the styling for ie was a complete mess untill "rule35" was effected.
The new release of IE 10, the css file limitation is removed, so this isnt a problem for anyone that uses ie10 (which just leaves us with the ie7, ie8 & ie9 users)
This is offcouse not a problem when the css files are compressed in a live site, but its a "small" annoince in the development of the site (not to mention that we at the same time have to battle ie6 drunk cousin ie7)

Overload

Its really easy to get lost in the amount of styles that a drupal site is carring around, when every module has its own classes + Drupal carries its own good amount of stuff.
and lets not forget the css cascade that can end up beeing so complicated that it can be tempting just to use !importent to whatever you need.

If you think you can just drop a style.css into the theme & then expect it to look the way that its defined in style.css, then you havent worked with Drupal -or you just dont give a rats ass about pixel perfect implementations (and then you probably dont care about having 500 unused styles defined) your gonna use countless hours to reset, overwrite & beat drupal into what you might consider best practice, lets be honest drupal is not actually known for a clean mean styles & markup (much of it based on the fact that Drupal7 still supports IE6)

Take the power back

The way to get the control over Drupals styles is normally one of these 4 methodes:

Revove all $styles

Remove "print $styles;" from html.tpl (was page.tpl in d6)
This will remove every css file that drupal even dreamt about , the problem here is that we also remove the administration elements wont work, jQuery sweetnes wont work etc. To make the site work you need to find the css classes thats needed and add them ind by hand - This is generally a very bad idea & will only cause you problems down the road, new modules thats installed wont work etc. but you got complete control ;)

foad style .info css overwrites

In the themes .info file you can easy exclude a css file just by defining it in css with the same filename as the file you wanna remove.
So lets say you wanna kill off foomodules pesky foomodule.css apparently it adds pink dotted lines around you divs & makes you cry & you basically dont wanna deal with it.

** THEMENAME.info **

stylesheets[all][] = foad/foomodule.css

Now Drupal is tricked into beliving that we have a css files in foad/foomodule.css define in the theme, so it includes that file in the $css list - it dosnt exist so woho its now dead & gone :)
The reason i use the foad as a fake folder is to remember that this file myst Fuck Off And Die.

You should remember though to be carefull what you call the css files in you theme, naming accedentially a file views.css have gotten me into trouble a couple of times. (views-style.css is a much safer name)

Stylestripper module

The stylestripper module to remove all the css files you dont wanna include in a theme. The problem here is that you have to do alot of configuration each time you create a new theme
Guess that features & strongarm can probably do that + havent tried yet in D7.

Overwrite styles as needed.

Offcourse we have the simpel & classic way to clean out is to overwrite & zeroing out the styles thats defined by drupal, and you dont need. Just overwrite all style that drupal spits out, and then you done
This results here is a pretty huge css file thats only job is to zeroing out styles thats been defined & the theme dosnt need.
and you gonna have to fiddel with that file everytime theres new modules added to the site.

These 4 methodes always leaves us down to the simple question:

Why does Drupal add stuff that i dont need, or asked for - thats dumb

(insert you own profanity here)

lets compare this to a database query:

If youre a developer that dont really like to work out in the frontend, let me try to give you an example of how drupals style implementation looks & feels like:
I need the title field from footable so i could do a simple and quick "SELECT title FROM footable" as my database query. - now instead of that just to be sure that i have everything, in case i might one day need it, i better also select the date, the author, the body, its grandmother and what ever i might can find... aaah lets just grap it all
"SELECT * FROM footable"
ah now we have whats needed & offcourse whatever else that might gonna be added to the footable forever.

I can here developers all over the world screaming right now - why oooh why do you wanna select all fields in the table if you only- you are using unessasry resources & it takes longer time to get the data yadi yadi
Well this is how the style css file hell that drupal gives us today feels & its plain wrong.
Everything, including the kitchen sink and its mother are added into the css & spoonfed down the throat of the theme - the frontend development now have to paddel through the ton of styles defined from a ton modules that all are throwing in their idea of what should be in styles... argh (sorry for ranting).

Best of both worlds!

So what that we really need is something like this:

  • must be ready to go outta the box.
    The reason that Modules comes with all the style defined is that it should be usuable when you install it - it dosnt make sense that the theme must write custom css everytime. Sensible defaults would be nice.
  • We dont wanna have unused styles & have to work with a ton of overwrites. It makes the page load slower & makes it weight more
    It makes styling sites a pain & really dosnt make sense to have a remove when nessesary, when we really wanna have an add when nessesary aproach.
  • Modules needs to be able to tell the themes what they should not mess with, so a theme dont accedentially ends up destroing functionality, by overwriting a style or a css file.

Seperation of css logic

Now in Drupal7 all this is taken into consideration, at least if you look at the system module in core (drupal/modules/system/) it is (I danced with joy when i figured this out)
So Lets look at the css files that system is packing

system.admin.css
system.base.css
system.theme.css
system.maintenance.css
system.menus.css
system.messages.css


(i havent included the -rtl version here in the list)

Look there is no system.css file!
Instead all the files have added a description to them after the module name (.base, admin, theme, maintenance, menuse etc)
That actually means that we now can make themes that dont have the problems that I described earlier.

The module is splitting up the normal modulename.css file into 3 different files:

  • modulename.base.css (system.base.css)
    .base.css file is having all the essential style definitions that we needs to make sure the module is working,
  • modulename.admin.css (system.admin.css)
    heres the styles that we need for the adminstration of the module & finally we have the
  • modulename.theme.css (system.theme.css)
    Gives us good defaults for the module.

Holy crap B.A.T.man does this mean that if we remove all the [modulename].theme.css from my themes css files, i dont have to overwrite it & dont screw with the administration interface or the modules functionality?

-drummroll-

YES!

something like this in your template.php will do the trick

<?php
THEMENAME_css_alter
(){
  foreach (
$css as $file => $value) {
    if (
strpos($file, '.theme.css') !== FALSE) {
      unset(
$css[$file]);
    }
  }
}
?>

uuuh gimme gimme

Unfortunately all of Drupal core is not working this way (yet), I hope that we can get all logic in the core styles seperated asap and theres a ton contrip modules to get up to speed, with the way of the system module.

I have started the work of seperating the core css files into the B.A.T. (base, admin, theme) namescheme in the worlds best theme that "fixes evertyhing thats wrong in drupal (tm)": Mothership.

In the mothership, theres also n controller to quickly cleanout the .theme / .base files etc - very handy to remove some of all the clutter. Steal it use it & make it better please :)

If youre a module developer you should really think about splitting up you modules css into BAT css files. The fact that its the right way to do it, system module does it, you will never again have to curse a theme for accedentially removed a style that was essential to your module.
Dont forget there will not be hordes of angry frontend developers in your issuque going "wtf why are ya not following the Guidelines" ;)

I hope this post have put some light on the problems we currently have in an essential part of Drupal frontend development, theres a simple, clean & easy way to fix this problem.

So please wont you be the Module to my Theme?

Jun 25 2011
Jun 25

One of the easiest methods of optimizing the execution of PHP script is by using a static variable. Imagine a function that does some complex calculations, possibly executes several database queries. If the return value from the function does not change too often and the function may be called several times during single request, it may be beneficial to cache the return value with static variable,
You could implement it within your complex function or with a wrapper function if you’re trying to cache the function you didn’t write.

function mymodule_complex_calculation() {
  static $cache;
  if (isset($cache)) {
    return $cache;
  }
  // Otherwise we need to perform our calculations
  // ...some complex calculation that returns 
  $cache = complex_calculation();
  return $cache;
}

This is a very simple pattern and cached data will “survive” only single web request but it may still be very effective, especially if function is called many times during the same request. Drupal implements a drupal_static() function that is a serves as centralized place for storing static variables. The advantage over using your own static variable is that data stored by drupal_static() can be reset. It means that, if other piece of code decides that some cached variable should be cleaned in mid-request, it can do so. Function definition is:

function &drupal_static($name, $default_value = NULL, $reset = FALSE)

You will need a unique name to address the data you want to cache. This will really become a key in the static array. The customary way in Drupal is to use the name of your function as $name, you can use PHP’s magic constant __FUNCTION__ that resolves to current function name. Now we can update our function as follows:

function mymodule_complex_calculation() {
  $cache = &drupal_static(__FUNCTION__);
  if (isset($cache)) {
    return $cache;
  }
  // Otherwise we need to perform our calculations
  // ...some complex calculation that returns simple value
  $cache = complex_calculation();
  return $cache;
}

You may notice that we don’t use drupal_static() to actually set the data – and we don’t need to! As soon as we assign anything to $cache, it will end up in our centralized static store.
drupal_static() has one disadvantage – it adds a new function call (plus execution of some logic inside drupal_static()) every time you use cache which increases the execution time. Compare it with the listing 1 – much simpler. This will add some overhead to each call. At this level we are talking about micro optimizing. It will make noticeable difference only if you function is called hundreds (or thousands) of times per request. If that’s the case, you can use advanced usage pattern for drupal_static. It merges functionality of our 2 functions:

function my_funct() {
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    //17 is the default value in case the cache was empty
    $drupal_static_fast['cache'] = &drupal_static(__FUNCTION__,17);
  }
  $cache = &$drupal_static_fast['cache'];
  //do whatever you need with $cache ...

Pay attention to the fact that $drupal_static_fast is an array and the actual cache is within that array ($drupal_static_fast['cache']). You have to use an array, otherwise your reference to the static variable will be lost and each time my_funct() is called, it will need to retrieve a value using drupal_static() – therefore negating our optimization (see manual for the details).
I’ve added a benchmark for it to micro-optimization site. Assuming I’ve got the test right, you can see the 17x difference between accessing static variable vs calling drupal_static() function.

Jun 01 2011
Jun 01

One thing i always promise myself after have been giving talks at conferences is to make sure that the material is coming out quickly right after.
What im always ending up doing though is off course not that :(

So now after giving the same session in Chicago, Stockholm & Copenhagen, I thought it was appropriate to finally release my notes & slides for those of you who have asked for this. yes it changed name started out as "how to make awesomesauce" which was the working title, when it was preselected for the Chicago Drupalcon, I kept it so people didnt got confused ;)

Worse is that all my clever notes are usually lost in the wind (maybe thats for the best) This time though im happy that my sessions were recorded twice for your viewing pleasure.

DrupalCon Chicago 2011

It was a total blast, giving this presentation, it was probably the biggest room I have ever presented in - think it said there was room for 8-900 people. *Gasp!*,I used to be nervous speaking in the front of 20 people. But it warms my little front end loving heart that the DrupalCons is finally after years of fighting to get more than 2 session in the the accepting the Frontend developers & that we can actually draw a crowd (or did you all just came to see me curse at developers ?)

Those who didnt belive i actually gave the session in a damn godd looking suite. Those of you who dont belive this can check out this video where im interviewed later that day I know that somebody didnt really belive it ;)

The video I used for the Intro & Outtro is can be seen here in it full glory -cause everybody Drupals - Monster (remix) by A. Hughes & D. Stagg

IMG_1126 As a final note to Chicago: It was a total Blast! specially the detail of so many of us in the same Hotel kicked ass!
ooh and one of my hottest dreams ever happend, and I can claim that i made Microsoft say im sorry!

I can now go into the grave a happyman
... ooh wait theres still ie7

Next Stop Stockholm

Last month the good people in Sweden held their DrupalCampand even better they invited me to come and speak at the camp & who cant say no to goto stockholm? and the fact they did alot of flattering which I offcourse cant stand for : "and we will have some key Drupal people such as Todd Nienkerk, mortendk and Addison Berry." - yup im a sucker for that stuff. This also gave me an opportunity to dig into the old scandinavian sport: Taking pokes at each others -did a horrible reference to the Vasa ship that sometimes was how Drupal fels for us Frontend Developers

As soon as the Stockholm people are gonna release the video its gonne go online here, unless they have censored it ;)

Copenhagen - drupaldag

The session was cut down a bit and again given in copenhagen for the yearly informal meetup "DrupalDag" (drupalday) The fun thing here was the developers taking pokes at me during the session & actually pointing out a mistake in the slides Apparently it is possible to change a submit button from the theme layer in D6 - if you use the theme registery & create a new little function to change it ... Damn drupal is still sooooooo developer orientated, that making small logical changes is like stabbing a fork into you eye and puring lemon in it afterwards.

Sessions on Tour?

I used think that it sucked ass to redo a session again & again but when it takes me somewhere betweeen 40-60 hours to get a session ready & that the video recordings are sometimes very shitty, and might even made it to the Conferences websites afterwards (yup iknow the DrupalCon i was leading in Copenhagen had this issue big time, and it was outta our hands :( Then it suddenly makes sense, especially if you like me are on a mission from the frontend gods: Gather an army & clean out the crap from Drupal ;)

The Theme Like a Rockstar session is gonna be on its last show for the Drupal Design Camp in Berlin the 25+26 of June - its taken its turn & I am working on another session that will Rock you like a hurricane (yups) working title "Angry Themer" which will be more focused around theme selectors understanding, regions thinking & how to not be angry, now that you know how to manipulate drupal.

Stuff:

Apr 22 2011
Apr 22

I wanted to change the way teasers are displayed – disable this information about the node submission: published by admin on Fri, 04/22/2011 – 17:25.

Drupal teasers

Drupal teasers

As it turns out, there is a variable that Drupal checks when generating submission information. The variable is set per each content type in a format node_submitted_<NODE TYPE>, e.g., node_submitted_page and should be simply set to TRUE or FALSE. Here is the code I’ve added to my micropt module, to micropt.install

function micropt_install() {
  variable_set("node_submitted_micropt", FALSE);
}

Teaser with no submission information

Teaser with no submission information


You can change the value of the variable using drush or directly in the database:
UPDATE `variable` SET `value` = 'b:1;' WHERE `name` LIKE 'node_submitted_micropt'

“b:1;” is a serialized value for TRUE, for FALSE use “b:0;”. If you do so, don’t forget to clear the cache!

Apr 16 2011
Apr 16

Update 2013.06.17: use Multiple Checkbox Checker.

Update 2012.12.10: also try CheckFox extension.

Update on 2011.12.01: the script doesn’t work for my FF8 anymore, looks like checkboxmate-lefedor-edition is a way to go now.

Upon installing WYSIWYG module in Drupal 7, site builder is presented with rather annoying task of selecting all the buttons to be enabled. The corresponding section of the WYSIWYG form – “buttons and plugins” is rather intimidating:
wysiwyg checkboxes screenshot

Site builder is required to go through all the checkboxes and check them manually. There is some ongoing work to fix the problem on Drupal side but meanwhile there is a better way – Firefox plugin! Install greasemonkey, restart your browser and add this user script.

The usage is not very straightforward at the beginning but it’s very handy once you get used to it. Position your mouse cursor above the first checkbox, click and drag with the mouse. All the checkboxes inside the rectangle you’ll draw will flip their state.

Feb 08 2011
Feb 08

I made it down to the european Drupal Developer Days in Brussels, and were lucky enough that they accepted my speak, even that Im not real a developer.
As i promised in Brussels I would make a post outta this this + a link to the slides, and add some more background. Thanx for not throwing rocks after me during the session

Scratch your own itch

My big itch with drupal since day one (drupal 4.7) have been that drupal adds markup and css by The truckloads, it never seemed like the developers really minded, about this little detail. "dude it works"

Dont Think its out of pure devloper evil but simply by having another focus, after all gettig the functions & site to work is a bit higher up the list than satisfieng a capucino drinking smartass designer-themer-whatever
The answer always been "dude you can overwrite it"

This have resolved in themers and designers using obsene amount of time looking through sourcecode ( thanx firebug) to figure out where a css class could be overwritten, not to mention the hours of trying to change the markup somewhere wrapped deep down inside of 43 divs. the sad reality have also been that by overwriting some css elements, or removing classes or markup could actually break modules (my mothership did that with views ajax pagination, actually I was a bit proud when that happend ;))

Drupal7 is heaven

Now in drupal 7 theres been taken giant leaps forward, thanx to both developers & themers and designers.

One of the thing im most excited about (besides the 6000 theme preprocess calls and hooks) is the way that modules should declare its css files, So the drupal dev days brussels seemed to be a perfect spot to indoctrinate the european drupal developers about this new namescheme.
If theres one thing i really learned during my now soon to be 5 years with drupal is that theres a huge difference in the way that we look at the website (and the world) and that the rest of the world really dont gets the diffence between frontend and backend "its just a website", so hopefully by adding that little story into my slides i also managed to break some barriers, and explain what it is that makes us speak diffent dialects of geek, and why we not always understand eachother.

If you dont really care about all that and just wants the 10 seconds talk, here it is:

  1. Dont add crap to the frontend
  2. name you css files by what they do (modulen.admin.css, module.base.css & module.theme.css)
  3. Dont add crap! - its the themes job to make it look & feel its the modules job to make it work.

Heres the slides on slideshare (I even made it to be the featuredslides of the day)
Hopefully this will be yet another step to change the way that we develop sites in drupal forever(!)
If you wanna dig deeper down then read these to post from Jacine Luisi

    The Brussels Dev Days

    oh and did drupal developer days brussels kick ass? bet ya!
    It was as always great to meat discuss & talk drupal with people in and around the community.

    I made swentel blush, with my love for display suite & got around to talk alot from drupalappstore to surviving as a freelancer + everything in the middle + html5 and hopefully made a ton of new

    I was very amused by the amount of geeks that didn't understood that danish developer Tinef wasn't someones girlfriend . just because she wear high heals apparently she didn't looked like a developer ;) Dudes accept it Drupal is so hot & big now, that we are attracting everything from high badass heels to people wearing long leather jackets and carry swords on their backs (or was that only the ones that studied old medieval german literature - oooh details forgotten in the liters of belgian beers)

    a huge thanx to the whole team behind the Drupal Dev days in Brussels!
    Im looking much forward to comming next time, where ever its' gonna be in europe, and preach about the wonders of design for developers ;)

    Jan 07 2011
    Jan 07

    Drupal 7 is out!

    Late Tuesday night was one of the most exciting Drupal events I've yet to be part of: the official release of Drupal 7. I've been working on the Drupal 7 documentation for over a year at this point, and crunching really hard the last few weeks on the Install and Upgrade guides, and core module documentation. I knew the day was coming, but it was even more inspiring than expected being a part of those last few days and hours leading up to the launch.

    When Angie (aka. "webchick", Drupal 7's core maintainer) started rolling the release, it was quite obvious how excited everyone was on IRC, as this went on for about five minutes straight after she created the final release:

    D7 Release IRC log

    After some final cramming to get the rest of the launch related pages on Drupal.org updated (Lisa Rex, Bojhan Somers, Steve Karsch and Neil Drumm really deserve a special thank you, a they did a fantastic job getting that finished!), the launch page was finally published. Then the official tweet went out and the community rejoiced!

    You can see a great list of all the contributors to the core Drupal 7 code on the http://drupalgardens.com homepage (for as long as it's up). We're really proud to have four of the Affinity Bridge crew listed on there among the almost 1000 contributors: Shawn (langworthy), Tylor (tylor), Tom (thegreat), and I (arianek) all contributed core patches along the way. You can see all the stats on the Growing Venture Solutions Contributors for Drupal 7 - Final Numbers post.

    I know I've only been a party to a fraction of all the hard work that has gone into making Drupal 7 as fantastic as it is, but it's been such a great learning experience and wonderful way of getting familiar with the changes in Drupal 7 even before it launched.

    What this means for us

    We started planning for, and developing in, Drupal 7 ahead of the launch as soon as it was feasible. This has helped us start to get up to speed on the changes early, as well as provide our clients the benefit of one less upgrade to do in the next few years (especially since the Drupal 6 to 7 upgrade has a lot of big changes). It has also allowed us to help out a bit with finding bugs with the early Drupal 7 release candidates.

    Drupal 7 core has a ton of improvements that impact both us (as a development team) and our clients (as end-users), and we're excited to transition to it. If you're relatively technical, I strongly encourage you to watch this fun and informative Drupal 7 Overview video from Lullabot (which is available free until Jan. 12, 2011). Some of the highlights of what I'm most excited about are:

    • There's been a ton of improvements to the user interface (UI). 
      • The new administrative overlay, allows site administrators to perform some administrative tasks without navigating to the admin section of the site. 
      • There are also new contextual links, which allow you to do things like modify the content of a block right from any page of the site, without having to go to the admin section of the site.
      • The new admin dashboard and shortcuts bar make navigating the admin area more intuitive, and allow you to set up a collection of custom links for admin pages you visit frequently.
    • Fields in core!
      • The Custom Content Kit (CCK) module from previous versions, which allowed you to configure additional content types is now part of core as the Field module/Field API, and updated Field UI.
      • Image handling in core! At long last, you can add image fields (with fancy cropping, resizing, and other manipulations) to content types in core without installing a single additional module! Fantastic!
    • Update manager is the new and improved version of the Update status module. Now, not only will it tell you what's out of date and provide a link to the recommended version, but you can install and update modules and themes through the admin interface! How cool is that?! 
    • The improved installer and default install profiles make installing Drupal 7 so quick and easy! The standard install profile takes care of a bunch of extra configuration that it didn't used to, and you can also select the minimal profile if you are a developer and want to start with a stripped down to the basics install.
    • We now have both public and private files at the same time by default. This means that it's easy to set up the site so some or all of the files you upload are private and can't be downloaded off the website from an unauthenticated user. This will be great for people who want to have collections of private or internal documents for their organizations, without having to worry someone could find them through a URL, or that they might get indexed in search engines.
    • RDFa in core. I've been working on wrapping my head around the semantic web and RDF for a while, and finally had an "aha" moment at Lin Clark's talk at DrupalCon Copenhagen in the summer. This is really exciting stuff! The basic idea is that RDFa adds markup that turns sites into structured data that can then be referenced by other sites. It basically turns all websites using RDF into a big shared database that can be cross-referenced. This is fascinating as far as the future of the web, as it will continue to increase collaboration between different sites and organizations, and help allow for single sourcing of information on the internet (ie. if you change something in one place, it self-updates wherever that information is being referenced).
    • On the much more technical side, there are things like:
      • The minimum of PHP 5.2.4 for the server requirements has allowed for a more object oriented (OO) system. This means that more kinds of content, not just nodes (pages, articles) but also users, taxonomy (ie. "tags"), and comments are now what are referred to as "fieldable entities". So before, where we used to only be able to add extra fields to nodes, we can now for example add extra fields to taxonomy terms, or comments.
      • More options as far as what kind of database you can use because of the DBTNG ("Database The Next Generation", the new db abstraction layer in Drupal 7).
      • Various security improvements
    • Theme improvements mean nicer looking, more interactive, efficiently built themes.
      • jQuery in core means lots of nice looking fancy UI and design elements that don't need Flash.
      • Fantastic new default themes ship with core, makes for great looking admin backend, and nice looking, usable out-of-the-box theme for your site.
      • New theme system opens up even more doors for the possibilities when you build custom themes (like we do for all of our clients).
    • Automated testing coverage! Drupal 7 core has fantastic coverage by the built in Testing (aka. Simpletest) framework - sleep well knowing that all of core is working as it should!

    For more details, you can also watch the overview video on the Drupal 7 release page, or there's also a pretty detailed article on Linux User Magazine (just make sure to find the pager at the bottom of the body text, there are 4 pages to the article).

    Finally, for anyone in and around Vancouver, come celebrate the Drupal 7 Release tonight at the D7 Release Party!

    Jan 06 2011
    Jan 06

    To celebrate the Drupal7 release over 100 partys worldwide will take place tomorrow Friday 7. january. just 2 days after the Release of Drupal7 In copenhagen we will go nutter in champagne, cocktails & Drupal7 an epic combination.

    pst... What did you do for D7

    Its been to years since the mighty @webchick got the torch & I must say im very happy about the way a'lot turned out: especially the openness & communication towords us who dont gives a ratts ass about database connections & security patches, but wanna make sites that:
    * Looks the way the designer made in photoshop/Fireworks
    * With Designers who really dont care about anything else than how epic Helvetica is.
    * That Developers can work on afterwards
    * with css & markup thats smooth as cream
    Well se over the months how it really turned out ;)

    So what did I do for Drupal7 - well 2 things:
    1. Had the discussion with webchick in Paris (2009) over a year ago about html.tpl.php and if and whys and back n forth...
    2.Nothing else beside some community organistaion work, a couple of camps here n there & a small 1200 attendes conference (btw Drupal Association, thanx for not mentioning Drupalcon Copenhagen as one of the big things in 2010...seriously?)

    Drupal 7 on Ruby

    Here in wönderfull Drupalhagen we have thrown together a little thing both to enlighten the masses & have a small little party - cause thats the way we roll baby!
    So if you have nothing better todo (you dont!) then you should come by and listen to 4 Quick sessions about Drupal7
    This will be the first time i only talks for 15 minutes, and maybe even presents in a tie (!) or in the nude, Who knows?

    When were done with the serous stuff, well take over a bar that we thinks will fit Drupal7 pretty good: (besides the fun in having it on Ruby... ahem gets it ruby, drupal php?) and start the The Danish Drupal Associations Official Kickass Party

    Four of the Finest Danish (and a swedish) DrupalShops found the wallet and are pushing a ton of Kroner into the bar so there will be (some) champagne & Drinks etc

    Why Ruby and not one of the usual superbad worldclass beerbars, well Drupal7 is a shift in many ways So we had to do something different, D7 got some much needed ux & design love , so to reflect that & keep the expected level of awesomesauce we thought that Ruby should fit our demands for perfection :)

    If you decided to drop by for the presentations its
    Friday january 7 13:45
    berlingske
    Berlingske Media
    Pilestræde 34
    DK-1147 København K

    If you prefere champagne, drinks & hot Drüpal Love (I know you do) We are at
    Ruby
    Nybrogade 10
    1203 Copenhagen
    map
    From around 16:30

    If youre not in DrupalHagen well fear not theres a party near you somewhere

    cheers!

    Jan 06 2011
    Jan 06

    California's #1 RV Dealership is now running Drupal 7. ActiveLAMP completely redesigned and re-implemented mikethompson.com from Drupal 5. Several months ago we made the decision to leap head first into Drupal 7 development, rather than use Drupal 6 for this rebuild, and we're glad we did.

    MikeThompson.com provides an easy way for users to find and inquire on RV's, schedule service appointments, apply for job openings, etc..., however, the real benefit of using Drupal 7 is two fold, it is a great CMS and it is a great framework.

    Drupal 7 CMS Benefits

    The content on mikethompson.com is real easy to manage. Inventory Managers at the dealership can login, and easily manage new and used inventory; Content Managers can manage miscellaneous content pages, announcements, and promotions; and sales staff can manage inquires on the site (using webform), the list goes on of what we were able to accomplish using the Drupal 7 CMS.

    Drupal 7 Framework Benefits

    Drupal is engineered with the developer in mind. We wrote quite a bit of custom code to make it very easy for users using the CMS to manage the site. For example, with the Field API we were able to add extra fields to taxonomy terms and file upload fields, the drupal hook system allowed us to easily tap into webform module to implement access control from our own modules, the Drupal 7 contextual links allowed us to make it real easy for content managers to manage various regions of the site. On top of being able to hook into the existing functionality already in Drupal, we built a handful of custom modules to bring everything together. We were able to extend Drupal 7 to do exactly what we needed it to do.

    Modules we used

    Some of the contrib modules we used in building the site include Views, Webform, WYSIWYG, Administer Users by Role (we ported), Google Analytics, Secure Pages, Pathauto, Context, and of course Features. We also used very heavily a few core modules such as Taxonomy -- to categorize RV Inventory several different ways, Field -- to add custom fields to Taxonomy and Nodes, and Image -- the imagecache replacement that is now in Drupal 7 core.

    Modules we are releasing to the community.

    We also built a few new modules that we will be contributing back to the community for Drupal 7, Themepacket and Spritesheets.

    Themepacket provides a new views display that makes it easier for themers and developers to theme views output using custom theme templates, without manually registering theme hooks in your modules and themes, it also discovers any assets found within your themepacket implementation, without the need to call drupal_add_css() or drupal_add_js(). The module will also preprocess your fields for you so you can use nice looking variables in your templates.

    Spritesheets is a module we developed to optimize css background images in themes and modules on to one image asset. You have the ability to configure which directories Spritesheets module will search, and it will parse your CSS to find images that can be included on a spritesheet. You can then configure which images should be optimized to a spritesheet. Spritesheets can greatly reduce page load time, bandwidth, and the tax on your server by combining.

    Conclusion

    Drupal 7 has launched, and it is ready for prime time! The #D7CX initiative seems to have really paid off. All the heavy hitting contrib modules we needed to build this site has a D7 version. That's a big win for the community! We were able to build a site that is easy to manage and maintain for the site managers using Drupal 7 core, contrib modules, and by extending the Drupal 7 platform to our specific needs with custom modules. Great CMS! Great Framework! Drupal 7 is phenomenal!!!

    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