Free Training by Valuebound, Bangalore on Drupal Global Training Days

Bangalore Drupal User Group in collaboration with Valuebound & TIME Inc India will be conducting a free Drupal training on Global Drupal Training Day, Sat, 29th Aug.

What is it?

It's a full day introduction to Drupal. Attendees will leave having successfully built a Drupal site. Part of the Drupal Global Training Day initiative by the Drupal Association.

Whose it for? 

It's for those interested in taking up Drupal as a career path. Hobbyist or entrepreneurs who wants to learn site building on your own.

Cost? It's FREE. Venue and lunch provided by TIME Inc India.

Venue

Time Inc.
RMZ ECOWORLD, PLOT C1, CAMPUS 8A, 5TH FLOOR OUTER RING ROAD BENGALURU, INDIA - 560103
Phone: +91 80 7105 7100

How do you use hook_menu_alter() in drupal 7

I have been working on Drupal 7 for almost two years now. During these two years I have worked on many hooks but hook_menu_alter() hook is the one of the mostly used one. Today i going to explain my experience with this hook.

Change theme of particular page/menu:

I have discussed this one of earlier post in detail. There we have used hook_custom_theme() hook to change theme on particular page. Instead of this we can also use hook_menu_alter() as another way to achieve same feature.

/*
 * Implements hook_menu_alter().
 */
function custom_module_menu_alter(&$items){
  // Change 'node/add/page' page to admin theme (Assume by default node/add page uses default theme)
  $items ['node/add/page']['theme callback'] = variable_get('admin_theme');
}

Change title of page/menu:

Menu provides page titles. If we are in ‘node/add/page’ then we see page title as ‘Create Basic page’ but what if we need custom title like ‘Add page’. We can achive this using below custom module.

/*
 * Implements hook_menu_alter().
 */
function custom_module_menu_alter(&$items){
  // Change 'node/add/page' title to 'Add page'
  $items ['node/add/page']['title'] = 'Add Page';
}

Customize accessing a page/menu:

For many pages/menus we restrict access to different users or on conditions. Let’s say we want restrict ‘user/register’ page in particular times.. I mean no registration will be done in 12AM - 06AM.

/*
 * Implements hook_menu_alter().
 */
function custom_module_menu_alter(&$items){
  // Restrict 'user/register' page in 12AM-05AM
  $items ['user/register']['access callback'] = '_MY_MODULE_time_access';
}

/*
 * Access callback function to restrict user registration in particular timings
 */
function custom_module_time_access(){
  // Get current time hour like 0,1,2,3....23
  $current_time_hour = date('G');
  
  // if current time is between 0 & 5 then return false
  if($current_time_hour >= 0 && $current_time_hour <= 5 ){
    return false;
  }
  return TRUE;
}

Create duplicate page/menu:

We can also use hook_menu_alter() hook if we want to create a duplicate page, a page with same functionality but with different url. Let’s say we want a url ‘add/page’ which acts same as of ‘node/add/page’.

/*
 * Implements hook_menu_alter().
 */
function custom_module_menu_alter(&$items){
  // Copy ‘node/add/page’ page to ‘add/page’
  $items ['add/page'] = $items ['node/add/page'];
}

Custom Account cancellation methods in Drupal 7

In drupal 7 whenever admin selects to cancel user/s account, it provides multiple cancellation options like

  • Disable the account and keep its content.
  • Disable the account and unpublish its content.
  • Delete the account and make its content belong to the Anonymous user.
  • Delete the account and its content.

In this post I am going to explain how to create a create custom method like ‘Disable the account and make its content belong to the admin user.

There are two user API hooks available to achieve this - hook_user_cancel_methods_alter() & hook_user_cancel(). Before we start implementing lets discuss about these hooks.

hook_user_cancel_methods_alter()

