Theme Drupal Content as an Overlay

By Mike on April 26th, 2012
Mike

What if you want to have forms display as overlays on your Drupal 7 installation? Perhaps you want to give your users a way to add nodes without leaving the current page (like adding reference nodes to the node being edited).

There are a few ways to accomplish this task, but this approach will add this functionality without requiring specific template changes within the active theme. Instead, all code can reside within your custom module. This is handy if you want your functionality to remain independent of what theme is used, which seems ideal to me.

Drupal 7 includes the Overlay module; which, when enabled does a nice job of displaying the admin pages in an overlay. It would be great to tap into what drupal is using here in this module, but unfortunately the code is tailored pretty specifically, and isn’t very extensible.

This approach will also provide the form without the irrelevant regions of a page like the header, footer, sidebars, etc.

For the overlay functionality we usually use Colorbox, which is our library of choice for implementing light-box like functionality with jQuery. There is a module with help facilitates this integration with Drupal. But there are a number of jQuery libraries that accomplish the same thing. The installation of one of these libraries is outside the scope of this example.

So here is how accomplish this…

First we create the menu callback and it’s corresponding function, which will need to also reside in your *.module file unless you specify otherwise in the menu hook. This callback will be responsible for providing what ever it is you want to display in your overlay. In this example I am providing a form.

function mymodule_menu()
{
  $items = array();

  $items['mymodule/popup'] = array(
    'title' => 'Popup Overlay',
    'page callback' => '_mymodule_callback',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );

  return $items;
}
function _mymodule_callback() {
  module_invoke('admin_menu', 'suppress');
  $form = drupal_get_form('_mymodule_form');
  $form['#popup'] = true;
  return $form;
}

So here is what we are doing with this callback. We are invoking the suppress function of the admin_menu in order to prevent this menu from appearing along the top of the overlay. You don’t need to do this if you are not using this module, however because we are using module_invoke we won’t receive an error if the module doesn’t exist on this Drupal installation.

Next we are grabbing the form render array to pass back from this callback. This can be any render array you want.

Finally, we add an element to our render array that we will be using later to indicate that we want to only show the main content of this page.

Next we are going to implement hook_theme to define a new theme element in the registry.

function mymodule_theme() {

  $items['mymodule_popup'] = array(
    'render element' => 'page',
    'template' => 'mymodule_popup',
  );

  return $items;
}

This function defines a new theme called mymodule_popup. It indicates it will be theming the page element and will be using a template named mymodule_popup (.tpl.php). This tpl file should reside in the base directory of your custom module unless you specify a path in the theme definition.

Next let’s create our tpl.php file. All we want this to do is show our main content, wrapped in minimal html. Simply copying the innermost portion of your standard page.tpl.php file will give you a good start.

<div id="page-wrapper"><div id="page">
  <div id="main-wrapper"><div id="main" class="clearfix">
    <div id="content" class="column"><div class="section">
      <a id="main-content"></a>
      <?php print render($page['content']); ?>
    </div></div><!-- /.section, /#content -->
  </div></div><!-- /#main, /#main-wrapper -->
</div></div><!-- /#page, /#page-wrapper -->

Lastly we implement hook_page_alter. This is what tells Drupal to use our new stripped down theme file when displaying a page with the attribute of ‘#popup’. This attribute corresponds to the line of code we included in the callback function.

function mymodule_page_alter(&$page) {
  if (isset($page['content']['system_main']['#popup'])) {
    $page['#theme'] = 'mymodule_popup';
  }
}

That does it, after refreshing the theme cache, when invoking an ajax callback (using colorbox or comparable library) you should see your overlay displaying the content returned from the callback function.

Hope this helps, feel free to ask questions in the comments.

Updating a Drupal Module’s Schema

By Mike on April 18th, 2012
Mike

I recently had the need to make updates to a table I am defining using Drupal’s schema API.  It’s extremely simple to do, though there isn’t much in the way of documentation (if there is, let me know in the comments).  The biggest reason to implement a schema update is if you want to make updates to the database, but do not want to lose the data already in the system (otherwise you can just uninstall and reinstall the module to update the schema).

