Category Archives: Drupal

Making Drupal Messages appearing in modal dialog with Bootstrap 3

This post is another step in the theming Drupal 7 wit Bootstrap 3, you can read my previous article about “Drupal 7 and bootstrap 3 theming the login form“.

Now the purpose here is to change the default Drupal messages display system :

default drupal messages

to this a nice modal message using Bootstrap 3 :

Drupal messages with bootrap 3

Okay let’s start :

1) Fist you need to rewrite the theme_status_messages() in your theme.php file like this :

function [your_theme_name]_status_messages($variables) {
  $display = $variables['display'];
  $output = '';

  $status_heading = array(
    'status' => t('Status message'),
    'error' => t('Error message'),
    'warning' => t('Warning message'),
  );
  foreach (drupal_get_messages($display) as $type => $messages) {
    // ! important : adding html needed for the modal.
    $output = '<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog ">
      <div class="modal-content">
        <div class="modal-body">';

    $output .= "<div class=\"_messages $type\">\n";
    if (!empty($status_heading[$type])) {
      $output .= '<h2 class="element-invisible">' . $status_heading[$type] . "</h2>\n";
    }
    if (count($messages) > 1) {
      $output .= " <ul>\n";
      foreach ($messages as $message) {
        $output .= '  <li>' . $message . "</li>\n";
      }
      $output .= " </ul>\n";
    }
    else {
      $output .= $messages[0];
    }
    $output .= "</div>\n";

    $output .= '</div>
        <div class="modal-footer">
          <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
    </div><!-- /.modal -->';
  }
  return $output;
}

2) Now into your script.js file add :

// modals.
$('#myModal').modal();

3) Flush your theme registry cache and Voilà ! now every time the messages will be displayed within the modal dialog box.

Hope you enjoyed !

Drupal 7 and bootstrap 3 theming the login form

Bootstrap 3 is out with responsiveness, simplified code, new components etc .. so how to integrate this new features on a Drupal theme ? in this tutorial we’ll try to change the default Drupal login form from this :

startTo this :

final_result

1) First of all we’ll need to create a new theme ( in this tutorial we’ll be using Zen theme to create a subtheme) and download the bootstrap source.

2) Second we’ll need to create a custom module to alter the form and remove some of the uneeded html elements.

Okay no more talk let’s start !

– We begin by including the bootstrap css minified file into the subtheme :

yourtheme.info content :

stylesheets[all][] = bootstrap/css/bootstrap.min.css

Notice no important change appears that’s because we need to add bootstrap classes ..

Now we set what we need for the templates :

// set custom tpl for the login page.
function [your_theme_name]_theme() {

  $items = array();

  $items['user_login'] = array(
    'render element' => 'form',
    'path' => drupal_get_path('theme', '[your_theme_name]') . '/templates',
    'template' => 'user-login',
  );
  return $items;
}

//add class to buttons
function [your_theme_name]_button($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'submit';
  element_set_attributes($element, array('id', 'name', 'value'));

  $element['#attributes']['class'][] = 'form-' . $element['#button_type'];
  $element['#attributes']['class'][] = 'btn';
  // adding bootstrap classes.
  if($element['#button_type'] == 'submit'){
    $element['#attributes']['class'][] = 'btn-primary';
    $element['#attributes']['class'][] = 'btn-lg';
  }
  if (!empty($element['#attributes']['disabled'])) {
    $element['#attributes']['class'][] = 'form-button-disabled';
  }

  return '<input' . drupal_attributes($element['#attributes']) . ' />';
}

/**** theme form textfields. ***/
function [your_theme_name]_textfield($variables) {

  $element = $variables['element'];
  $output = '';
  // login form adding glyphicon.
  if($element['#name'] == 'name') {
    $output = '<span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>';
  }

  // force type.
  $element['#attributes']['type'] = 'text';
  // set placeholder.
  if(isset($variables['element']['#description'])){
    $element['#attributes']['placeholder'] = $variables['element']['#description'];
  }

  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength'));
  // adding bootstrap classes.
  _form_set_class($element, array('form-text', 'form-control', 'input-lg-3'));

  $extra = '';
  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
    drupal_add_library('system', 'drupal.autocomplete');
    $element['#attributes']['class'][] = 'form-autocomplete';

    $attributes = array();
    $attributes['type'] = 'hidden';
    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
    $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
    $attributes['disabled'] = 'disabled';
    $attributes['class'][] = 'autocomplete';
    $extra = '<input' . drupal_attributes($attributes) . ' />';
  }

  $output .= '<input' . drupal_attributes($element['#attributes']) . ' />';

  return $output . $extra;
}

/*** theme password field ***/
function [your_theme_name]_password($variables) {
  $element = $variables['element'];
  $element['#attributes']['type'] = 'password';
  element_set_attributes($element, array('id', 'name', 'size', 'maxlength'));
  _form_set_class($element, array('form-text', 'form-control'));

  $output = '';
  // login form adding glyphicon.
  if($element['#name'] == 'pass') {
    $output = '<span class="input-group-addon"><span class="glyphicon glyphicon-eye-close"></span></span>';
  }

  return $output . '<input' . drupal_attributes($element['#attributes']) . ' />';
}

