Oct 27 2014
Tim
Oct 27

By default Search API (Drupal 7) reindexes a node when the node gets updated. But what if you want to reindex a node / an entity on demand or via some other hook i.e. outside of update cycle?

Turned out it is a quite simple exercise. You just need to execute this function call whenever you want to reindex a node / an entity:

search_api_track_item_change('node', array($nid));

See this snippet at dropbucket: http://dropbucket.org/node/1600

search_api_track_item_change marks the items with the specified IDs as "dirty", i.e., as needing to be reindexed. You need to supply this function with two arguments: entity_type ('node' in our example) and an array of entity_ids you want to be reindexed. Once you've done this, Search API will take care of the rest as if you've just updated your node / entity.

Additional tip: In some cases, it's worth to clear field_cache for an entity before sending it to reindex:

// Clear field cache for the node.
cache_clear_all('field:node:' . $nid, 'cache_field');
 
// Reindex the node.
search_api_track_item_change('node', array($nid));

This is the case, when you manually save / update entity values via sql queries and then want to reindex the result (for example, radioactivity module doesn't save / update a node, it directly manipulates data is sql tables). That way you'll ensure that search_api reindexes fresh node / entity and not the cached one.

May 20 2014
Tim
May 20

I had a case recently, where I needed to add custom data to the node display and wanted this data to behave like a field, however the data itself didn't belong to a field. By "behaving like a field" I mean you can that field at node display settings and able to control it's visibility, label and weight by dragging and dropping that field.

So, as you may have undestood, hook_preprocess_node / node_view_alter approach alone wasn't enough.

But we do Drupal right? Then there should be a clever way to do what we want and it is here: hook_field_extra_fields() comes for help!

hook_field_extra_fields() (docs: https://api.drupal.org/api/drupal/modules!field!field.api.php/function/h...) exposes "pseudo-field" components on fieldable entities. Neat!

Here's how it works, let's say we want to expose a welcoming text message as a field for a node, here's how we do that:

/**
 * Implements MODULE_NAME_field_extra_fields().
 */
function hook_field_extra_fields() {
  $extra['node']['article']['display']['welcome_message'] = array(
    'label' => t('Welcome message'),
    'description' => t('A welcome message'),
    'weight' => 0,
  );
  return $extra;
}

As you see in example above, we used hook_field_extra_fields() to define an extra field for an enity type of 'node' and 'article' bundle (content type). You can actually choose any other type of entity that's available on your system (think user, taxonomy_term, profile2, etc).

Now if you'll clear your cache and go to display settings for Node -> Article you should see 'A welcome message' field available.

Ok the last bit is to actually force our "extra" field to output some data, we do this in hook_node_view:

/**
 * Implements hook_node_view().
 */
function MODULE_NAME_node_view($node, $view_mode, $langcode) {
  // Only show the field for node of article type
  if ($node->type == 'article') {
    $node->content['welcome_message'] = array(
      '#markup' => 'Hello and welcome to our Drupal site!',
    );
  }
}

That should be all. Now you should see a welcome message on your node oage. Please note, if you're adding an extra field to another entity type (like, taxonomy_term for example), you should do the last bit in this entity's _view() hook.

UPDATE: I put code snippets for this tutorial at dropbucket.org here: http://dropbucket.org/node/1398

Mar 18 2014
Tim
Mar 18

I'm a big fan of fighting with Drupal's inefficiencies and bottlenecks. Most of these come from contrib modules. Everytime we install a contrib module we should be ready for surprises which come on board with the module.

One of the latest examples is Menu item visibility (https://drupal.org/project/menu_item_visibility) that turned out to be a big trouble maker on one of my client's sites. Menu item visibility is a simple module that let's you define link visibility based on a user's role. Simple and innocent... until you look under the hood. The thing is Menu item visibility stores it's data in database and does a query per every menu item on the page. In my case it produced around 30 queries per page and 600 queries on menu/cache rebuild (which normally equals to the number of menu items you have in your system).

The functionality that this module gives to an end user is good and useful (according to drupal.org: 6,181 sites currently report using this module) but as you see, storing these settings in db can become a huge bottleneck for your site. I looked at the Menu item visibility source and came to this "in code" solutions that fully replicates the module functionality but stores data in code.

Step 1.

Create a custom module and call it like Better menu item visibility., machine name: better_menu_item_visibility.

Step 2.

Let's add the first function that holds our menu link item id (mlid) and role id (rid) data:

/**
 * This function returns a list of mlid's with a list of roles that have access to link items.
 * You can change the list to add new menu items or/and roles
 * The list is presented in a format:
 * 'mlid' => array('role_id', 'role_id),
 */
function better_menu_item_visibility_menu_item_visibility_role_data() {
  return array(
    '15' => array('1', '2'),
    '321' => array('1'),
    '593' => array('3'),
    // Add as many combinations as you want.
  );
}

This function returns an array with menu link item ids and roles that can access the item. If you already have Menu item visibility installed, you can easily port the data from the db table {menu_links_visibility_role} into this function.

Step 3.

And now let's do the dirty job and process the menu items:

/**
 * Implements hook_translated_menu_link_alter().
 */
function better_menu_item_visibility_translated_menu_link_alter(&$item, $map) {
  if (!empty($item['access'])) {
    global $user;
 
    // Menu administrators can see all links.
    if ($user->uid == '1' || (strpos(current_path(), 'admin/structure/menu/manage/' . $item['menu_name']) === 0 && user_access('administer menu'))) {
      return;
    }
 
    $visibility_items_for_roles = better_menu_item_visibility_menu_item_visibility_role_data();
    if (!empty($visibility_items_for_roles[$item['mlid']]) && !array_intersect($visibility_items_for_roles[$item['mlid']], array_keys($user->roles))) {
      $item['access'] = FALSE;
    }
  }
}

In short this function skips access check for user 1 and for user that has 'administer menu' permission and does the access check for link menu items listed in better_menu_item_visibility_menu_item_visibility_role_data. As you see, instead of calling database it gets data from the code which is really fast.

Let me know what you think and share your ways of fighting with Drupal's inefficiencies.

Feb 26 2014
Tim
Feb 26

Drupal Views offers us a cool feature: ajaxified pagers. When you click on a pager, it changes the page without reloading the main page itself and then scrolls to the top of the view. It works great, but sometimes you may encounter a problem: if you have a fixed header on your page (the one that stays on top when you scroll the page) it will overlap with the top of your view container thus scroll to top won't work preciselly correct and the header will cover the top part of your view.

I've just encountered that problem and making a note here for the future myself and, probably yourself, about how I solved this problem.

If you'll look into the views internal, you'll see it uses internal Drupal JS Framework command called viewsScrollTop that's responsible for scrolling to the top of the container. What we need here is to override this command to add some offset to the top of our view.

1. Overriding JS Command

Thankfully, Views is flexible enough and provides hook_views_ajax_data_alter() so we can alter js data and commands before they got sent to the browser, let's overwrite viewsScrollTop command with our own. In your custom module put something like this:

/**
 * This hook allows to alter the commands which are used on a views ajax
 * request.
 *
 * @param $commands
 *   An array of ajax commands
 * @param $view view
 *   The view which is requested.
 */
function MODULE_NAME_views_ajax_data_alter(&$commands, $view) {
  // Replace Views' method for scrolling to the top of the element with your
  // custom scrolling method.
  foreach ($commands as &$command) {
    if ($command['command'] == 'viewsScrollTop') {
      $command['command'] = 'customViewsScrollTop';
    }
  }
}

Now, everytime Views emits viewsScrollTop command, we replace it with our own custom one customViewsScrollTop.

2. Creating custom JS command

Ok, custom command is just a JS function attached to Drupal global object, let's create a js file and put it into it:

(function ($) {
  Drupal.ajax.prototype.commands.customViewsScrollTop = function (ajax, response, status) {
    // Scroll to the top of the view. This will allow users
    // to browse newly loaded content after e.g. clicking a pager
    // link.
    var offset = $(response.selector).offset();
    // We can't guarantee that the scrollable object should be
    // the body, as the view could be embedded in something
    // more complex such as a modal popup. Recurse up the DOM
    // and scroll the first element that has a non-zero top.
    var scrollTarget = response.selector;
    while ($(scrollTarget).scrollTop() == 0 && $(scrollTarget).parent()) {
      scrollTarget = $(scrollTarget).parent();
    }
    var header_height = 90;
    // Only scroll upward
    if (offset.top - header_height  $(scrollTarget).scrollTop()) {
      $(scrollTarget).animate({scrollTop: (offset.top - header_height)}, 500);
    }
  };
})(jQuery);

As you may see, I just copied the standard Drupal.ajax.prototype.commands.viewsScrollTop function and added header_height variable that equals to the offset/fixed header height. You may play with this value and set it according to your own taste.

Note the name of the function Drupal.ajax.prototype.commands.customViewsScrollTop, the last part should match your custom command name. Save the file in your custom module dir, in my case it's: custom_views_scroll.js

3. Attaching JS to the view

There are multiple ways to do it, let's go with with the simplest one, to your custom_module.info file add scripts[] = js/zukunft_scroll.js and clear caches, that'll make this file to be autoloaded on every page load.

That's all, since now, your views ajax page scrolls should be powered by your customViewsScrollTop instead of stock viewsScrollTop, see the difference?

Dec 30 2013
Tim
Dec 30

December 30th, 2013

This is the 13th issue of the weekly Drupal news round-up and the last one in the year 2013. The last week was pretty silent and it was hard to find something interesting, but in the end I've managed to dig some Drupal gold for you. Today will be no dessert, because of the sad events happening in my country of origin.

Wish you all a Happy New Year! Be healthy and happy, the rest is not so important. Let's Drup Up The Week!

Modules

Code per Node

Code per Node makes it possible to add custom CSS and Javascript per node, per content type, per block, and globally. The code is stored in the database, but served from the file system.

Template Picker

Template picker gives content creators a list of templates to choose from as they create nodes. The templates in this list are auto-discovered in your site's default theme through a simple naming convention: node--content-type--tp*.tpl.php

A Simple Timeline

The Simple Timeline module allows the rendering of entities selected by a view on a simple vertical timeline.

Drupal 8

Drupal 8 Developer Prep

Chris Shattuck has prepared Drupal 8 Prep Video series where he covers essential Drupal 8 dev topics. If you want to be on track, get in and check it out. Lot's of interesting material is inside.

Drupal Snippets

Dec 23 2013
Tim
Dec 23

December 23rd, 2013

Ho ho ho! 12th issue of the weekly Drupal roundup "Let's Drup Up The Week" is out! This pre-Christmas issue is packed with tutorials and useful Drupal 8 tips including blocks, forms and pages in D8, storing geo data in Drupal, doing tests with CasperJS, PHPStorm tricks, Drupal snippets and more!

Let me wish everyone Merry Christmas, don't work a lot during the week and have more fun ;) and... Let's Drup Up The Week now!

Drupal 8

How building modules is different now

Drupal 8 is in alpha now, so its a good time to dip your feet in it and notice the major differences Drupal 8 introduced after adopting some Symfony low-level components.

Articles

Check Your PHP Version

PHP 5.3 has reached end of life and will no longer have any more security updates in 2014 that means a lot of upgrade / maintainance fun is coming...

Modules

Entityqueue

A rewrite of Nodequeue for Drupal 7 based on entities.

Node Embed

Have you ever wanted to include the rendering of node within the content of another node?

Drupal Snippets

Le Dessert

Dec 16 2013
Tim
Dec 16

December 16th, 2013

This is the 11th issue of my weekly Drupal roundup "Let's Drup Up The Week". In this issue you'll find out how to: sync sites with Drush, add pseudo fields to nodes and entities, setup PHPStorm and XDebug, get a list of resources to get started with Drupal 8, learn twig templating system and more!

If you want to receive this weekly roundup as an email newsletter, sign up via the form below. Have a nice read!

Drupal 8

Twig Screencast

See the basics of Twig in this short eight minute long screencast.

This week in Drupal core: December 11 12, 2013

In the past week, we've closed 15 critical issues and 26 major issues, and opened 7 criticals and 15 majors. That puts us overall at 112 release-blocking critical issues and 475 major issues.

Modules

Slug

The slug module manages menu links and urls for node pages in a different way than pathauto and the core menu system. It is much easier to use plus it keeps everything organized neatly.

Ordered List

This module provides the Ordered List field type.

Le Dessert

Dec 09 2013
Tim
Dec 09

December 09th, 2013

Today we have a little anniversary: today is 10th issue of the weekly Drupal news roundup "Let's Drup Up The Week"! And this week, everything is small and simple: not much material and all tutorials are small, quick and simple like creating a drush command or image gallery for Drupal 7. Have a nice read and don't forget to subscribe for email edition of this roundup. Let's Drup Up The Week!

Articles

Views Rewrites

View field rewrites. Pretty basic stuff but maybe useful for newbies.

Drupal snippets

Le Dessert

Dec 02 2013
Tim
Dec 02

December 02nd, 2013

There are so many useful Drupal tutorials and information in the 9th edition of my weekly Drupal round-up, that you can easily spend a week reading all this! Here are the main highlights: porting theme to D8, creating custom field formater for D8, XDebug, drush and theming tricks and, of course, selected Drupal snippets. In the end, as always, Le Dessert. If you want to receive this weekly Drupal news roundup via email just subscribe via the form below! Let's Drup Up The Week!

Articles

The Angry Themer

In this article, let’s explore the art of removing, once and for all — with a few little magic tricks — the clutter of CSS classes and irritating CSS that you never need.

Modules

Webform Scheduler

It adds an optional start date and end date field to the webform form settings, so you can schedule when webform can be opened and closed.

High-performance JavaScript callback handler

This project targets module developers and provides a "bare bone" callback handler which is intended to be addressed by modules wanting to improve response times for specialized tasks.

Flag Limiter

This module allows any flag to have both absolute and user-specific limits added to it.

Drupal Snippets

Le Dessert

Nov 25 2013
Tim
Nov 25

November 25th, 2013

The 8th issue of the weekly Drupal news roundup is out! In the issue: new versions of Drupal 6, 7 and 8, performance tips, recruiting tips, drupal snippets, tutorials and award winning music video for the dessert. Enjoy and let's drup up the week!

News

Drupal 7.24 and 6.29 released

Drupal 7.24 and Drupal 6.29, maintenance releases which contain fixes for security vulnerabilities, are now available for download.

Tutorials

Don’t Bootstrap Drupal, Use Drush

There are times when doing Drupal development when you need to run a custom PHP script, maybe moving data from one field to another, that doesn't warrant the time and effort to create a custom module.

Articles

Check your cache before you wreck yourself

It seems to be a common misconception that Drupal's cache_get checks whether a given cache entry has expired, and won't return a stale result. In fact, in Drupal this is not always the case.

Drupal Snippets

Le Dessert

Gesaffelstein - Pursuit

I've spent the last week at the Camerimage film festival dedicated to cinematographers and their works. The video below became a winner in the Best Music Video competition. The video itself and music track blew me away as well as everyone in the screening room.

[embedded content]

Nov 18 2013
Tim
Nov 18

November 18th, 2013

Another week has started and it's time to wrap up the previous one and warm up for the new week of Drupal. Today's issue is fairly rich on tutorials and techniques including responsive iframes, faster auto-completes, multithreaded migrations and more! At the end as always you'll find Le Dessert, today it's the shortest film evern nominated for an Oscar and the subscription form, remember, you can always subscribe and get this weekly roundup via email. So fasten your coffee cups, Let's Drup Up the Week!

Tutorials

Multi threading Part 2: How to make Migrate move

Drupal Migrate migrations take time, especially when you have lots of entities to get imported. Multi threading comes for the rescue! From this tutorial you'll find out how to use multi threading to speed up migrations dramatically!

Modules

Past Log

Past is an extended logging framework, designed to log and later analyze complex data structures to a pluggable backend.

It can record watchdog events (and be a watchdog module replacement). Also it can capture uncaught exceptions with backtraces and circumvent PHP limitations in error handling with a shutdown handler to capture all possible application errors. It can even scan PHP error.log files for missing pieces.

Views Share

Now you can share views via URL, embed code and oEmbed.

Drupal Snippets

Le Dessert

Fresh Guacamole

The 2013 Academy Award Nominated film by PES. Fresh Guacamole is the shortest film ever nominated for an Oscar.

[embedded content]

Nov 11 2013
Tim
Nov 11

November 11th, 2013

Today is the sixth edition of the weekly Drupal roundup. You'll find lots of interesting Drupal stuff in today's issue: latest D8 news, D8 Alpha get's a monthly release, a list of 13 super useful modules, tips on organizing your modules folder, a stunning Drush extension, Drupal for ELMS and many more topics including some Drupal snippets. Enjoy and remember, if you want to receive this roundup via email, just subscribe via form at the bottom. Let's Drup Up The Week!

Drupal 8

This week in Drupal Core

Notable commits, patches, features and Drupal 8 events in a weekly wrap-up by Drupal core developers.

Tutorials

Exporting Views to Code

A simple tutorial on how to export your Views to code and them make them available in your Drupal modules. Good for beginner Drupal devs.

Modules

Semantic Fields

Semantic Fields was created to give users the abilility of customizing and enhancing the HTML output of a field.

Drush Search & Replace

This drush plugin performs a text search & replace on all content and content revisions in all text fields and all custom blocks on a Drupal site. It does this directly in the database, not by loading, editing and then saving entities, so it is very fast.

Drupal Snippets

Le Dessert

Nov 07 2013
Tim
Nov 07

If you have a fieldgroup in a node, you may want to hide it on some conditions. Here's how to do that programmatically.

At first, we need to preprocess our node like this:

/**
 * Implements hook_preprocess_HOOK().
 */
function MODULE_NAME_preprocess_node(&$variables) {
}

The tricky part starts here, if you'll google for "hide a fieldgroup" you'll get lots of results referencing a usage of field_group_hide_field_groups() like this snippet: http://dropbucket.org/node/130.

While this function perfectly works on forms it is useless if you apply it in hook_preprocess_node() (at least I couldn't make it work). The problem is fieldgroup uses 'field_group_build_pre_render' function that is get called at the end of the preprocessing call and populates your $variables['content'] with a field group and its children, so you can't alter this in hook_preprocess_node(). But as always in Drupal there's a workaround.

At first let's define some simple logic in our preprocess_node() to determine if we want to hide a field group:

/**
 * Implements hook_preprocess_HOOK().
 */
function MODULE_NAME_preprocess_node(&$variables) {
  if ($variables['uid'] != 1) {
    // You can call this variable any way you want, just put it into $variables['element'] and set as TRUE.
    $variables['element']['hide_admin_field_group'] = TRUE;
  }
}

Ok, so if user's id is not 1 we want to hide some fantasy 'admin_field_group'. We define logic here and pass result into elements array that is to be used later. As I previously noted, field group uses 'field_group_build_pre_render' to combine fields into a group, so we just need to alter this call in our module:

/**
 * Hide admin field group on a node display.
 */
function MODULE_NAME_field_group_build_pre_render_alter(&$element) {
  if (isset($element['hide_admin_field_group']) && isset($element['hide_admin_field_group'])) {
    $element['hide_admin_field_group']['#access'] = FALSE;
  }
}

We made a check for our condition and if it is met, we set field group's access to FALSE that means: hide the field group.

So now you should have a field group hidden on your node display. Of course, this example is the simplest case, you may add dependencies on node view_mode, content type and other conditions, so sky is the limit here. You can find and copy this snippet at dropbucket: http://dropbucket.org/node/927

I wonder, if you have another way of doing this?

Nov 04 2013
Tim
Nov 04

November 04th, 2013

Today is the fifth issue of my weekly Drupal news roundup! That was a pretty interesting week that brought us a renewed drupal.org but not only. In this issue you'll find modules that will help you with ads and images, will learn how you can do crazy stuff with drupal fields and themes, read about git and web development approaches of top Drupal shop and in the end, fill up your collection with some pretty useful snippets.

Don't forget that you can get this roundup via email, just subscribe by using the form below. Have a nice Drupal week, let's Drup it up!

Articles

How to Create a Winning Website

To make process of site creation / redesign easier to understand, Chapter Three produced an infographic to illustrate the steps required to create a beautiful and meaningful Drupal website.

Modules

Swipe Photo Gallery

This module provides two dimensional (horizontal + vertical) gallery with the support of swipe on tablet and mobile devices.

Simpleads Better Random

This module provides better random ordering for Ads powered by Simpleads. Actually, it fixes Simpleads randomizer that works really bad.

Drupal Snippets

Le Dessert

Oct 29 2013
Tim
Oct 29

There are situations, when you or other modules alter username via hook_username_alter() and this can change username dramatically: for example, you can alter username into a combination of First and Last Name, etc.

Looks nice, but there's a problem, it will alter username into First and Last Name everywhere, even in admin emails being sent out to users upon registration and instead of real username your users will get an altered username in their mail which is sometimes not good. So what can be done? Hassling with hook_username_alter() and trying to catch cases when you can alter or not username isn't pleasant and here when tokens come to rescue. You can create a custom raw username token which holds unaltered username taken directly from database. Then you can put this token everywhere you need an unaltered username including admin emails.

So let's prepare our custom token, this is simple, put the code below into your custom module (don't forget to replace MODULE_NAME with your module name):

/**
 * Provide information about our custom token.
 */
function MODULE_NAME_token_info() {
  $info['tokens']['user']['name_raw'] = array(
    'name' => t('Name: raw'),
    'description' => t('Raw username taken straight from DB.'),
  );
  return $info;
}
 
/**
 * Provide replacement values for placeholder tokens.
 */
function MODULE_NAME_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  if ($type == 'user' && !empty($data['user'])) {
    $user = $data['user'];
    foreach ($tokens as $name => $original) {
      switch ($name) {
        case 'name_raw':
          $replacements[$original] = $user->name;
          break;
      }
    }
    return $replacements;
  }
}

And clear the cache. You should now have a User: Name Raw token available in the token list. Put it anywhere you need an unaltered username to be shown and profit!

You can find and clone this snippet here: http://dropbucket.org/node/905.

Oct 28 2013
Tim
Oct 28

There are no Rules for D8 yet, so how you can implement new comment notifications? Read on.

In Episode 28: Getting Excited for Drupal 8 - The Donkey, Human, Ant, Chameleon CMS, Larry Garfield, Alex Bronstein, Juampy, and Joe Shindelar join Kyle Hofmeyer to discuss why they are excited about Drupal 8.

A pretty provocative article about Drupal 8 and Backdrop future.

This tutorial shows how to do what you could do in Drupal 7 with just ten lines of code in Drupal 8. Unfortunatelly, you'll have to type a bit more to Drupal 8. How I adore Symfony...

Drupal 8 Image field sweetness!

Oct 21 2013
Tim
Oct 21

A module which allows for limiting items per menu to a certain amount.

With this module you can attach a table, as a field, to any entity.

Oct 14 2013
Tim
Oct 14

What's new in Drupal 8 this week? Goodbye, legacy BC routing support, important API and data model changes, notable commits and many more!

By the end of this week we should get Drupal 8 Alpha 4, yay!

From this article you'll find out how to create and define configurations options for your Drupal 8 module.

Chris Hall shows how to extend db_select to enable paging in Drupal 8

Another good tip by Chris Hall, this time Chris suggests using Honeypot module to block spam submissions. We've been using this module for several modules and I must say the results are pretty good!

At Prague, it was decided that we will replace the major version upgrade path with migrate module.

We all know that Drupal 8 is going to be released "when it's ready", but what does it mean actually? You'll find out from this article.

A list of Drupal 8 live sites. Are you adventerous enough to launch your own site based on D8?

Oct 07 2013
Tim
Oct 07

Today I'm launching a weekly roundup called "Let's Drup Up The Week" to wrap up the previous week and to start up the new week of Drupal. I'm planning to prepare this roundup on a weekly basis listing interesting articles, discussions, modules, tutorials and snippets, all related to Drupal. You can subscribe to this list via the form below to get this roundup delivered straight to your inbox.

Probably you've already noticed the image above? Well, it is related to one of the link listed in this Drupal roundup. Read on and let me know what you think. From now on, if you have interesting Drupal news, send them to me using the contact form. Ok, enough of saying, get yourself some coffee and read on.

Subscribe below to receive next issues of Let's Drup Up The Week newsletter straight to your inbox.

Name *

Email *

Tags 

Oct 01 2013
Tim
Oct 01

If you've missed DrupalCon Prague 2013 or, maybe, you want to relive once again this great party go and see all videos from the event on this page: all DrupalCon 2013 Prague videos. Or use the playlist embed below. There you'll find 4 days, 7 hours long video material (104 videos)!

Tags 

Jul 29 2013
Tim
Jul 29

There are loads of modules that can do this for you, but why to install one more module if you can do this with one string of code? The best thing is that approach below does a redirection even if you login from user login block.


Just put the following code into your custom module:

/**
 * Implements hook_user_login().
 */
function module_name_user_login(&$edit, $account) {
  // Don't redirect on password reset.
  $current_menu_item = menu_get_item();
  if ($current_menu_item['path'] == 'user/reset/%/%/%') {
    return;
  }
  // Redirect user to profile page after the login.
  $_GET['destination'] = 'user';
}

You can find this snippet at dropbucket.org here: http://dropbucket.org/node/746
UPDATE 03/08/2013: Added several lines to prevent redirection during password reset.

Now to a little explanation what we've done here: we used user_login() hook that fires when user logs in. We just set $_GET['destination'] value and profit!

The best part is that this approach works when user log in from the login block. No Rules, no trigger, no any other module I've tried didn't do this for me.

Happy Drupal coding and don't forget to check Drupal snippets repository time from time, there you can find real gems!

Tags 

Jul 04 2013
Tim
Jul 04

I often get emails from beginner Drupal developers asking "Where to learn PHP for Drupal or Drupal PHP?". Actually, "Drupal PHP" is an interesting term, that in the language of beginners means "how to learn writing custom modules and do customizations and understand Drupal internals" that equals to learning and understanding Drupal API.

There are two flavours of Drupal developers: those who can install modules and click trough UI interface. Well, we call them site builders, not developers, but often these two meanings get mixed into one. And there is a second type of developers, that I call true Developers. These guys don't afraid of doing customizations, can override any theme/form, write hooks and if there is no usefull module or module can't do what you want, they can quickly jump in and write their own stuff.

If you want to be that second kind of Drupal developer, here is list of five resources that are indispensable to you:

  1. Pro Drupal 7 Development book. IMHO, that is the only Drupal book you need to read to understand how things work inside: http://www.drupalbook.com/
  2. Videos from BuildAmodule.com (http://buildamodule.com). Especially I do recommend Drupal 7 Development Core Concepts and Drupal 7 Theming Essentials. The narrator has a great style and explains everything very well.
  3. There's a great Examples module that has common dev tasks solved in code: http://drupal.org/project/examples. Study its examples and you'll understand a lot.
  4. Drupal API at http://api.drupal.org. This should be your Bible. The main documentation hub for all Drupal Core functions.
  5. Drupal snippets repository at http://dropbucket.org - place where you can store Drupal snippets and find snippets submitted by others. Has lots of useful stuff to discover.

So this is a bullet proof list of resources that I strongly recommend to study if you want to become true Drupal Developer.

Good luck!

Tags 

Jul 02 2013
Tim
Jul 02

"Woa, what a long title", you must say. Yes it is and it deserves that for sure. But at first, please answer this question: "How many times you've been forced to work on client's server, because of the fact that there are services, that work only with remote server's localhost and can't be exposed to the outer world?". It could be a case with SOAP server or DB (in my case it was MSSQL) which accepts connections only from remote server's localhost.

Doing development work on a remote server is not the most pleasant stuff, if you're not a big fan of vim and connection timeouts. Looking how to solve this annoying problem, I've stumbled upon a little tool called "Sshuttle" (you can grab it from Github here: https://github.com/apenwarr/sshuttle). Here is what project's page says about it "Transparent proxy server that works as a poor man's VPN. Forwards over ssh. Doesn't require admin. Works with Linux and MacOS. Supports DNS tunneling."

In simple words, ir forwards all your Linux/Mac OS X traffic through your remote ssh connection, that makes remote server act as a proxy and think, that you're local. The best thing is that you don't need to have root on a remote server. You just need to be able to access it through ssh.

The concept is so easy and simple that I can't excuse myself for not finding this tool earlier!

Installation

Installation is simple, just do a

git clone https://github.com/apenwarr/sshuttle.git

into any directory you want.

Usage

1) When you want to forward all your traffic through a remote server, you just do this:

/home/username/sshuttle/sshuttle -r remote_server_user_name@remote_server_ip_or_domain_name 0.0.0.0/0 -vv

Note, I cloned sshuttle into my /home/username directory.

2) Then the system will ask for your local root password and after that, it will ask you for your remote server user name password.

3) If eveything goes well and command won't get interrupted, sshuttle will start forwarding all traffic from your Ubuntu/Mac OS to the remote server. You can even open your browser and check your ip, you'll see it has changed to your remote server's ip. Sometimes, however, command breaks, but it is easily fixed by running it again.

4) When you want to stop, just hit Ctrl + C in terminal to abort the command.