So here’s what you do.

First you need to modify the hook_schema implementation to include the new fields (or removal of fields).  For my example I’ll be adding a field called ‘test_flag‘ to my custom table.


'test_flag' => array(
  'description' => 'Is this record flagged',
  'type' => 'int',
  'size' => 'tiny',
  'not null' => TRUE,
  'default' => 0,
),

This will ensure that the schema is correct for anyone installing the module for the first time.  But we need to make sure anyone using this module also has the correct schema.  You need to name your function [module name]_update_[version number].  Naming the function this way is important and provides a lot of nice functionality for free.  Your version number should be the version of Drupal times 1000.  So the first update for a module on Drupal 7 should be versioned 7001.  Subsequent versions being 7002, 7003, etc…

The comment you place over your function is also important.  This is what will be used as a description to the user updating the module.  This was an unexpected surprise for me when looking through core.

Lastly you need to make the db changes.  Drupal gives us an easy way to do this within a single line of code.  Use db_add_field passing in the name of the schema (table) and the field you are looking to add along with an array of attributes for this field.  The array of attributes uses the same structure other schema definitions.


/**
* Add test_flag fields to the {custom_table} table.
*/
function custom_update_7001() {
  db_add_field(
    'custom_table',
    'test_flag',
    array(
      'type' => 'int',
      'size' => 'tiny',
      'not null' =>TRUE,
      'default' => 0,
    )
  );
}

Drupal will automatically recognize that a new version of the module is available and will the run the function code when doing a database update with update.php or drush updb.

The Future of Drupal Upgrades is Migrate

By Jonathan Pichot on March 26th, 2012
Jonathan Pichot

Major version upgrades in Drupal are hard.

Drupal’s open-source  development process puts everything on the table every major release, including fundamental APIs and features. This allows Drupal to evolve as a platform, such as when fields moved into core in Drupal 7, and how Drupal 8 will adopt many components from Symfony2. But this also means that every major version upgrade requires significant changes to your data structure.

Part of the challenge is that Drupal installations are never just core, but a large constellation of contributed modules with their own database tables. In other words, for any site more complicated than a basic install, its data is not just being handled by Drupal core, but by a handful of other modules, each with varying levels of complexity and maintainability.

The typical upgrade procedure (for now) on Drupal.org is to use Drupal’s built-in update mechanism, update.php. While update.php does a great job keeping your database schema up-to-date when making minor-point updates (eg. D7.10 to D7.12), it is severly limited in handling any major upgrade beyond a stock Drupal installation.

Update.php, for example, is capable of upgrading contributed module data only if the maintainer of that module has provided a new version and has written the requisite upgrade code. Established and well-maintained modules are usually good at this, but even the largest modules can go away. As the Drupal ecosystem evolves, better solutions emerge to common use-cases. For example, the D7 References module, which includes the heavily used Node and User Reference fields, will likely be deprecated in Drupal 8 in favor of Entity Reference. This means that any site that uses User and Node reference fields will need to be upgraded to Entity Reference fields after D7. This kind of data shift between two different modules is only one of the challenges of major upgrades.

Update.php is also incapable of jumping Drupal versions. To upgrade from D5 to D7 using update.php, you’d have to first run D6′s update.php, then D7′s. With all this data shifting, it’s also common to have leftover database tables. These tables can bloat your databse, hurting performance and your data usage.

The solution is the Migrate module. Migrate uses an Object-Oriented process to take data from a source–database, CSV, JSON, etc–and insert it into a Drupal database. Each Migrate process is essentially a subclass of Migrate which defines what fields to import and any other needed logic. At the moment, Migrate requires a user to write these PHP classes themselves, since Migrate was originally targeted at importing data from non-Drupal sources. But a new project called migrate_d2d by mikeryan, lead maintainer of Migrate, aims to use Migrate for major version Drupal upgrades. At DrupalCon Denver 2012, mikeryan mentioned that he is looking at replacing update.php with migrate_d2d for all upgrades to D8.

This is awesome.