This hook is used to modify account cancellation methods and can be used to add, customize, or remove account cancellation methods. After we invoke this hook all defined methods are converted as radio button form elements by user_cancel_methods() We can define following 3 properties -

  • title: The title of method (radio button's title).
  • description: (optional) A description to display on the confirmation form if the user is not allowed to select the account cancellation method. The description is NOT used for the radio button, but instead should provide additional explanation to the user seeking to cancel their account.
  • access: (optional) A boolean value indicating whether the user can access a method. If #access is defined, the method cannot be configured as default method.

In our case we are defining new method called ‘my_module_assign_to_admin

hook_user_cancel()

These hook will be called on user account cancellations. Depending on the account cancellation method, the module should either do nothing, unpublish content, or anonymize content. In this case also following 3 properties can be defined -

  • $edit: The array of form values submitted by the user.
  • $account: The user object on which the operation is being performed.
  • $method: The account cancellation method.

In our case we are defining functionality for our method ‘my_module_assign_to_admin

Let’s create module called my_module, using following code

/*
 * Implements hook_user_cancel_methods_alter().
 */
function my_module_user_cancel_methods_alter(&$methods) {
  // Add a custom method.
  $methods['my_module_assign_to_admin'] = array(
    'title' => t('Disable the account and make its content belong to the admin user.'),
    'description' => t('All contents will be assigned to admin user.'),
    // access should be used for administrative methods only.
    'access' => user_access('Administer permissions'),
  );
}

/*
 * Implements hook_user_cancel().
 */
function my_module_user_cancel($edit, $account, $method) {
  switch ($method) {
    case 'my_module_assign_to_admin':
      // Assign nodes to admin user.
      module_load_include('inc', 'node', 'node.admin');
      $nodes = db_select('node', 'n')
        ->fields('n', array('nid'))
        ->condition('uid', $account->uid)
        ->execute()
        ->fetchCol();
      node_mass_update($nodes, array('uid' => 1));
      break;
  }
}

Just enable this module on your module list page, you should see additional option for user cancellation -

  • Disable the account and make its content belong to the admin user

Referrence
https://api.drupal.org/api/drupal/modules!user!user.api.php/function/hook_user_cancel/7
https://api.drupal.org/api/drupal/modules!user!user.api.php/function/hook_user_cancel_methods_alter/7

How to create custom tokens in Drupal 7

One of the great feature in drupal is tokens system. Tokens are reusable text that can be placed into documents via simple placeholders, like %site-name or [user]. In Drupal there are many default tokens are made available thru’ token module e.g. nodes, users, taxonomy as well as other site related tokens. For example to display site name we have [site:name] token, to display node author we have [node:author]. All these tokens are properties of entities. And if we add new field in node then these field will be available as token. For example [node:body] is the token where it will display body field.

But quite a few times we come across situation when default tokens available in Drupal is not enough for project. Today we are going to discuss about how to create custom tokens using our custom module. In our example we will create a token Trimmed body field. This will display 20 characters of body field in a node wherever we will use this token.

To achieve these we will be using hook_token_info() and hook_tokens() hooks Create a new module MY_MODULE and implement these two hooks. But before start implementing this let’s discuss about hook_token_info() and hook_tokens() hooks.

hook_token_info()

These hook provides information about available placeholder tokens and token types. Tokens are placeholders that can be put into text by using the syntax [type:token], where type is the machine-readable name of a token type, and token is the machine-readable name of a token within this group.

Return value properties:

These function will return associative array of available tokens and token types.

types

  • name: Name of the token type.
  • description: Description of the token type.
  • needs-data: The type of data that must be provided to token_replace() in the $data argument (i.e., the key name in $data) in order for tokens of this type to be used in the $text being processed.

tokens

  • name: Name of the token.
  • description: Description of the token.
  • type (optional): A 'needs-data' data type supplied by this token, which should match a 'needs-data' value from another token type. For example, the node author token provides a user object, which can then be used for token replacement data in token_replace() without having to supply a separate user object.

hook_tokens()

These hook provides replacement values for placeholder tokens. This hook is invoked when someone calls token_replace(). That function first scans the text for [type:token] patterns, and splits the needed tokens into groups by type.

Return value properties :

$type: The machine-readable name of the type (group) of token being replaced, such as 'node', 'user', or another type defined by a hook_token_info() implementation.

$tokens: An array of tokens to be replaced. The keys are the machine-readable token names, and the values are the raw [type:token] strings that appeared in the original text.

$data: (optional) An associative array of data objects to be used when generating replacement values, as supplied in the $data parameter to token_replace().

$options: (optional) An associative array of options for token replacement; see token_replace() for possible values.

Create MY_MODULE module & create file MY_MODULE.tokens.inc and implement following code.

/**
 * Implements hook_token_info().
 */
  function custom_title_token_info() {

    // Define token value, body_trim is the token will be used as [node:body_trim]
    $node_trim['body_trim'] =  array(
      'name' => t("Trimmed body field"),
      'description' => t("Trim body field to 20 characters "),
    );

    // Return associative array of tokens & token types
    return array(
      'tokens' => array(
        'node' => $node_trim,
      ),
    );
}

/**
 * Implements hook_tokens().
 */
function custom_title_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();

  // Check if token type is node
  if($type == 'node'){
    foreach ($tokens as $name => $original) {
      switch ($name) {
        // Check token is body_trim
        case 'body_trim':
          $body = $data['node']->body[LANGUAGE_NONE][0]['value'];
          // Trim 20 characters and return
          $replacements[$original] = substr($body,0,20) . ' ...';
          break;
      }
    }
  }
  return $replacements;
}

