Drupal

To show the profile2 form directly on the user account edit form :

The following assumes that the profile2 type is called "profile".

First, we have to hide the tab on the user account page :

/**
* Implements hook_menu_alter().
*/
function MY_MODULE_menu_alter(&$items) {
$items['user/%user_category/edit/profile']['access callback'] = FALSE;
}

Then, merge the profile2 form with the user account form itself :

/**
* Implements hook_form_FORM_ID_alter() for the user edit form.
*/
function MY_MODULE_form_user_profile_form_alter(&$form, &$form_state) {
if (($type = profile2_get_types('profile')) && $type->userCategory) {
if (empty($form_state['profiles'])) {
$profile = profile2_load_by_user($form['#user'], 'profile');
if (empty($profile)) {
$profile = profile_create(array('type' => 'profile', 'uid' => $form['#user']->uid));
}
$form_state['profiles'][$profile->type] = $profile;
}
profile2_attach_form($form, $form_state);
}
}

Drupal uses a default jQuery UI theme. Here is how to use your own theme created using the jQuery ThemeRoller.

Put the generated jQuery UI theme in your theme directory, in a subfolder called "jquery-ui". It should have an "images" folder and a "jquery-ui.css" file.

Then, in your theme's template.php :

/**
* Implements hook_library_alter().
*/
function YOUR_THEME_library_alter(&$libraries, $module) {
$libraries['ui']['css'] = array();
$libraries['ui.accordion']['css'] = array();
$libraries['ui.autocomplete']['css'] = array();
$libraries['ui.button']['css'] = array();
$libraries['ui.datepicker']['css'] = array();
$libraries['ui.dialog']['css'] = array();
$libraries['ui.draggable']['css'] = array();
$libraries['ui.droppable']['css'] = array();
$libraries['ui.mouse']['css'] = array();
$libraries['ui.position']['css'] = array();
$libraries['ui.progressbar']['css'] = array();
$libraries['ui.resizable']['css'] = array();
$libraries['ui.selectable']['css'] = array();
$libraries['ui.slider']['css'] = array();
$libraries['ui.sortable']['css'] = array();
$libraries['ui.tabs']['css'] = array();
$libraries['ui']['css'][drupal_get_path('theme', 'YOUR_THEME') . '/jquery-ui/jquery-ui.css'] = array();
}

For a recent project, I had to migrate from Drupal 5 to Drupal 7. Here is how I did it without too much pain. The key steps are :

  • Export data to CSV from the original instance using Views module and a CSV output plugin.
  • Import them in the 7.x instance using Feeds.

A friend of mine just pointed out that my name is written in big characters in a slide of the latest Keynote of Dries Buytaert showing Drupal contributors :) It is in slide #10, and also in the video, around 1:00. Yay ! I'm famous !

Random magic hehe, I'm not such a big contributor ;) Try to find my name in this picture where contributors size is proportionate, that's a little harder :) :

/**
* Implements hook_cron_queue_info().
*/
function MYMODULE_cron_queue_info() {
$queues = array();
$queues['MYMODULE_queue_notify'] = array(
'worker callback' => 'MYMODULE_queue_notify_worker',
'time' => 15,
);
return $queues;
}
 
/**
* Queue worker for sending notification mails.
*/
function MYMODULE_queue_notify_worker($params) {
drupal_mail('MYMODULE', 'notify', $params['to'], language_default(), $params, $params['from']);
}
 
/**
* Implements hook_mail().
*/
function MYMODULE_mail($key, &$message, $params) {
$language = $message['language'];
$message['subject'] = $params['subject'];
$message['body'][] = $params['message'];
}
 
/**
* Implements hook_rules_action_info().
*/
function MYMODULE_rules_action_info() {
return array(
'MYMODULE_rules_action_mail' => array(
'label' => t('Send mail'),
'group' => 'MYMODULE',
'parameter' => array(
'to' => array(
'type' => 'text',
'label' => t('To'),
'description' => t('The e-mail address or addresses where the message will be sent to. The formatting of this string must comply with RFC 2822.'),
),
'subject' => array(
'type' => 'text',
'label' => t('Subject'),
'description' => t("The mail's subject."),
),
'message' => array(
'type' => 'text',
'label' => t('Message'),
'description' => t("The mail's message body."),
),
'from' => array(
'type' => 'text',
'label' => t('From'),
'description' => t("The mail's from address. Leave it empty to use the site-wide configured address."),
'optional' => TRUE,
),
),
),
);
}
 