Migrate_d2d effectively takes a clean install of Drupal and brings in all your old data. This means only the data you need is imported, so no old, unused tables. And since Migrate can take data from one module and use another module’s hooks to import it, moving data from one module to another becomes possible. This process also opens up the ability to jump versions. This means, then, that a supported upgrade path from D6 to D8, for example, could become a reality.

If migrate_d2d matures enough for it to become the default major upgrade mechanism, it will help eleviate many of the upgrade frustrations in Drupal. This is particularly important for organizations who can’t afford to always rebuild their site after every major version release. With the added flexibility of migrate_d2d, the Migrate module will further secure Drupal as the CMS of choice for organizations large and small.

For more on Migrate, check out this DrupalCon Denver presentation by drewish, and if you wait till the Q&A, mikeryan talks a little about migrate_d2d.

DrupalCon Denver 2012

By Jonathan Pichot on March 26th, 2012
Jonathan Pichot

Last week Mike and I were in Denver for the 2012 North American DrupalCon. Besides discovering a great city–and having one of the best burgers I have ever had–we were able to check the pulse of the Drupal community.

An important part every DrupalCon is discovering where the community is headed. Below are the six themes I came away with from DrupalCon this year, separated by topics relevant immediately, and important topics about the future of the platform.

Mike has already written on the Symfony2 integration, which I link to in the list. I’ve written about the future of Migrate. I’m hoping to address several of the other topics in the coming weeks.

Rdio vs. Spotify

By Mike on March 24th, 2012
Mike

In a previous post I discussed the growing shift of music listeners from owning to streaming their music.  Now I’m going to take a quick look at what I would consider to be the two best streaming services.  I have used both Rdio and Spotify over the past year and they both have their advantages.  The good thing is that the competition between them will make better products for us.  I am currently using Rdio after about 8 months with Spotify; switching because of the Rdio desktop client refresh.  One nice advantage to these services is that they both have free plans, which in my case, means I can switch between the two premium plans as I feel like without losing my settings, etc.

Read the rest of this entry »

Drupal and Symfony 2

By Mike on March 22nd, 2012
Mike

We here at Rapid Development Group are first and foremost Drupal developers, and have become the “go-to” people for anything related to the popular CMS. A large chunk of our work is in some form or another related to a Drupal site (even if it is an iOS app that connects to a Drupal backend).

Outside of this I have always been interested in other development frameworks, especially ones that implement the traditional MVC architecture, and have ORM configuration all within code that is easily versioned and deployed.  These kinds of framework allow for quick application development when the weight of CMS functionality isn’t needed.  Something that Ruby on Rails has become so popular for providing.

Read the rest of this entry »

Drupal’s EntityFieldQuery and Taxonomy

By Mike on February 22nd, 2012
Mike

Drupal 7′s powerful EntityFieldQuery class can be used as an alternative to writing a view (and using views_get_view_result).

When attempting to grab a list of terms in a vocabulary you can do the following.

$taxonomy_query = new EntityFieldQuery;
$taxonomy_query->entityCondition('entity_type', 'taxonomy_term')
  ->propertyCondition('vid', 2)
  ->propertyOrderBy('weight');

$taxonomy_terms = $taxonomy_query->execute();

foreach ($taxonomy_terms['taxonomy_term'] as $tid => $term) {
  # code...
}

I didn’t come across any good examples of this the Drupal docs, or anywhere else for that matter.  Hope this helps.

Drupal 7 HTML E-Mail With PDF Attachments

By rhunter on February 16th, 2012
rhunter

Are you having trouble getting attachments working on Drupal 7? You are not alone. Drupal pared back the core e-mail functionality quite a bit from 6 to 7. You can’t even send html mail anymore without installing a module. This article will focus on getting attachments working – then getting pdf attachments working, but we will be using Mime Mail, so a side effect will be HTML enabled mail.

Most of the solutions for sending mail with an attachment in Drupal 7 don’t seem to rely on Drupal modules. The most popular solution to this problem is to basically circumvent Drupal and create a new php class to send your mail. I wanted to use a more Drupal centric solution.

My solution involves the modules Mime Mail, Mail System, and Print, along with our own custom module that we will write that will send the email.