Note : We have not defined any custom token type as we needed node related token.

Reference:
function hook_token_info
function hook_tokens

Implementing themes based on specific conditions in Drupal 7

In drupal 7 we have options to set default theme & admin theme. There are limitations, Admin theme will be available for roles which has access permission for admin theme. But in case if we have conditions to set specific theme for specific page based on user roles or specifying theme for particular node types, drupal core will not provide options to do these. We do have module available for this purpose - ThemeKey. But we can achieve by using drupal hooks also.

In this post I am going to explain how we can change particular theme for different pages based on various conditions. Let’s take following scenarios.

  1. Set admin theme for node edit pages for manager role users
  2. Set default theme for node/add/article pages for manager role users

Note : By default manager role is not set admin theme.

Drupal 7 provides hook_custom_theme() hook to do these functionality. Let’s create module called dynamic_theme. Check implementation of hook_custom_theme() for above scenarios.

Scenario 1 : Set admin theme for node edit pages for manager role users

/**
 * Implements hook_custom_theme().
 */
function dynamic_theme_custom_theme() {

  // Load current user
  global $user;

  // Check current page is 'node/%nid%/nid'
  if(current_path() == 'node/%node/edit'){
    // Check current user role is 'manager'
    $roles = $user->roles;
    if(in_array('manager',$roles)){
      // return admin theme for these page
      return variable_get('admin_theme');
    }
  }
  
}

Scenario 2 : Set default theme for node/add/article pages for manager role users

/**
 * Implements hook_custom_theme().
 */
function dynamic_theme_custom_theme() {

  // Load current user
  global $user;

  // Check current page is 'node/%nid%/nid'
  if(current_path() == 'node/add/article'){
    // Check current user role is 'manager'
    $roles = $user->roles;
    if(in_array('manager',$roles)){
      // return default theme for these page
      return variable_get('theme_default');
    }
  }
}

In case if we have multiple themes then return theme name in these function.

Note : The theme you want to activate must be enabled.

Register for DrupalCamp Bangalore - July 25-26 at CMRIT

The much-awaited event, DrupalCamp Bangalore is finally here and the Garden City is all set to welcome the Drupal enthusiasts from all over India. The event will be scheduled from July 25-26 at CMRIT Bangalore and will be featuring a series of curated sessions and sprints.

The excitement is in the air and we, the Valuebound team is constantly volunteering and taking part in every aspect of the DrupalCamp to make it a big success.
 
The mission is to evangelize and spread the vibrant and versatile open source platform, Drupal, across the globe. Join our hands, be a part and experience the dynamicity of Drupal. If you are not yet registered, gear up and grab a ticket right away.