My workflow

For every remote server I need to forward my connection I create a .sh file like 'server_name.sh' that has only one line:

/home/username/sshuttle/sshuttle -r remote_server_user_name@remote_server_ip_or_domain_name 0.0.0.0/0 -vv

Then I just run this script:

bash server_name.sh

And get all my connections forwarded to remote server. This way you don't have to remember all your ip addresses and user names.

So that's it. I hope you'll find this tool useful. To me it is a huge life and time saver in one. I want to thank Avery Pennarun for creating this tool.

P.S. Shuttle icon is by Stefan Dziallas from iconwerk.de

Tags 

May 30 2013
Tim
May 30

While working with Migrate and Migrate 2.6 beta 1 I stumbled upon several undocumented "surprises" which are hopefully going to be documented, but so far, you can spend lots of time trying to figure out what may be wrong. Here's roundup of my findings:

1. There is one correct way of registering migrations and handlers

You should do this in hook_migrate_info(), your register code may look like this:

/**
 * You must implement hook_migrate_api(), setting the API level to 2, for
 * your migration classes to be recognized by the Migrate module.
 */
function MY_MODULE_migrate_api() {
  $api = array(
    'api' => 2,
 
    // Custom field handlers.
    'field handlers' => array(
      'ExampleMigrateFieldHandler',
    ),
 
   // Groups.
   'groups' => array(
     'nodes' => array('title' => t('Nodes')),
   ),
 
    // Migration classes.
    'migrations' => array(
      'ExampleNode' => array(
        'class_name' => ExampleNodeMigration',
        'group_name' => 'nodes',
      ),
    ),
  );
 
  return $api;
}