To send an email with a pdf attachment, one must first be able to send an email with some kind of attachment at all. This is no small feat, as the documentation on this is severely lacking. However, attachment functionality is built into the Mime Mail module. Most of the confusion seems to arise from 2 things: the fact that the attachments are set via $message['params']['attachments'], rather than $message['attachment'], and that attachments are an array of arrays. Another possible pitfall is that you must set up drupal_mail() to use mime mail as the mail system interface. This is where the mail system module comes into play. The module is pretty straightforward, and lets you set a different mail system per module. There is a straightforward configuration at admin/config/system/mailsystem where you create a new setting for your module, and select mime mail as the mail system.

To make sure that we can even send attachments, we test sending a .txt file that should exist on every site. This is the code that should be in your custom module to test for sending an attachment. I am using the case of a user submitting a form as the trigger to send the emails.

function _example_form_submit($form, &$form_state) {
  _example_form_save($form, $form_state);
  global $user;
  $accounts = array($user, user_load(XX)); //you can add accounts to this array to notify
  example_notify($accounts, $user); //could also pass $form_state or other variables
}

function example_notify($accounts, $from) {
  $params['from'] = $from;
  foreach ($accounts as $account) {
  $params['account'] = $account;
  // example_mail() will be called based on the first drupal_mail() parameter.
  drupal_mail('example', 'notice', $account->mail, user_preferred_language($account), $params, $from->mail);

  drupal_set_message('This form has been emailed to '. $account->name);
  }
}

function example_mail($key, &$message, $params) {
  $data['user'] = $params['from'];
  $account = $data['user']->name;

  $attachment = array(
  'filecontent' => file_get_contents(DRUPAL_ROOT . '/README.txt'),
  'filename' => 'test.txt',
  'filemime' => 'text/plain',
  );

  switch($key) {
  case 'notice':
  $langcode = $message['language']->language;
  $message['subject'] = 'example submission from' . $account;
  $message['body'][] ='<p>'. $account .' has submitted an example.</p>';
  $message['params']['attachments'][] = $attachment;
  break;
  }
}

Hooray! Attachments are now working! Not too bad once you gather all the pieces together. Now, onto producing pdf attachments.

We will use the pdf generation capabilities of the print module. Installing and configuring the module is beyond the scope of this blog post, but I can tell you that it is easier than you think it would be and the directions on the module page are pretty straightforward. Now that we have this module installed and configured to show pdf versions of pages on the site, we need to tap into the print_pdf module in our custom code. We are going to access a hook of the print_pdf module called print_pdf_generate_path. This function is poorly named, since it’s return value is not a path at all, but is instead the actual file data for the pdf being created. We pipe this into the filecontent of our attachment and we are good to go.

function _example_form_submit($form, &$form_state) {
  _example_form_save($form, $form_state);
  global $user;
  $accounts = array($user, user_load(XX)); //you can add accounts to this array to notify
  example_notify($accounts, $user); //could also pass $form_state or other variables
}

function example_notify($accounts, $from) {
  $params['from'] = $from;
  foreach ($accounts as $account) {
  $params['account'] = $account;
  // example_mail() will be called based on the first drupal_mail() parameter.
  drupal_mail('example', 'notice', $account->mail, user_preferred_language($account), $params, $from->mail);

  drupal_set_message('This form has been emailed to '. $account->name);
  }
}

function example_mail($key, &$message, $params) {
  $data['user'] = $params['from'];
  $account = $data['user']->name;

  module_load_include('inc', 'print_pdf', 'print_pdf.pages');
  $file_content = module_invoke('print_pdf', 'generate_path', 'example-url/');

  $attachment = array(
  'filecontent' => $file_content,
  'filename' => 'example-filename',
  'filemime' => 'application/pdf',
  );

  switch($key) {
  case 'notice':
  $langcode = $message['language']->language;
  $message['subject'] = 'example submission from '. $account;
  $message['body'][] ='<p>'. $account .' has submitted an example.</p>';
  $message['params']['attachments'][] = $attachment;
  break;
  }
}