Register yourself at http://drupalcampbangalore.org/ticket/register

Writing custom Drush commands in Drupal 7

As a drupal developer we use drush on daily basis. For example clearing the cache, downloading or enabling modules/themes, updating modules. All these commands comes with core but drupal also provides hooks to integrate with our custom modules.

Today we are discussing about how we can write drush commands through our custom module. We are taking example - “Count of nodes by type”.

$ drush node-count 

or

$ drush nc 

Example of using & output:

$  drush node-count article
article’s node count : 100

To achieve these we have to hook_drush_command(). Let’s create module called custom_dc, And check these code.

/**
 * Implementation of hook_drush_command().
 */
function custom_title_drush_command() {
  $items = array();
  $items['node-count'] = array(
    'callback' => 'custom_title_node_count',  // Callback function
    'description' => 'Drush command to get node count of particular node type.',
    'aliases' => array('nc'), // alias of command
    'examples' => array(      // List these example when user types : drush help nc
      'Get all nodes count' => 'drush nc',
      'Get articles node count' => 'drush nc article',
      'Get articles, pages node count' => 'drush nc article page',
    ),
  );
  return $items;
}

/*
 * Callback function for hook_drush_command().
 */
function custom_title_node_count() {
  // Get arguments passed in command, Ex: drush nc page blog
  $args = func_get_args();
  if ($args) {
    // Loop for types
    foreach($args as $type){
      // Query to get count of particular type
      $result = db_select('node', 'n')
        ->fields('n', array('nid'))
        ->condition('type', $type, '=')
        ->execute();
      $num_of_results = $result->rowCount();
      drush_print($type. "'s node count : " . $num_of_results);
    }

  }
  // If no type passed then return total count
  else {
    drush_print('No node types mentioned');

    $result = db_select('node', 'n')
      ->fields('n', array('nid'))
      ->execute();
    $num_of_results = $result->rowCount();

    drush_print('Count of all nodes : '. $num_of_results);
  }
}

This hook defined command “node-count”. 

Some points about hook_drush_command() implementation.

  • callback : These is callback function for these command.
  • alias :  Alias of these command, here ‘nc’ is alias so we can run command like these Ex: drush nc blog
  • examples :  Array of examples where it will display by help command
$ drush help nc
Drush command to get node count of particular node type.
Examples:
 Get all nodes count                       drush nc              
 Get articles node count                   drush nc article      
 Get articles, pages node count            drush nc article page
Aliases: nc

How to use newly created drush commands - Get all nodes count

drush nc

Get article nodes count

drush nc article

Get page nodes count

drush nc page

Get page, blog nodes count

drush nc page, blog

Installing & configuring Apache Solr-5.2.0 with Drupal 7 using Search API on Ubuntu 14.04

To install Solr Java Runtime Environment (JRE) version 1.7 or higher is needed. On your terminal check your Java version.

$ java -version

If JRE is available it will show you the version number. And if you got no result is found, then you have to installJRE. You can install the same using simple command in terminal

$ sudo apt-get -y install openjdk-7-jdk
$ mkdir /usr/java
$ ln -s /usr/lib/jvm/java-7-openjdk-amd64  /usr/java/default

Now we have JRE installed, lets install Solr.

Installing Solr is pretty easy. Browse to folder you want to install Solr and download the latest copy of Apache Solr  from here - http://www.apache.org/dyn/closer.cgi/lucene/solr

$ cd /opt
$ wget http://archive.apache.org/dist/lucene/solr/5.2.0/solr-5.2.0.tgz

Untar the tar ball and go to solr folder.

$ tar -xvf solr-5.2.0.tgz
$ cd /opt/solr-5.2.0

Now to install Solr as service run this command.

$ bin/install_solr_service.sh --strip-components=2

This will install Solr as a service and run in the background on your web server. By default it uses the port number 8983.

You can change default port number to one of your choice. Just run this line.

$ bin/solr start -p 8984 // Here 8994 would be your new port number