2. Current version of product reference field handler doesn't support multiple values

You heard it right! If you have more than one product reference per field, migration will fail. There is a patch already, however it is not even in dev version of commerce_migrate. But wait no longer, just disable original MigrateCommerceProductReferenceFieldHandler and register your own handler which should look like this:

class CustomMigrateCommerceProductReferenceFieldHandler extends MigrateFieldHandler {
  public function __construct() {
    $this->registerTypes(array('commerce_product_reference'));
  }
  public function prepare($entity, array $field_info, array $instance, array $values) {
    $migration = Migration::currentMigration();
    $arguments = (isset($values['arguments']))? $values['arguments']: array();
    $language = $this->getFieldLanguage($entity, $field_info, $arguments);
    // Setup the standard Field API array for saving.
    $delta = 0;
    if(!is_array(reset($values))) {
      $values = array($values);
    }
    foreach (array_filter($values) as $value) {
      $return[$language][$delta]['product_id'] = reset($value);
      $delta++;
    }
    if (!isset($return)) {
      $return = NULL;
    }
    return $return;
  }
}

.

This is a patched version of the original MigrateCommerceProductReferenceFieldHandler which now supports multi-values.

3. Current version of date_migrate.module doesn't support new way of field_handler registration

Which means that your data fields won't get imported properly if you won't register DateMigrateFieldHandler explicitly. To do this, add it to your hook_migrate_api():