It’s downright simple once you see the example code, but believe me this took a lot of trial and error (since googling didn’t seem to lead to much useful information) to get everything to meld together. Of particular note is the use of module_load_include in order to access functions of other modules that exist outside of the main .module file. If you have any suggestions for improvement, or have questions, feel free to leave comments below.

Portions of this code were adapted from other examples available, but I don’t remember exactly from where. Mad props go out to you, Drupal community.

Building a flexible layout with jQuery splitters and accordions

By Jonathan on January 2nd, 2012
Jonathan

This is part 1 of a series: The Learning jQuery code browser. This article series explores the construction of the code browser tool that accompanies the book Learning jQuery, Third Edition.

The first challenge in building the code browser was finding a way to present all of the information required simultaneously. We need to be able to see the JavaScript code side-by-side with the finished product, while at the same time having easy access to the associated HTML and CSS for reference. In addition, we need controls for navigating among code samples easily.

The finished product uses a combination of accordion and splitter widgets to accomplish this.

A combination of HTML, CSS, and JavaScript is needed to put this together. First, the HTML.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Learning jQuery Code Listing Browser</title>

    <link rel="stylesheet" href="jquery-ui/css/smoothness/jquery-ui-1.8.9.custom.css" media="screen">
    <link rel="stylesheet" href="browse.css" media="screen">
    <script src="jquery-1.5.js"></script>
    <script src="jquery-ui/js/jquery-ui-1.8.9.custom.min.js"></script>
    <script src="jquery.history.js"></script>
    <script src="splitter.js"></script>

    <script src="browse.js"></script>
  </head>
  <body>
    <div id="container">
      <div id="navigation">
        <h1>Learning jQuery, Third Edition</h1>
        <label for="chapter">Chapter</label>
        <select name="chapter" id="chapter" size="1"></select>

        <label for="step">Code Listing</label>
        <div class="ui-state-default ui-corner-all"><a href="#prev" id="prev" class="ui-icon ui-icon-triangle-1-w">Prev</a></div>
        <input type="text" name="step" value="1" id="step">
        <div class="ui-state-default ui-corner-all"><a href="#next" id="next" class="ui-icon ui-icon-triangle-1-e">Next</a></div>
      </div>
      <div id="content">
        <div id="splitter">
          <div id="left-pane">
            <h3><a href="#html">HTML</a></h3>
            <div class="panel" id="html"></div>
            <h3><a href="#css">CSS</a></h3>
            <div class="panel" id="css"></div>
            <h3><a href="#javascript">JavaScript</a></h3>
            <div class="panel" id="javascript"></div>
          </div>
          <div id="right-pane">
            <div>
              <iframe id="result"></iframe>
            </div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

This HTML 5 code sets up divisions for the navigation area, the left pane, and the right pane. Within the left pane we have subdivisions for HTML, CSS, and JavaScript code.

There is obviously a significant amount of CSS involved here. The following is the portion of the CSS required for the basic page structure.

#navigation {
  padding: 10px 0;
  height: 20px;
  background-color: #000;
  color: #fff;
}

#left-pane {
  width: 250px;
}
#right-pane {
}

#splitter {
  clear: left;
  height: 100%;
  overflow: hidden;
}
#right-pane > div {
  padding-left: 20px;
  height: 100%;
}
#result {
  width: 100%;
  height: 100%;
  border: none;
}

With this HTML and CSS in place, we have a start at our page layout. There is still more work to do in styling the page, but in this instance we won’t care about graceful degradation for users without JavaScript enabled, since all of the code examples rely on JavaScript anyway. So, we’ll leave the rest of the styling work to the jQuery plugins we’ve been using.

The accordion widget

An accordion widget is pretty simple. we simply need to expand one item while collapsing the others. A basic approach is easy to outline:

$(document).ready(function() {
  $('#left-pane h3').click(function() {
    $('#left-pane div:visible').slideUp();
    $(this).next().slideDown();
  });
});

This gets the very rudimentary job done, but there are lots of details left untended. For example:

  • Setting up the initially-visible item
  • Gracefully handling clicks on the currently-active item
  • Keyboard support
  • Visual feedback that the titles are clickable
  • Expanding the active item to take up as much vertical space as possible
  • Various styling enhancements