Your Solr should be up and running. Browse to http://your_ip_address:8983/solr

You can also stop Solr as service from the solr directory.

$ bin/solr stop

Check Solr Status if it is running or not.

$ bin/solr status

We have successfully installed Solr but open for everyone who knows our IP address. we need to secure it.

For authentication of solr server url http://your_ip_address:8983/solr we have to do some configuration.

Go to the folder and create a new file with name realm. properties

$ cd opt/solr/server/etc
$ nano /opt/solr/etc/realm.properties

Add username, password and role in this format -

USERNAME:PASSWORD, ROLE-NAME

eg. 
solr : solr_123, solr-admin

Save this file.

Now Edit /opt/solr/etc/webdefault.xml and add the following:

Save webdefault.xml file.

Now Edit /opt/solr/etc/jetty.xml

Now restart your Solr server.

$ cd /opt/solr/
$ bin/solr restart

Check with default port if authentication is working or not by visiting http://your_ip_address:8983/solr

Now it must be asking for username and password. Use the Username and Password which you added in /opt/solr/etc/realm.properties to login.

You should see your Solr admin console.

Configuring Solr with Drupal 7

Get the latest version of Search API Solr Search from Drupal ( Apache Solr Drupal module didn’t worked with Solr 5.2.0 though it used to work with Solr 4.4 )

$ cd /opt
$ wget  http://ftp.drupal.org/files/projects/search_api_solr-7.x-1.8.tar.gz
$ tar -zxf search_api_solr-*.tar.gz

We need to copy Solr configuration files from Search API Solr Search module to solr configuration directory.

$ rsync -av search_api_solr/solr-conf/5.x/  /opt/solr/example/files/conf/

Create new Solr core for your website andcopy Solr configuration files to new core.

$  mkdir /opt/solr/server/solr/valuebound // Here valuebound is name of my Solr Core
$ cp -r  /opt/solr/example/files/conf/  /opt/solr/server/solr/valuebound/ 

Restart Solr now

$ cd /opt/solr 
$ bin/solr restart

Open your Solr admin page - http://your_ip_address:8983/solr

Solr 5.2 admin configuration page

Click On Core Admin and create new core with same name which we used above to create Solr core directory.

Once again restart Solr.

Now we have Solr configured, secured with new core, lets configure our Drupal site to use Solr for search. Install below modules -

Enable these modules in your site module list page. Now we will create one search server and one search index to be used with Solr.

