drupal 7

Drupal Migrate: Don't forget to de register your classes

Often times when writing a module to migrate content leveraging the Migrate module you will find yourself disabling and re enabling your module as you add classes to it.
When you do this you might find that you get errors about classes not being found or that your migrations are still being displayed in the interface even though your module is disabled (when using a class from another module such as d2d_migrate).
To get around this, make sure you de register your migration classes in a HOOK_disable() function in your module.

 function MYMODULE_disable() { 

Stopping Drupal spam registrations without an annoying captcha

There are many modules out there to prevent spam registrations in Drupal, but many of them involve some sort of Captcha, which I hate, or a paid for service. Stopping fake site registrations should not make it harder for the legitimate people trying to register on your site, and having to pay to prevent spam does not sit well with me.
While Drupal does have a setting to "Require email validation", I do usually have this enabled, but it does not stop the actual registration process and your user table will increase in size pretty quickly, also, some bots seems to be able to get around this too.
Here is a list of the modules I enabled to stop spam registrations to great effect.

Include a honeypot field

The honeypot module is a great module to implement as your first line of defense. It adds a hidden field to your forms, that when a value is added, the form will not submit.
It also has a "Honeypot time limit" setting that is the "Minimum time required before form should be considered entered by a human instead of a bot.". Not though, that using this setting will disable page cache for whatever page that the form on, As on many of my sites have the registration form on all/most pages I usually set this to 0 effectively disabling it so the pages still cache.

Block certain username or email patterns

Often spam registrations have email addresses at a few common domains and you can stop this by enabling the user restrictions module , but this may not be enough and maybe you want to check the username field for a pattern instead. Enter the Regex Registration Deny module , This is a module...

Removing the entity ID from Drupal entity reference fields

On a site I am currently working on I have a content type that includes an entity reference field. When creating a node, the entity reference autocomplete includes the entity id in the field after selecting the entity desired. This can be confusing for the user.
When trying to find a solution to this problem I came across many issues and different proposed solutions including a sandbox module called Entity reference trim .

I tried the entity reference trim module but it has problems when the form was submitted and had errors.
Taking a closer look into this module I could see that it was altering the widget (adding a hidden field) and overriding some of the core Drupal js to do with the autocomplete functionality. While poking around the autocomplete javascript I noticed that the autocomplete fires a 'autocompleteValue' event.
Using this event I could change the entity reference field value and store it, then change it back when the form is submitted.

Below is the code that I am using but be aware that I have not yet tested it extensively and not tested it with multiple entity reference fields. Also, as the event bubbles, a more generic version could probably be coded.

NOTE: you will have to change the jQuery selector.

 (function ($) { 
Drupal.behaviors.damnId = {
attach: function (context, settings){
// Get the entity reference input
$eref = $('#edit-field-postcode-suburb-und-0-target-id', context);
// If field has value on page load, change it.
var val = $eref.val();
var match = val.match(/\((.*?)\)$/);
$eref.data('real-value', val);
$eref.val(val.replace(match[0], ''));
// Listen for the

Drupal views exposed form in a bootstrap modal

I am currently working on a site with the Bootstrap theme which has a fullscreen views map ( Goomap ) with exposed filters. As the map is full screen I want to have the exposed filters inside a bootstrap modal. Luckily it is quite easy to theme the views exposed filters form.

To do this you have to override the views exposed filters form theme file. Copy the views theme file (sites/all/modules/views/theme/views-exposed-form.tpl.php) and place the copy in your own theme folder. To get this to work you may have to click on "Rescan template files" under "theme" in the view. Your site should now be using the new template file and you can edit it as you please. You can get more specific with the naming of the template file to target a single exposed form, (views-exposed-form--VIEWNAME.tpl.php for example).

Below is the code that I am using in my views-exposed-form.tpl.php

 <a data-toggle="tooltip" title="<?php print t('Filter Results'); ?>"> 
<button class="btn btn-default btn-sm" data-toggle="modal" data-target="#filterModal">
<i class="glyphicon glyphicon-cog"></i>

<div class="views-exposed-form">
<div class="modal fade" id="filterModal" tabindex="-1" role="dialog" aria-labelledby="filterLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title" id="filterLabel">Filter</h4>
<div class="modal-body">

<div class="views-exposed-widgets clearfix">
<?php foreach ($widgets as $id => $widget): ?>
<div id="<?php print $widget->id; ?>-wrapper" class="views-exposed-widget views-widget-<?php print $id; ?>">
<?php if (!empty($widget->label)): ?>
<label for="<?php print $widget->id; ?>">
<?php print $widget->label; ?>
<?php endif; ?>
<?php if (!empty($widget->operator)): ?>
<div class="views-operator">
<?php print $widget->operator; ?>

Not another Drupal mapping module: Goomap

Yes, I have done it, created yet another Drupal mapping module. I call him Goomap .

The first thing you are probably going to ask is "why?". Well, here's why:

  • Complexity
    Most of the time when trying to use one of the other Drupal mapping modules I would find the process far too complex. Especially the last time I used the Openlayers module. I wont go into detail about this but if you have used it you will know what I mean. Every time I have needed maps on a drupal site over the past couple of years I have found it easier to just use the Google maps api itself and not even bother with a drupal mapping module.
  • Map provider support
    Many people may consider this a step backward as the Goomap module only supports Google maps where as other mapping modules support other map providers. But I have only ever used Google maps as it has always served my purpose and the documentation is fantastic. So why support other map providers if I (and probably many others) never use them?
  • Map color customization
    Now I'm not exactly sure on how to customize the colors on the other modules, but with the Goomap module it is quite easy because the goomap module gives you access to the mapOptions object that is send to the Map constructor. The mapOptions object has a "styles" property which accepts an array which represents the styles (colors etc.) that the map will have. This "styles" array can simply be pasted into the mapOpions textarea in the map settings. You can easily generate and copy this JSON array from sites such as https://snazzymaps.com/
  • ...

Drupal 7 Bootstrap image field upload widget

When using the Bootstrap theme in Drupal 7, the image upload widget leaves a lot to be desired. I looks pretty crappy
Below is how I overcame this.
It should probably work with file fields too but instead of overriding THEME_image_widget, you would override THEME_file_widget, though I haven't tried it yet.

First, add this to your css

 .btn-file { 
position: relative;
overflow: hidden;

.btn-file input[type=file] {
position: absolute;
top: 0;
right: 0;
min-width: 100%;
min-height: 100%;
font-size: 100px;
text-align: right;
filter: alpha(opacity = 0);
opacity: 0;
outline: none;
background: white;
cursor: inherit;
display: block;

Then override the theme_image_widget in your template.php
A note on admin theme
If your upload widget is on a node edit page (or any admin page) the active theme will be your admin theme. This means the code will need to go into your admin themes template.php and the css in your admin themes css.

 function MYTHEME_image_widget($variables) { 
$element = $variables['element'];
$output = '';
$output .= '<div class="image-widget form-managed-file clearfix">';

if (isset($element['preview'])) {
$output .= '<div class="image-preview">';
$output .= drupal_render($element['preview']);
$output .= '</div>';

$output .= '<div class="image-widget-data">';
if ($element['fid']['#value'] != 0) {
$element['filename']['#markup'] = '<div class="form-group">' . $element['filename']['#markup'] . ' <span class="file-size badge">' . format_size($element['#file']->filesize) . '</span></div>';
else {
$element['upload']['#prefix'] = '<div class="input-group"><span class="input-group-btn"><span class="btn

Disable taxonomy term delete button if term has nodes.

The below snippet will disable the delete button on the taxonomy term edit page if the term has any nodes assigned to it.
It implements hook_form_FORM_ID_alter()

 function hook_form_taxonomy_form_term_alter(&$form, &$form_state) { 
$query = db_select('taxonomy_index', 't');
$query->condition('tid', $form_state['term']->tid, '=');
$query->join('node', 'n', 't.nid = n.nid');

$count = $query->countQuery()->execute()->fetchField();
if ($count) {
$form['actions']['delete']['#disabled'] = TRUE;
$form['actions']['delete']['#suffix'] = "<span>$count nodes, cant delete</span>";

Drupal Domain Access user 1 menu

Today when developing a Drupal site with the Domain Access module I had an interesting problem.
My site is set up with a custom theme and 2 domains.
My custom theme is using Zurb Foundation and so I had to override the main menu theme functions to add the Zurb classes.
This was easily done by implementing theme_links__system_main_menu, theme_menu_tree__main_menu__submenu and theme_menu_link__main_menu as outlined below (my theme name is nexus).

 function nexus_links__system_main_menu($variables) { 
$links = menu_tree_output(menu_tree_all_data(variable_get('menu_main_links_source', 'main-menu')));
$output = drupal_render($links);
return $output;

function nexus_menu_tree__main_menu__submenu($variables) {
return '<ul class="menu dropdown">' . $variables['tree'] . '</ul>';

function nexus_menu_link__main_menu($variables) {
$element = $variables['element'];
$sub_menu = '';
if ($element['#below']) {
$element['#below']['#theme_wrappers'][] = array('menu_tree__main_menu__submenu');
$sub_menu = drupal_render($element['#below']);
$element['#attributes']['class'][] = 'has-dropdown';
if (isset($element['#href']) && ($element['#href'] == $_GET['q'] || ($element['#href'] == '<front>' && drupal_is_front_page())) && (empty($element['#language']) || $element['#language']->language == $language_url->language)) {
$element['#attributes']['class'][] = 'active';
$output = l($element['#title'], $element['#href'], $element['#localized_options']);
return '<li' . drupal_attributes($element['#attributes']) . '>' . $output . $sub_menu . "</li>\n";

The problem was that all node links assigned to the main menu would show up if you were logged in as user 1, even if they were not assigned to the current domain. Though, if you were not logged in the menu would appear correct and only show links assigned to the current domain.
This is obviously the correct behavior as the domain access module uses Drupal's node access system and the access system is bypassed for user 1.
At this point I could have switched...

Drupal Module: Watchdog Event Extras

When checking the logs on the Drupal sites I run I often find myself copying the IP and searching it on google. Most of the time it is when I'm looking at a page not found or login attempt failure and I would like to know if these came from some sort of spam or a legitimate user. This process became a little tedious, so I created the Watchdog Event Extras module.

Basically what the module does is overrides the standard drupal log event page, outputting the same and adding a drupal_alter()
call. At the moment the module includes two sub modules, the first of which adds geolocation data derived from the hostname and the freegeoip.net web service with the second adding data from the stopforumspam.com web service.

Any other module can also add data to the report page by implementing MYMODULE_watchdog_event_extras_alter(&amp;$rows, $dblog)

Cheick it out https://www.drupal.org/project/watchdog_event_extras

Also, don't forget to checkout the Link Favicon Formatter module if you ever needed to add a site favicon to a link field: https://www.drupal.org/project/link_favicon_formatter

Changing the Inline Entity Form autocomplete field to a select list

The Inline Entity Form module for Drupal is an awesome module. Most people probably have experienced using it with Drupal Commerce, but it can be used when ever an Entity Reference field is used. I have personally used it on many projects, most of which were not commerce related.

Sometimes though, the autocomplete field to select an existing entity is not appropriate, say if you only have a few entities that can be referenced.

Luckily though we can make use of the hook that the Inline Entity Form module provides which is "HOOK_inline_entity_form_reference_form_alter(&$reference_form, &$form_state)".

Below is an example of how to change all the autocomplete fields to select lists when the reference field references any type of node.

 function MYMODULE_inline_entity_form_reference_form_alter(&$reference_form, &$form_state) { 
// change the entity reference 'add more' autocomplete into a select list
if($reference_form['#entity_type'] == 'node') { // only change the forms that reference a node
$field = field_info_field($reference_form['#parents'][0]);
$nodes = node_load_multiple(array(), array('type' => reset($field['settings']['handler_settings']['target_bundles'])));
$options = array();
foreach($nodes as $node){
$options[$node->title.' ('.$node->nid.')'] = $node->title;
$reference_form['entity_id']['#type'] = 'select';
$reference_form['entity_id']['#options'] = $options;