These are all things we could take care of ourselves, but there’s no need to when the jQuery UI project has done the job for us. The jQuery UI accordion widget is simple to use, and very powerful.

$(document).ready(function() {
  $('#left-pane').accordion({
    fillSpace: true,
    active: 2
  });
]);

A call to .accordion() does almost all the work. The only parameters we have to provide are fillSpace, which makes sure the accordion uses all the vertical space available to it, and active, which lets us tell the widget to reveal the third item (the one containing JavaScript code) initially and to hide the other two.

The splitter widget

The accordion conserves vertical space in the left column. We also want to give the user flexibility, though, in deciding how much of the screen to devote to the source code and how much to the rendered output. A splitter widget will accomplish this.

Again, using a jQuery plugin is much more efficient than trying to write the code ourselves. The jQuery UI project doesn’t have a candidate to try, but Dave Methvin’s splitter plugin will fit the bill nicely.

Again, using the plugin couldn’t be very much simpler.

$(document).ready(function() {
  $('#splitter').splitter({
    type: 'v',
    anchorToWindow: true,
    cursor: 'col-resize'
  });
});

We are using three parameters in our call to .splitter() to reach the desired effect. The type parameter lets us specify that the splitter will run vertically (splitting the content horizontally). The anchorToWindow parameter ensures that the splitter fills up the entire window height, even when the window is resized. Finally, the cursor parameter allows us to choose an appearance for the mouse cursor while it is over the splitter, to give the user extra feedback.

With these two plugins in place and active, users can now switch between the three source code viewing areas at will using the accordion widget, and resize the source code and output areas using the splitter widget. Next up, we’ll be looking at how we populate these areas with real content.

The Learning jQuery code browser

By Jonathan on December 29th, 2011
Jonathan

This year, Karl and I completed the third edition of Learning jQuery. We’re very excited about the updates, which bring the book in line with the newest features of the library. We also used this opportunity to take our reader feedback into account. Exercises were added to the end of each chapter. The examples readers found confusing were elaborated on or rewritten. The biggest change, though, related to the structure of the second half of the book and the code examples therein.

Readers liked the first seven chapters of the earlier editions, which build up the basic concepts of the jQuery library. Each uses a self-contained web page, with all the code examples in the chapter relating to that page. In the second half of the book, though, all of the examples referred to the same fictional web site. While this gave a nice “real-world” feel to these examples, in practice readers were confused by multiple chapters requiring the same code base. It was also difficult for readers to view the effect of just one example in isolation from everything else that was going on. In addition, to accurately represent the code to the user, many pages at the end of the chapter needed to be devoted to code listings that were largely repetitive—pages that could instead be used for more explanatory prose.

To remedy this, the second half of the book was completely rewritten. Rather than being structured around concepts such as “tables” and “forms,” the chapters now mirror the structure of the first half of the book, stepping through the basic jQuery building blocks, but this time from a more advances perspective. This approach allowed us once again to use small web pages for each chapter, with all code examples for a chapter working on the same content.

What remained was the problem of handling the large code listings. A code download is provided with the book, so we felt a printed copy of all code was not particularly helpful to the reader. Instead, we wanted a way for the reader to be able to execute and experiment with the code at any stage of its development in a chapter. We also wanted to present this in a visually helpful way.

The result is the Learning jQuery Code Browser. This tool allows readers to view any listing in the book in the context of the rest of the code. They can see exactly which lines of code have changed, view the HTML and CSS the script applies to, and view the result of that code when run against the page.

This tool was built quite quickly, and is hardly a paragon of engineering, but nonetheless readers have found it very useful already. Creating it required work in HTML, CSS, PHP, and JavaScript, including the incorporation of several third-party libraries. This makes it worthy of some study as an example. In an upcoming series of articles, I’ll be breaking down the pieces and parts of the code browser, discussing how each component works. Topics will include:

  • Building a flexible layout with jQuery splitters and accordions
  • Combining HTML, CSS, and JavaScript on demand
  • Simple navigation UI widgets
  • Managing browser history and the back button
  • Syntax highlighting with GeSHi
  • Writing a simple “diff” script to highlight changed lines of code