function MY_MODULE_migrate_api() {
  $api = array(
    'api' => 2,
 
    // Date module doesn't register handler according to new Migrate 2.6 requirements
    // that's why we register it here.
    'field handlers' => array(
      'DateMigrateFieldHandler',
    ),
 
    // Our migration classes.
    'migrations' => array(
      'ExampleNode' => array(
        'class_name' => ExampleNodeMigration',
        'group_name' => 'nodes',
      ),
    ),
  );
 
  return $api;
}

4. It is not straightforward how to define migrate destination for commerce_product entity

In your migrate class __construct() function do this:

$this->destination = new MigrateDestinationCommerceProduct('commerce_product', 'YOUR_PRODUCT_BUNDLE_NAME');

Key schema for commerce product is defined as:
MigrateDestinationCommerceProduct::getKeySchema('commerce_product');

5. In migrate 2.6 you can use hash value to track changed source rows

Hope these notes will save someone a little bit of precious time.

Tags 

May 28 2013
Tim
May 28

When you import data with Migrate (http://drupal.org/project/migrate) it is nice to have ability to update already imported data if source has changed. To track updated data Migrate uses highwater marks (more on this: http://drupal.org/node/1223936). Highwater mark is a column of a source data which has timestamp of the last data change. However, the problem with highwater mark is that you don't always have such "time tracking" enabled on source's page. For example, if you migrate users from D6 to D7, there is no field in {users} table, which stores "changed" timestamp, like in {node} table for example.

So what to do? Luckily, Migrate 2.6 beta 1 came out ten days ago which brings us hash value based tracking: http://drupal.org/node/1997616. Now you don't need timestamps/highwater marks. Now, Migrate will automagically create hash value for every row of your source data and will compare it against already stored hashes, if hashes aren't equal, it will treat row data as updated an update it. Pretty neat!

To enable this option, all you need to do is to add 'track_changes' => 1 to $options before you map source in your migrate class constructor, it may look like this:

class ExampleNodeMigration extends Migration {
  public function __construct($arguments) {
    parent::__construct($arguments);
   $options = array('track_changes' => 1);
   $this->source = new MigrateSourceSQL($this->query(), $this->fields(), NULL, $options);
}

Update: put this snippet on dropbucket.org: http://dropbucket.org/node/626

After this, during the first import run Migrate will auto-update all content you have (as if you've forced update option) and create hash values for every row. During next runs, it will import new content and update content that has changed at source.

Hope this tutorial will be helpful, since there is no documentation yet for this really usefull feature.

Tags 

May 24 2013
Tim
May 24

Hi everyone, hope some of you had/having a great time at DrupalCon Portland. Since I could go I decided to do something useful and apply to Dropbucket Drupal Snippets Repository some new ideas I had in my mind. Long story short, last night I rolled out an update which brought the follwing:

  1. New look for listings and category pages. Now there are 30 snippets per page on any list. I removed "code previews", since they occupied lots of space on the page and reworked listing item look in order to make scanning easier. And yes, we ditched View module, bye bye you hungry slow thing.
  2. New page sections like "New", "Hot", "Popular: Month", "Popular: Today". These screens do what they sound like. Filtering algoithm is not ideal, but I'll work on finetuning. Now on the frontpage you see current hot snippets instead of new snippets, to see new snippets you need to look into "New" tab.
  3. Solr brought into action! Now site search is powered with Solr which brings you more precise searching and you can filter through results via facets. Nice!
  4. My snippets section got a rework. Besides individual solr search powered with facets to filter out results, I've changed the way how snippets get into "My snippets" section. Previously you could find there snippets that you created and bookmarked. Now, in addition to new and bookmarked snippets, you'll see there all snippets that you added to snippets lists.

I made a quick hangout overviewing all new features:

So let me know what do you think about all this.

Tags 

May 02 2013
Tim
May 02

"How to find form id in Drupal" is one of the most popular questions, especially for the beginners.

More experienced developers know that to find form id you need to either look into the DOM source code or to create your own hook_form_alter() function like this:

function YOUR_MODULE_NAME_form_alter(&$form, &$form_state, $form_id) {
  dpm($form_id);
}

This function will show you all form ids on the page.

Being really tired of this approach, I decided to write a little module which will solve the problem once and forever. So I created Get Form ID module which is already available at drupal.org: http://drupal.org/project/get_form_id

The module adds a contextual link to every form that lets you easily find out form's ID and name of hook_form_FORM_ID_alter() hook. More details on how it works you can find in the video below:

Let me know what you think.

Tags 

Apr 08 2013
Tim
Apr 08

On 13th - 14th of April 2013 in Wrocław (c'mon, pronounce it, you can: vrɒtswəf) will be held the second in history Polish Drupal Camp (http://dcwroc.pl/). Drupal scene in Poland is still relativelly small, but for sure is very promissing. Three years ago I moved to Poland and almost no one I met knew a thing about Drupal. Today Drupal is pretty much visible here, with big projects based on Drupal (including the official website of Polish Prime Minister) and increasing demand for the talent the number of which is still scarse.

More than a half ago I met nice people here in Gdansk where I currently reside and we've started local Drupal Tricity Users Group. The group has attracted lots of attention thanks to our more or less regular online meetings via Google hangouts. These hangouts turned out to be the first tech hangouts in Poland!

In five days we're leaving to the south of the country for Drupal Camp in Wroclaw. Looks like the event will attract 100+ people from all over the Poland and there are some guests from other countries. This year the conference is going to be billingual, half of sessions (held on April 13th) will be in english.

Here is the list of english language sessions:

    I'm especially looking forward to my session: never had a chance to talk in front of such a big crowd and the fact that my session got the biggest number of votes puts additional pressure and, at the same time, hype on me :)

    Hope to see and talk to you (oh and to party with you, there's a Drupal party on 13th of April in the evening) folks there :) See you in Wroclaw!

    Tags 

    Mar 25 2013
    Tim
    Mar 25

    Yes, you read it right! Now you can create personal lists of Drupal snippets at Dropbucket.org - Drupal snippets repository. It turned out that we already have loads of great snippets at the website and there challenge have appeared: how to group these snippets in some convenient way? So for example, you found five cool snippets about theming and you could add them to your bookmarks, but later, you can lose track of them because you're constantly adding other snippets to your bookmarks and sooner or later you can simply get lost in your bookmarks feed.

    So I thought about this problem and decided to develop "Add to List" feature which now lets you to create any number of snippet lists (public or private) and add any number of snippets to these lists. Here is an example of how such list looks like: http://dropbucket.org/list/298.

    The list can be shared, commented and the best part - it can be cloned! So if you like someone's snippet list you can clone it and extend!

    I tried to make snippet list creation process as smooth as possible. On snippet pages and on snippet views you should note this link:

    Click on it and you will see a popup like this:

    As you see, I already have three lists created and I can add a snippet to any list by clicking on checkbox near the list name. Also I can filter through my lists by list title. And in the end, at the very bottom, I can create a list easily bu just entering its name in the textbox, easy!

    After you've added at least one snippet list, you will see a jump menu on the right in a sidebar where you can select any of your lists and quickly jump between:

    So this is it :) Go and play with this new feature. Now we can create lists of great snippets and share them inside our team or with the community, think of such lists as "Performance Tweaks" or "SEO Snippets". And don't forget to let me know what you think about it :)

    Tags 

    Mar 19 2013
    Tim
    Mar 19

    Today I want to share with you 8 great Drupal snippets that blew my mind. I found these browsing Dropbucket.org - Drupal snippets repository. There are lots of cool Drupal snippets being shared and stored at dropbucket.org but I found these to be the most new and interesting to me. I do really wish I knew about before. But Drupal is full of surprises and there are loads of tricks which don't know about, even if you've spent lots of years working with The Big Drop :) Okay, let's start. Snippets aren't sorted in any order of preference:

    1. Find which modules implement specific hook

    This is a drush trick which will return list of modules which implement given hook:

    drush ev "print_r(module_implements('menu'))"

    Submitted by Pierco, you can find this snippet here: http://dropbucket.org/node/135

    2. Automatic Drush site aliases

    This is another Drush related snippet. Actually it is a Drush module which automatically creates Drush site aliases for your Drupal multi-site environment.

    $aliases = array();
    $drupal = '/var/www/drupal';
     
    // Automatic alias for each Drupal site
    $site = new DirectoryIterator($drupal . '/sites');
    while ($site->valid()) {
      // Look for directories containing a 'settings.php' file
      if ($site->isDir() && !$site->isDot() && !$site->isLink()) {
        if (file_exists($site->getPathname() . '/settings.php')) {
          // Add site alias
          $basename = $site->getBasename();
          $aliases[$basename] = array(
            'uri' => $basename,
            'root' => $drupal,
          );
        }
      }
      $site->next();
    }
     
    // Get all site aliases
    $all = array();
    foreach ($aliases as $name => $definition) {
      $all[] = '@' . $name;
    }
     
    // 'All' alias group
    $aliases['all'] = array(
      'site-list' => $all,
    );

    Credits go to BWPanda, you can find this snippet here: http://dropbucket.org/node/84

    3. Dev site settings.php tweaks

    Some standard configuration ($conf) variables which can be added for dev sites. Placing these configs in settings.php will enable lot's of dev-related functions by default:

    $conf['file_public_path'] = '/absolute/path/to/public/files/directory';
    $conf['file_private_path'] = '/absolute/path/to/private/files/directory';
    $conf['file_temporary_path'] = '/absolute/path/to/tmp/directory';
    $conf['securepages_enable'] = FALSE;
    $conf['devel_enable'] = TRUE;
    $conf['reroute_email_enable'] = TRUE;
    $conf['cache'] = FALSE; //page cache
    $conf['block_cache'] = FALSE; //block cache
    $conf['preprocess_css'] = FALSE; //optimize css
    $conf['preprocess_js'] = FALSE; //optimize javascript
    error_reporting(-1);
    $conf['error_level'] = 2;
    ini_set('display_errors', TRUE);
    ini_set('display_startup_errors', TRUE);

    Submitted by ultimike, you can find this snippet here: http://dropbucket.org/node/216

    4. Change taxonomy term path

    This snippet let's you to change default 'taxonomy/term/tid' path for any vocabulary! Ubercool!

    function MY_MODULE_entity_info_alter(&$entity_info) {
      $entity_info['taxonomy_term']['uri callback'] = 'MY_MODULE_taxonomy_term_uri';
    }
     
    function MY_MODULE_taxonomy_term_uri($term) {
      switch ($term->vocabulary_machine_name) {
     
        case 'vocabulary_one':
          return array(
            'path' => 'vocabulary-one/' . $term->tid,
          );
        break;
     
        case 'vocabulary_two':
          return array(
            'path' => 'vocabulary-two/' . $term->tid,
          );
        break;
     
        default:
          return array(
            'path' => 'taxonomy/term/' . $term->tid,
          );
        break;
      }
    }

    Big thanks to malcolm for sharing, you can find this snippet here: http://dropbucket.org/node/92

    5. Easy way to hide a field group including children

    This snippet let's you hide any fieldgroup and its children for any form:

    function MODULE_form_node_form_alter(&$form, &$form_state) {
      if (!user_access('admin_role_name')) {
        field_group_hide_field_groups($form, array('group_for_admin_name'));
      }
    }

    Submitted by Netlooker, you can find this snippet here: http://dropbucket.org/node/130

    Next two snippets do the same thing but leveraging different approaches:

    6. Remove all markup of a field

    Strip off field's markup on node_view level. Useful when you want to "clean" lots of fields at a time:

    /**
     * Implements hook_node_view_alter().
     */
    function YOUR_THEME_node_view_alter(&build) {
      unset($build['YOUR_FIELD_TO_EDIT']['#theme']);
    }

    Submitted by piouPiouM, you can find this snippet here: http://dropbucket.org/node/231

    7. Clean all markup of a field with "nomarkup" theme function

    Theme level approach. Useful when you want to clean a particular field in a particular template.

    /**
     * Implements HOOK_theme().
     */
    function YOUR_THEME_NAME_theme(){
      return array(
        'nomarkup' => array (
          'render element' => 'element',
         ),
      );
    }
     
    /**
     * Cleans all markup of a field.
     */
    function theme_nomarkup($variables) {
      $output = '';
      foreach ($variables['items'] as $delta => $item) {
        $output .=  drupal_render($item);
      }
      return $output;
    }

    Then you can use this theme function in your .tpl file to get clean content from a field:

    <?php
      $content['field_NAME']['#theme'] = "nomarkup";
      // Print a clean from markup field
      print render($content['field_NAME']); 
    ?>

    And as the dessert, here is my favorite Drupal snippet:

    8. Cache regenerator

    This snippet will regenerate your cached pages by visiting them one by one which is done thanks to xmlsitemap module and wget, look how simple it is:

    #!/bin/bash
    # Drupal cron
    wget -O - -o /dev/null http://example.com/cron.php?cron_key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    # Visit every page from your sitemap.xml
    wget --quiet http://example.com/sitemap.xml --output-document - | egrep -o "http://example.com/[^<]+" | wget -q --delete-after -i -

    So there were 8 Awesome Drupal snippets I wish I knew before :) Hope you like them and that at least one of them is news for you. Come and joing growing community at Dropbucket.org where Drupal folks share and store great snippets!

    Tags 

    Mar 04 2013
    Tim
    Mar 04

    A week ago I've announced a project which I created in order to fullfill my own need of storing Drupal snippets - Dropbucket.org. I've announced this project here on my blog and it turned out to be a huge success attracting lots of eyes, positive responses, thanks, clicks, tweets and registrations. I'm really amazed by reactions I received and today I decided to sum up the first week of life of the Dropbucket.org.

    The announcement itself gathered 5000 views in a week and got 52 retweets, 33 google pluses, 15 shares on linkedin and 262 likes on facebook! All these numbers tell by themselves, drupal people liked the idea of a Drupal snippet repository and gladly shared info about the project with their friends and followers. I want to thank everyone for the support and mentions on the internet, spreading the word about Dropbucket.org helps to grow the project and bring more people in.

    Now to Dropbucket's numbers. 500 users have registered on the website and 150 snippets has been added during the first week which is really really impressive! People from 102 countries (Hi to Drupal folks from Zimbabwe) visited dropbucket.org spending 4 minutes on the site on average.

    These are really impressive numbers which motivate me to develop the idea and add new features. During the last week, I've introduced several new features like voting on snippets, filtering snippets by author's name and showing author's name on listing pages. I've got lots of different feature request and I will try to implement most requested for sure. I've even created a facebook fan page for the project, although I'm not the biggest fan of facebook, this page is a good way to inform everyone about latest happenings at dropbucket, feel free to follow/like it, the url is as simple as http://www.facebook.com/dropbucket.

    I'm planning to introduce API soon (one of the most requested features out there), so people will be able to import / export snippets and write their own IDE plugins (like a plugin for Sublime for example).

    I want to thank again everyone for your amazing support and I'm happy you liked the idea of dropbucket.org. The biggest thing you can do to help us is to tell about dropbucket on your blog, twitter, facebook or google account and, of course, contribute your snippets! Let's the story continues!

    regards,
    Tim Kamanin

    Tags 

    Feb 25 2013
    Tim
    Feb 25

    Dropbucket - Drupal snippets storage

    I've been doing Drupal for last six or seven years and tried lots of ways of storing snippets. I used internal capabilities of IDE's (like snippets in Eclipse or code templates in Netbeans), I stored them in notepad, evernote, used lots of different downloadable snippet managers and stuff.

    But there always were two needs which I couldn't satisfy with these approaches: I wanted snippets to be stored online (so I didn't lost them when I format my HDD or uninstall IDE) and I wanted to share my drupal snippets in a dedicated place, where drupalers gather.

    We Drupal people, we love to share, this is in our blood and this is an underlying power which drives Drupal community, do something and share with others! So why not to share with our snippets? I believe every of us has loads of different chunks of code which we use on a daily basis, we need to store them, we need to share them. That's why I created dropbucket.org - Drupal snippets repository, a place where you can put your little drops of drupal code and fill the snippet bucket.

    Feel free to go and register now to start storing and sharing your snippets. Below I will tell you about some cool features which are waiting for every drupaler at Dropbucket:

    1. Brandable profile address

    Upon your registration, you get a profile url like http://dropbucket.org/your_username, so hurry up to take up your name :)

    2. Snippet add form

    After registering, you can start to add snippets via "Snippets add form" which has only two mandatory fields to fill: title and code. Hovewever, I do encourage you to add some description to your code and assign category/drupal version to it, so this is convenient to browse your snippets in the future.

    You can add as many code chunks per snippet as you want by using "Add another source code" button.

    There are situations, when we don't want others to see our snippets, so every snippet can be marked as "private" and will be visible only for you.

    3. Snippet browsing and discovery

    Browsing snippets is flexible. You can search snippets by keyword, filter results by categories and drupal versions. There are two flavours of snippet browsing: sitewide, when you browse all snippets submitted to dropbucket.org and personal, when you browse your own snippets via "My snippets" page.

    There is also a nice feature suggested by one of early beta testers: you can subscribe to rss feed of any snippet search result, so for example, you can filter "Form API" snippets for "Drupal 7" and get a feed link like: http://dropbucket.org/rss.xml?keys=&field_category_tid=58&field_drupal_version_tid=4. Now you can add this link to your rss reader and get updates every time something appears in this category!

    4. Snippet page

    On a snippet page you can get a raw version of a snippet or you can copy a snippet to your clipboard by clicking "Copy" button:

    Also there is a possibility to "clone" a snippet. So this way you can create your own version of a snippet and place it under your account:

    Another possibility to put a snippet under "My snippets" is to bookmark a snippet:

    Once you bookmarked it, you can find a snippet on "My snippets" page.

    Every time you edit a snippet you automatically create a version of it. So all snippet changes are revisioned and you can see differences between revisions and revert your code to any of revisions:

    In the end, you can leave a comment for every snippet just to thank author of the snippet, ask a question or suggest a correction.

    5. Drupal karma

    For every action you do on dropbucket you get a Karma points which are visible on your public profile:

    This is a some kind of reward for activity and a way to find out who is the MVDSS (the most valuable Drupal snippets submitter :))

    So this was an overview of the initial version of dropbucket.org. There are more features I plan to add in the future like a public API and exporting of snippets to elcipse/sublime/other IDEs. Feel free to leave your suggestions, this way you will help me to introduce needed by a community features.

    I need your help to spread a word

    If you like the idea of dropbucket.org and you have a blog/twitter/facebook/google+ account or have an access to other media sources, please don't hesitate to share info about dropbucket.org. This way we'll let more drupal developers to find out about this service, which means we'll have more cool snippets to share and discover.

    Thank you in advance,
    Tim Kamanin

    Tags 

    Feb 21 2013
    Tim
    Feb 21

    This post is a quick addition to my previous tutorial: Loading Only One Field From An Entity or Node in Drupal 7. The tricky part there was what to do with node's field data and how to properly display it? Well there are lots of approaches there, but I see three which are of “Drupal Way” kind:

    1) Get raw field data via field_get_items(). This approach may be useful if you need field data for other than displaying the field puproses.
    2) Display single (with multivalues) field via field_view_field(). Returns a renderable array for the value of a single field in an entity. The resulting output is a fully themed field with label and multiple values.
    3) Display single (one value only) field via field_view_value(). Returns a renderable array for a single field value.

    So let's imagine we have an entity object: $node.

    Approach 1. We want to get node's field_story_image raw value, here's how to do that:

    $image_field_raw = field_get_items('node', $node, 'field_story_image');

    UPDATE: put this snippet on dropbucket for future reference: http://dropbucket.org/node/55

    As a result we have an array of raw field values which aren't anyhow preprocessed and look like they'd come directly from database.

    Approach 2. We want to get field ready for display and we're ok with displaying all field's values (In case the field is multivalued):

    $image_field  = field_view_field('node', $node, 'field_story_image');

    As a result, in $image_field we get a renderable array for all values of the field. Calling render($image_field) will nicelly render the image (or images if there are multiple) for us. By render I mean turning drupal arrays into consumable html.

    The cool thing about this approach is that you can get field rendered via any of formatters available for the field, for example, we want to get body field trimmed:

    $body_field  = field_view_field('node', $node, 'body', array('type' => 'text_trimmed'));

    Now in $body_field you have a rendered array for the body field of your node. Note that we passed formatter name in array('type' => 'text_trimmed') array. But we can do even more. Knowing that 'text_trimmed' formatter has a setting called 'trim_length' we can set this setting on the fly. Let's trim our field on 150 characters limit:

    $body_field  = field_view_field('node', $node, 'body', array('type' => 'text_trimmed', 'settings' => array('trim_length' => 150)));

    UPDATE: put this snippet on dropbucket for future reference: http://dropbucket.org/node/56

    Approach 3. We want to display a node field, which can be multivalued but we are only interested in first value. Let's output our field_story_image and make the task even a bit more complex: let's resize image and link it to its node!

    At first we need to get all raw values of a field (see approach 1):

    $image_field_raw = field_get_items('node', $node, 'field_story_image');

    After we got all values for a field, we want to pass them to field_view_value() like this:

    $single_image_field = field_view_value('node', $node, 'field_story_image', $image_field_raw[0],
      array(
      'type' => 'image',
      'settings' => array(
        'image_style' => 'medium',
        'image_link' => 'content',
      ),
    );

    UPDATE: put this snippet on dropbucket for future reference: http://dropbucket.org/node/57

    In the end, we get a renderable array for a single value of 'field_story_image' which is resized according to 'medium' image style and is linked to a node, voila!

    Tags 

    Feb 20 2013
    Tim
    Feb 20

    Time from time, while doing your custom Drupal code, you may want to load only one or several specific fields from a defined set of entities. So actually you have three approaches to this:

    1. Query for entity/node set and load whole entities to get desired fields data. Works, but not a performant solution.

    2. Make a direct sql query and get desired fields out of your database. Works too, is the fasted in terms of performance solution, but not too flexible and portable.

    3. Leverage EntityFieldQuery() and field_attach_load(). This approach is not as fast as the second, but way more faster than loading whole nodes, it is flexible and uses field caching mechanism. If you'll decide to change your database backend later in the future, let's say to MongoDB, you'll be able to switch without changing a line in your code, neat!

    But the biggest thing I love about the following approach is that you don't care if you field is single valued or multivalued. You'll get all the values without too much hassle.

    So let's get in more details. EntityFieldQuery() allows finding entities based on entity properties (for example, node->changed), field values, and generic entity meta data (bundle, entity type, entity id, and revision ID). More details about what EntityFieldQuery() can do for you find in official docs here: http://api.drupal.org/api/drupal/includes%21entity.inc/class/EntityField...

    Now let's imagine a sample task. We'll need a list of image urls of image fields attached to nodes of type "Story". So how do we get this list? Simple, watch my moves:

    1. Let's use EntityFieldQuery() to query a list of our article nodes:

    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'story')
      ->propertyCondition('status', 1)
      ->fieldCondition('field_story_image', 'fid', 'NULL', '!=');
    $result = $query->execute();

    So we queried for a list of nodes of type "story" and made sure that node has image attached to it. Imagine yourself doing this query via raw sql.

    $result should return us a list of entity ids. Node ids should leave in $result['node']:

    if (isset($result['node'])) {
      $stories = $result['node'];
    }

    Yes, we have to check if we have $result['node'] is set, because EntityFieldQuery() returns empty array in case if didn't find any nodes.

    2. Now to the most interesting part. Okay, we have an array of node ids, so now we want to load only 'field_story_images' for these nodes. We'll use field_attach_load() to do this:

    if (isset($result['node'])) {
      $stories = $result['node'];
     
      // At first we need to get field's id. If you already know field id, you can ommit this step
      // Get all fields attached to a given node type
      $fields = field_info_instances('node', 'story');
     
      // Get id of body field
      $field_id = $fields['field_story_image']['field_id'];
     
      // Attach a field of selected id only to get value for it
      field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));
    }

    I described what we're doing in each step in the code, so everything should be pretty much understandable. In the end, we're getting $stories array, which holds "semi-loaded" nodes with only field we queried attached.

    Caveat. field_attach_load() doesn't invoke hook_node_load(), so if some data is being manipulated via hook_node_load() you won't get its representation via described method. This is the only drawback of this method. But in most cases it is safe to use. Just check if it works in your situation.

    3. To access your list of values you can do the way you access full node's values, something like this:

      // Get values of our node field
      $output = field_get_items('node', $node, 'field_story_image');

    That simple! So for those who could get lost, here's the full code:

    $query = new EntityFieldQuery();
    $query->entityCondition('entity_type', 'node')
      ->entityCondition('bundle', 'story')
      ->propertyCondition('status', 1)
      ->fieldCondition('field_story_image', 'fid', 'NULL', '!=');
    $result = $query->execute();
     
    if (isset($result['node'])) {
      $stories = $result['node'];
     
      // At first we need to get field's id. If you already know field id, you can ommit this step
      // Get all fields attached to a given node type
      $fields = field_info_instances('node', 'story');
     
      // Get id of body field
      $field_id = $fields['field_story_image']['field_id'];
     
      // Attach a field of selected id only to get value for it
      field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));
     
      // Get values of our node field
      $output = field_get_items('node', $node, 'field_story_image');
    }

    UPDATE: put this snippet on dropbucket for future reference: http://dropbucket.org/node/54

    As you see, the described approach is pretty neat, you get all values of a field in one go and you leverage Drupal cache mechanism. More over, if you want to query for several fields, you need to add just two more lines to our code, let's say, in addition to image fields we want to get a body field, so after:

    // Get id of body field
    $field_id = $fields['field_story_image']['field_id'];
     
    // Attach a field of selected id only to get value for it
    field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

    you just need to add:

    // Get id of body field
    $field_id = $fields['body']['field_id'];
     
    // Attach a field of selected id only to get value for it
    field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));

    And you'll get a body field attached too! Or in more cleaner way these two fields attachment could look like:

    // Get all fields attached to a given node type
    $fields = field_info_instances('node', 'story');
     
    // Put all field names you want to load
    $field_names = array('field_story_image', 'body');
     
    foreach ($field_names AS $field_name) {
      // Get id of body field
      $field_id = $fields[$field_name]['field_id'];
     
      // Attach a field of selected id only to get value for it
      field_attach_load('node', $stories, FIELD_LOAD_CURRENT, array('field_id' => $field_id));
    }

    Wow that was a long read, but if you've survived till the end this means that now you have a powerful tool in your skillset. Go and try it!

    Tags 

    Jan 28 2013
    Tim
    Jan 28

    I’ve been using menu position module (http://drupal.org/project/menu_position) for some time and this is a really handy module I must say. It lets you set an active menu item based on different conditions. For example: you want products menu item to be set as active while you’re browsing nodes of content type “Products”.

    But I really missed one part of functionality for this module: I wanted to make a menu item active depending on a vocabulary which current taxonomy page belongs to. For example, you have a menu item “Articles” and you want this menu item to be set as active while you browse any category page which belongs to vocabulary “Article categories”.

    So I created a menu positon vocabulary module (now is live on drupal.org: http://drupal.org/project/menu_position_vocabulary) which itself is a plugin for menu position module. It provides user with "Vocabulary" tab available in menu position settings. In this tab you can select one or multiple vocabularies, this will activate menu position rule for taxonomy term pages which belong to selected vocabularies.

    Pretty simple :) Hope you’ll be enjoying this little addition and yes, now I have a permission to create full projects on drupal.org, so get prepared for more cool modules, I already some on the pipeline.

    Tags 

    Jan 23 2013
    Tim
    Jan 23

    A week ago Packt Publishing approached and asked me to review their new book called “Drupal Rules How-To” written by Robert Varkonyi. I like getting books for a review, because it motivates you to read. With my working schedule it’s hard to find time for another tech read, but when you give a promise to someone, you can’t retreat ;) So I agreed, read the book and here is my unbiased review.

    The book is about Rules (http://drupal.org/project/rules) module which is an indispensable tool for any Drupal developer. In simple words Rules lets you fire different actions on your site which are based on different events and conditions (for example, show “Have a nice weekend” to all users on Friday, when they visit frontpage.”). You can create different workflows without writing any code, by just clicking stuff in user interface.

    The book shows in full how to work with Rules and how to make them do what you want. It consists of 19 chapters which are labeled by one of three difficulty levels: Must know (beginner), Should know (Intermediate), Become an expert (Advanced).

    In “Must know” labeled chapters you will get useful information on how to display messages on a site, how to send notifications to users if someone comments on a node, how to reuse rules sets and how to debug Rules. Also in this chapter you will get introduced to a nice addon to Rules module called Rules scheduler. It can be used to fire actions based on date and time conditions.

    “Should know” part of the book is a bit more advanced. There you’ll get info on how to use custom php code in conditions and actions and how to subscribe to node comments by leveraging Rules and Flag module integration. My favorite part is about Views Bulk Operations and Rules integration. This couple will give you the power to create impressive administration interfaces for your website.

    Chapters labeled as “Become an expert” are mostly about custom code. There you will find out how to fire Rules programmatically and how to create custom events, actions and conditions which actually gives you limitless possibilities.

    The book is not a long read (only 60 pages), but it gives you lots of useful information about Rules. All chapters are easy to follow and repeat: they are written in step-by-step style, text is supported by screenshots and snippets. I advise you to learn by doing: recreate everything what’s written in this book (don’t just read) and you’ll get a good understanding on how Rules work.

    To sum up, Drupal Rules How-To is a good read for every Drupal site builder and developer. It is not long story, so you won't get bored. In the end, you’ll get a solid understanding of how Rules work along with a bunch of nice recipes which are ready to use in your current web projects.

    if you like reading real books, then you can get a paperback version from Amazon too (Paperback version of Drupal Rules How-To book).

    Tags 

    Jan 21 2013
    Tim
    Jan 21

    I’ve recently finished working on a project for a client. This was an interesting journey and I want to tell you about it.

    Several months ago a client approached to me with an interesting idea to create a social website where people could come and publish their top lists of everything you can imagine (for example, Top 5 Restaurants in Beijing). Client had his own vision of a project and wanted it to be implemented on Drupal, because of its modular nature and community support. After taking client’s vision and translating it into Drupal we came to what ended up as Listbattle.com (http://listbattle.com).

    Listbattle.com - Drupal site

    Main project requirements were:

    1) Cool looking and convenient in creation “List” content type which has a custom background option and multi valued list of items.

    2) Social functionality including users activity feed, awards for achievements, ability to follow other members activity and see own content.

    3) Listings with data sorted by day/week/month view stats.

    Below I’ll tell a bit about different functionality points and how they were implemented.

    1 Content type: List

    At the heart of listbattle.com lies a List content type which consists of different fields provided by Field API. I had several challenges implementing this task:

    1.1 List positions

    List positions are of multi valued nature and each position consists of several fields including: title, description, video url, media upload and media type.

    To solve this problem I could go with Field collection (http://drupal.org/project/field_collection) module, but it would ended up not so good for performance. Each field_collection is an entity with 5 fields attached to it. This would produce 6 records in 6 different tables per one list position!

    Thats why I created a custom field module which creates a custom field which holds all five fields, which creates one row in one table per position + gives nice integration with Views and gives possibility to handle this field in MongoDB in case of need.

    List item

    1.2 Youtube url handling

    One interesting feature of list position is a Youtube video url field. To embed a video you just need to put youtube url in it and custom field api will validate this url and embed video on the fly.

    Youtube videos

    1.3 Background images

    Every list can have a custom background, it can be predefined or uploaded by user. I looked at dynamic_background (http://drupal.org/project/dynamic_background) module at first. But it didn’t meet all our requirements plus it wasn’t so themeable without hacking. In the end it turned up to be easier to create one more custom Field which holds custom background data per node/entity.

    Custom background images interface

    1.4 Dynamic titles with placeholders

    If you look at titles of List, it is dynamically generated from the data users enter. It has three predefined templates, like “Top X _____”, “___Top X_______”, “_____X________”, this was done to standardize titles which users create. To achieve this, I created a custom Field which holds title format, prefix, suffix and title text for each node. To dynamically change title input fields I leveraged Drupal Ajax framework which is really cool!

    Dynamic titles

    1.5 Battle / Relist functionality

    Every list can be relisted (user can create own list based on any list) and battled (user can create his own version of your top 5 cartoons and put your list on a battle). I could use node clone (http://drupal.org/project/node_clone) module here but it turned out that our “clonning” process was a bit more complicated. In the end I created a custom module to leverage two different “clonning” workflows taking some nice ideas from node_clone’s module.

    Battle / Relist functionality

    1.6 Social sharing

    Every list can be shared on facebook/google/twitter via widgets provided by easy_social (http://drupal.org/project/easy_social) module.

    2 Social features

    Every user has a profile which has several interesting features, including:

    2.1 Activity stream

    The requirement was to create an activity stream for each user and to show all user’s and his friends activity and give a user ability to shout on his own “wall”. To achieve this, I used heartbeat module heavily customized via heartbeat API to play nicely with shoutbox module. I created heartbeat message templates for every needed activity (for example, “user X posted list Y”, “user A commented on List B”) and create them via Rules (http://drupal.org/project/rules) module, which takes care of creating actions depending on events.

    Activity stream on Listbattle.com

    2.2 Achievements

    Users can earn achievement badges depending on their actions. To make this possible I used achievements API (http://drupal.org/project/achievements) and created custom badges for different events and put rules in charge of controlling all of this. There are some badges at Listbattle which are dependent on custom user stats such as posts count, login counts, comments count etc. To count all these a custom userstats module was created. Possibly I will release it on drupal.org for public, after some polishing.

    User pane

    2.3 Facebook login

    Users hate to register and almost everyone is on Facebook right now. To leverage this, Listbattle.com has Facebook Login/Sign Up function on a site powered by fboauth (http://drupal.org/project/fboauth) module which I highly recommend to use in such cases.

    2.4 User views

    At profile pages users can see favorite, created lists, list of people whom they follow and who’s following them. I used Views extensively to implement this functionality.

    User views

    3 Listings

    There are more than 10 different views to show List content types: category/tag views, top of the day/week/month lists and more.

    Navigation

    The most interesting part here is day/week/month popular list views, where we needed to show popular lists and sort them by daily/weekly/monthly view stats data. The problem was even more complicated: we needed to gather stats on cached pages, which is impossible to do via standard hook_exit() methods. There were no ready made module to solve this, so I created entity_stats module (to be submitted to drupal.org soon), which can count view stats on node/user/taxonomy pages even if these pages are cached.

    So these are major features of Listbattle.com and my story about how Drupal was leveraged to implement these features. On overall there were created 17 custom modules for the project, several of them to be shared on Drupal.org soon.

    Current version of Listbattle.com is mvp (minimal viable product) actually, Listbattle.com team are working on building great content and there are lots of cool new features to be implemented in the future. Stay tuned.

    At the end, here are some impressions from client about the project and our work together:

    "The creation of List Battle has been both fun and in many ways instructive project. It evolved from a simple idea based on giving ordinary Internet users the opportunity to rank and categorize content on a toplist in a simple way, to becoming a relatively complex and complete project.
    It resulted in an end product that I am very pleased with.
    Tim is an extremely talented and developer, but he is also much more than that; He is a good communicator, he has a good visual and graphical understanding and then he is also extremely good at understanding projects from both a business-marketing standpoint and an end-user point of view.
    I doubt Listbattle had ever been so well executed without Tim, so I feel very fortunate to have had Tim as a developer on the project, and I would not hesitate to work with him in the future." - Jeppe Nielsen, Listbattle.com

    Tags 

    Jan 01 2013
    Tim
    Jan 01

    Wanted to share with you all a cool thing I got for Christmas from my cool wife :) A handmade Druplicon!

    Handmade Druplicon

    I guess I'm spending too much time with Drupal if even my wife knows how Druplicon looks like ;)

    Tim and Druplicon

    Wish you a Happy New Year, let your dreams come true!

    Tags 

    Dec 24 2012
    Tim
    Dec 24

    I want to wish Merry Christmas to all Drupal people all over the world!

    santa-drupal.jpg

    Get away of your computers, nodes, views and entities. Type exit in your terminal and spend some time with your family :) They deserved it.

    P.S. On a picture you see a Santa-styled logo of Drupal Trojmiasto Group (http://3drupal.pl), some cool things are happenning with Drupal here, but more on that after holidays. Take care!

    Tags 

    Oct 22 2012
    Tim
    Oct 22

    Time from time you need to update single or several specific fields of your entity in Drupal. It can be node, comment, taxonomy or some other custom entity. So how do we usually do this? Let's see:

    $node = node_load(1); // 1 is node id we want to load
     
    // Change field value
    $node->field_product_description[$node->language][0]['value'] = 'This is a very nice and useful product. Buy it now! We want your money!';
     
    // Save updated node
    node_save($node);

    This approach is totally ok, but hey, your poor Drupal did a massive job to update just one field: it loaded the whole node into memory and then, saved every field (even which wasn't updated) one by one into database. If your nodes are pretty big, it can produce a lot of unnecessary queries.

    Here's how to update entity field in a more "diet" way by using Drupal 7 Field API, this is a general code template:

    // Get the numeric id of your field by passing field name
    $info = field_info_field('field_name_goes_here');
    $fields = array($info['id']);
     
    // Execute the storage function
    field_sql_storage_field_storage_write('entity_type', $entity, 'update', $fields);
     
    // Clear field cache
    cache_clear_all("field:$entity->type:$entity->id", 'cache_field');

    And here's how to use it on practice:

    $node = node_load(1); // 1 is node id we want to load
     
    // Change field value
    $node->field_product_description[$node->language][0]['value'] = 'This is a very nice and useful product. Buy it now! We want your money!';
     
    // Get the numeric id of your field by passing field name
    $info = field_info_field('field_product_description');
    $fields = array($info['id']);
     
    // Execute the storage function
    field_sql_storage_field_storage_write('node', $node, 'update', $fields);
     
    // Clear field cache
    cache_clear_all("field:node:$node->nid", 'cache_field');

    So now, we updated only one field of the node without updating the whole node. Please note, that you can pass as many fields as you like via $fields array, so you can update more than one entity field at once.

    That's all for now, thanks for reading this. Share with others!

    A VERY BIG NOTE: Using this technique you can't rely on drupal hooks system. No hooks are being invoked, updated nodes won't be queued for search indexing if you won't do this manually. Be awared.

    Tags 

    Pages

    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