For Creating server and index we have to navigate to Search Api config page (http://valuebound.com/admin/config/search/search_api)

Drupal 7 Search Api config page

Click on Add server link. Name your Solr Server along with description and in Service class Select Solr As a Service.

Add server link for Solr Server

When you will select Service Class As Solr Service it will expand and you will below screen.

Solr Service Configuration in Drupal 7

We have four field

  1. HTTP protocol
    Select http
  2. Solr host
    If no authentication enabled, you have just add your solr server hostname or IP address of your server where Solr is installed.
    If you have Authentication enabled then server name would follow this pattern
    USERNAME:PASSWORD@IP_Address
    eg. solrserverusername:solrserverpassword@xxx.xxx.x.xxx
  3. Solr port
    Port number you have used in during installation of solr server eg. 8983
  4. Solr path
    In our case this would be /solr/valuebound

We have added Search server. Now we also need to add Index server. Navigate to Search Api config page (http://valuebound.com/admin/config/search/search_api) and click add Index server.

Add Index server in Drupal 7 for Apache Solr

Select Item Type “node” and select server which is created in previous step. Check “Index items immediately” then create index.

We have configured Solr server with Drupal.

Next Index all Content with solr server. Your Drupal search result would be served thru’ Apache Solr Server now.

How to disable account related e-mails in Drupal 7

Drupal 7 provides 8 basic email templates for registering, cancellation & password recovery. These settings we can find at ‘admin/config/people/accounts’ page.

account-seting-mail

In these templates, some of following templates has option to disable( checkbox above subject field ).

  • Account activation
  • Account blocked
  • Account canceled

But other templates by default enabled & those cannot be disabled through UI. So incase we don’t want these template then we can do it through programmatically by using hook_mail_alter(). 

In one of case we didn’t wanted to send default “Welcome (no approval required)” email template as we were using Rules to send custom email with some attachment. There is no option to send attachment in default email.

Now let’s look into the simple code how we can disable that. And later I will explain how we can disable for other default templates too. We have created module called no_emails.

/**
 * Implements hook_mail_alter().
 */
function no_emails_mail_alter(&$message) {
  if ($message['key'] == 'register_no_approval_required') {
    $message['send'] = FALSE;
  }
}

Here register_no_approval_required is the message key for ‘Welcome (no approval required)’ template, Following are other message keys in case if you want to disable them.

  • register_admin_created: Welcome message for user created by the admin.
  • register_no_approval_required: Welcome message when user self-registers.
  • register_pending_approval: Welcome message, user pending admin approval.
  • password_reset: Password recovery request.
  • status_activated: Account activated.
  • status_blocked: Account blocked.
  • cancel_confirm: Account cancellation request.
  • status_canceled: Account canceled.

Similarly we can disable Welcome (new user created by administrator) email template using below snippet.

/**
 * Implements hook_mail_alter().
 */
function no_emails_mail_alter(&$message) {
  if ($message['key'] == 'register_admin_created') {
    $message['send'] = FALSE;
  }
}

We have learned how can we disable Welcome (no approval required) template & Welcome (new user created by administrator) templates. You can use above mentioned message keys to disable other default email templates also.

How to get dynamic or Custom page titles in Drupal 7

Recently I was working in a project where we needed to show page title in format of [ node count associated with taxonomy term] [taxonomy term page is associated with] | [site name]. By default drupal 7 provides page title “term name | site name” for term pages. Our requirement was to get page title 125 vegetable recipe blog | my site name. Here 125 is node count of vegetable recipe tag. This is how we have  achieved this using  hook_preprocess_html().

Let’s create module called custom_title & create function custom_title_preprocess_html as follows in custom_title.module file.

/**
 * Implements hook_preprocess_html().
 */
function custom_title_preprocess_html(&$variables) {
  // Make sure current page is taxonomy/term/tid
  // In case if you use alias then you can use these way
  // Let’s say your term page is vegetables/tomato then use like
  // if( arg(0) = 'vegetables' && count(arg()) == 2 ){
  // and alternatively change loading term from name to tid
  if (arg(0) == 'taxonomy' && arg(1) == 'term' && is_numeric(arg(2))) {
    //loading term by tid
    $term = taxonomy_term_load(arg(2));

    //get node count by replacing token value
    $term_node_count = token_replace('[term:node-count]', array('term' => $term));

    //get site name
    $site_name = token_replace('[site:name]');
    $head_title = $term_node_count . " " . $term->name." blogs | " . $site_name;

    //add title
    $variables['head_title'] = $head_title;
  }
}

Now just enable this module and clear your Drupal cache. You should see  your page title like “ 125 vegetable blogs | site name ”. 

Similar to above example you can change page title like “Page Title | Krishna blog” using hook_preprocess_html(). In this case Krishna is node author. Custom or dynamic page title for node pages:

/**
 * Implements hook_preprocess_html().
 */
function custom_title_preprocess_html(&$variables) {
  // Make sure current page is node/nid
  // It will even if use aliases.
  if(arg(0) == 'node' && is_numeric(arg(1)) && count(arg()) ==2){
    //load node from nid
    $node = node_load(arg(1));
    //load user from uid
    $user = user_load($node->uid);
    //add title
    $head_title = $node->title . " | " . $user->name . " blog";
    $variables['head_title'] = $head_title;
  }
}

The way we have customized node page title & term page titles, similarly we can use hook_preprocess_html() hook to customize other page titles like user pages, search page titles or any custom pages.

Download the Drupal Guide
Enter your email address to receive the guide.
get in touch