/**
* Action: Add notification mails to the queue.
*/
function MYMODULE_rules_action_mail($to, $subject, $message, $from = NULL, $settings, RulesState $state, RulesPlugin $element) {
// Gather params.
$params = array(
'to' => str_replace(array("\r", "\n"), '', $to),
'from' => !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL,
'subject' => $subject,
'message' => $message,
);
// Add to the queue.
$queue = DrupalQueue::get('MYMODULE_queue_notify');
$queue->createItem($params);
}

When using a view with exposed filters, if the exposed filter is empty, by default views renders the view with all results displayed. To make an empty view instead :

  • Add an argument "Global: Null"
  • Action to take if argument is not present: Provide default argument
  • Default argument type: Fixed entry
  • Default argument: let it blank
  • Validator: PHP code
  • PHP validate code:
    if (!empty($view->exposed_input) && count($view->exposed_input) == 1 && isset($view->exposed_input['destination'])) {
    return FALSE;
    }
    return (!empty($view->exposed_input));
  • Action to take if argument does not validate: Display empty text (if you want the view to be rendered)

And voilà !

To create GIT patches using branches (which is required for drush make):
git clone --branch 7.x-1.x http://git.drupal.org/project/session_api
cd session_api
git checkout -b cron
[edit code...]
git commit -a -m "Use an expiration logic when clearing sessions on cron"
git checkout 7.x-1.x
git diff --no-prefix 7.x-1.x cron > session_api_cron.patch

You may use the "master" branch instead of "7.x-1.x".

Here is a simple database API example :

$results = db_select('authmap', 'am') // 'authmap' is the table name, 'am' the alias
->fields('am', array('uid')) // The alias and the field we want to fetch
->distinct() // Add distinct
->condition('module', 'MYMODULE') // A condition on the 'module' field, 'MYMODULE' value
->condition('authname', $ids, 'IN') // A condition on the 'authname' field, value is in $ids array
->execute() // Execute the query
->fetchCol(); // Fetch column

There are many examples on how to use AJAX using form API, but I could not find a good example on how to use AJAX with markup. Here is a simple method.

To create an AJAX link in Drupal, outside of form API, we first need to add a menu item :

function MYMODULE_menu() {
$items = array();
$items['MYMODULE/ajax'] = array(
'page callback' => 'MYMODULE_ajax_callback',
'access arguments' => TRUE,
'type' => MENU_CALLBACK,
);
$items['MYMODULE/ajax/%/%'] = array(
'page callback' => 'MYMODULE_ajax_callback',
'page arguments' => array(2, 3),
'access arguments' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}

Then, wherever you want to create a link, include the library :

// Add libraries
drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'jquery.form');

Create a link with the "use-ajax" class and a wrapper for the AJAX response. This is a dummy example, you must do this in an appropriate way of course :

// Output a link
l(t('AJAX'), 'MYMODULE/ajax/nojs/' . $some_argument, array('attributes' => array('class' => array('use-ajax'))));
// Output a wrapper
'<div id="MYMODULE-wrapper"></div>'

Finally, create your callback function :

function MYMODULE_ajax_callback($type = 'ajax', $some_argument) {
if ($type == 'ajax') {
$commands[] = ajax_command_replace('#MYMODULE-wrapper', 'Hey ! Some AJAX content !');
$page = array('#type' => 'ajax', '#commands' => $commands);
ajax_deliver($page);
}
else {
$output = t("This is some content delivered via a page load.");
return $output;
}
}

That's it !

Sometimes we need to add template suggestions to a module. To do this, we need to alter the registry and add the template suggestion to the preprocess function.

To add a template suggestion for blocks named "mytemplate.tpl.php" in the "theme" subfolder of your module, do the following :

/**
* Implementation of hook_theme_registry_alter().
*/
function MYMODULE_theme_registry_alter(&$theme_registry) {
  $theme_registry['block']['theme paths'][] = drupal_get_path('module', 'MYMODULE') . '/theme';
}
 
/**
* Implementation of hook_preprocess_block().
*/
function MYMODULE_preprocess_block(&$variables) {
  $variables['template_files'][] = 'mytemplate';
}

Syndicate content