/** Theme form element **/
function [your_theme_name]_form_element($variables) {
  $element = &$variables['element'];

  // This function is invoked as theme wrapper, but the rendered form element
  // may not necessarily have been processed by form_builder().
  $element += array(
    '#title_display' => 'before',
  );

  // Add element #id for #type 'item'.
  if (isset($element['#markup']) && !empty($element['#id'])) {
    $attributes['id'] = $element['#id'];
  }
  // Add element's #type and #name as class to aid with JS/CSS selectors.
  $attributes['class'] = array('form-item');
  if (!empty($element['#type'])) {
    $attributes['class'][] = 'form-type-' . strtr($element['#type'], '_', '-');
  }
  if (!empty($element['#name'])) {
    $attributes['class'][] = 'form-item-' . strtr($element['#name'], array(' ' => '-', '_' => '-', '[' => '-', ']' => ''));
  }
  // Add a class for disabled elements to facilitate cross-browser styling.
  if (!empty($element['#attributes']['disabled'])) {
    $attributes['class'][] = 'form-disabled';
  }
  if (isset($element['#parents']) && form_get_error($element)) {
    $attributes['class'][] = 'has-error';
  }

  if($element['#type'] != 'radio'){
    $attributes['class'][] = 'input-group';
  }

  $output = '<div' . drupal_attributes($attributes) . '>' . "\n";

  // If #title is not set, we don't display any label or required marker.
  if (!isset($element['#title'])) {
    $element['#title_display'] = 'none';
  }
  $prefix = isset($element['#field_prefix']) ? '<span class="field-prefix">' . $element['#field_prefix'] . '</span> ' : '';
  $suffix = isset($element['#field_suffix']) ? ' <span class="field-suffix">' . $element['#field_suffix'] . '</span>' : '';

  switch ($element['#title_display']) {
    case 'before':
    case 'invisible':
      $output .= ' ' . theme('form_element_label', $variables);
      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
      break;

    case 'after':
      $output .= ' ' . $prefix . $element['#children'] . $suffix;
      $output .= ' ' . theme('form_element_label', $variables) . "\n";
      break;

    case 'none':
    case 'attribute':
      // Output no label and no required marker, only the children.
      $output .= ' ' . $prefix . $element['#children'] . $suffix . "\n";
      break;
  }
  // remove description we'll use placeholder.
  if (!empty($element['#description'])) {
    //$output .= '<div class="description">' . $element['#description'] . "</div>\n";
  }

  $output .= "</div>\n";

  return $output;
}

Okay now the user-login-template.tpl.php :

<div class="col-md-5 col-md-offset-3 panel">
<div class="panel-heading"><h2><?php print t('Login'); ?></h2></div>
    <div class="panel-body">
    <?php print drupal_render_children($form) ?>

    </div>
</div>

at this point and if everything is ok you should see something like this :

intermediaire

We need to remove the label to get a nice version, in the custom module :

/** Hook_form_alter **/
function [your_module]_form_alter(&$form, &$form_state, $form_id) {
    // user login
    if($form_id == 'user_login'){
        $form['name']['#title_display'] = 'invisible';
        $form['pass']['#title_display'] = 'invisible';
    }
}

Ps : you’ll need to rebuild the theme registry to see the changes !

Et voilà ! hope you enjoyed. Please if you have any idea about how to do this in a more simple way feel free to comment.

Drupal 6, Theming Search Box

In this tutorial i will try to explain how to modifiy default search box provided by Drupal module “Search“, this one of many other methods and i think it’s the simplest way.

First of all you’ll need to enable it from admin>build>modules interface then associate it to a region.

Creating theme file

First of all create a file on you theme directory called : ‘search-block-form.tpl.php‘ which is a copy of template file of search box module, the problem whith drupal generated forms are the hidden fields and input file names so we need to pay attention to them :

<?php
// $Id: search-block-form.tpl.php,v 1.1 2007/10/31 18:06:38 dries Exp $
?>
<div class="container-inline">
    <?php
    //Default form call.
    //print $search_form;
    ?>
    <label>
<span>
<!-- input type text with correct name search_block_form -->
  <input name="search_block_form" type="text" class="keywords" id="edit-search-theme-form-l" maxlength="50" value="Search..." />
 </span>
<!-- action name "op" -->
<input name="op" type="image" src="<?= url(path_to_theme() . '/images/search.gif', array('absolute' => true)) ?>" class="button" />
    </label>

    <?php
    //hidden values !important
    print $search["hidden"];
    ?>
</div>

That’s all ! there’s an interesting forum topic where you can find other methods like preprocess functions etc. :
http://drupal.org/node/224183

Drupal 6, avoiding message ‘An illegal choice has been detected’.

Drupal form control can be tiresome some times, especially when developping custom modules .. In my case it was the integration of country and region select boxes from the ubercart module.

In my implementation of hook_form_alter we are adding these two elements in code :

$select_country = uc_country_select(uc_get_field_name('country'), $country, NULL, 'name');
$select_zone = uc_zone_select(uc_get_field_name('zone'), $zone, NULL, $country, 'name');

$form['country'] = $select_country;
$form['zone'] = $select_zone;

But when submitting the form we have always the same error : An illegal choice has been detected ??!!

As a solution and reading validation from code it’s possible to add in the form alter the information that this form has been already validated :

$form['zone']['#validated'] = true;

Drupal 6, programtically add custom meta tags to pages

Assuming that we need to add custom meta tags by page url or node type, drupal hook_preprocess_page() is the last function called before displaying the page, so it’s the right place for doing that :

/**
 * Implementation of hook preprocess_page
 *
 * @param array $variables
 */
function my_module_preprocess_page(&$variables) {
    //using path
    if(arg(1) == 'gallery'){
      //load existing node
      $node = node_load(arg(2));
     // the meta content.
      $head = ' .. ';
      drupal_set_html_head($head);
      $variables['head'] = drupal_get_html_head();
  }
}

In this case path is : gallery/[nid]