Adding JS libraries to a Drupal project with Libraries API
As a front-end developer, I often need to add JavaScript libraries to a project for front-end interaction. With most things Drupal, there are many different ways to go about adding these libraries, though some can be said to be more stylish than others. An approach that I’ve become particularly fond of utilizes a contributed module called Libraries API, which gives Drupal developers a consistent way to add libraries of all sorts.
To be entirely clear, a library is a bundle of code, often times CSS and JS, though it may be a bundle of PHP, or something else entirely. It's usually agnostic in the sense that the library isn’t targeted to Drupal applications.
In the past, I’ve added JS libraries directly to my theme, and then added the script to a page with drupal_add_js(). This means that the library is confined to the theme. If I want to use the library in a custom module as well, I have to reliably know the name of the theme, as that’s how drupal_get_path() works. That’s just straight-up bad practice, as it doesn't lend itself to modularity or reusable code.
Another method for adding JS libraries is the use of contributed modules named for the JS libraries they implement. The downside is that these JS libraries are often configured via the Drupal UI and frequently limit the configuration options of the library, or they are coupled to an outdated version of the library. In most cases, a requirement for these modules is that the library be added via Libraries API anyways.
By contrast, If I take the time to write a few extra lines of code and implement the library myself, I can ensure that it's available to other modules or themes in the project. This allows me to interact with the library the way the original author intended.
Working with Libraries API is fairly straightforward. As with all things, it’s a good idea to read the full documentation, which can be found at https://drupal.org/node/1342238, but you can get rolling with just a few lines of code.
Quick overview:
- Install Libraries API
- Add the library to sites/all/libraries
- Create a very short custom module that tells Libraries API about the library
- Add the library to the page where you want it
- Use it!
You’re using Drush, right? That’s what I thought. To install Libraries API, simply:
$ drush dl libraries
Next, create a directory at sites/all/libraries. If you're not using Drush, download the module from drupal.org/project/libraries, and add it to the contrib modules directory.
Add the library to sites/all/libraries
Download a library, and add it to the libraries directory at sites/all/libraries. For this example, I'm using a JS library called FlexSlider to add a carousel to my project. To add the library, I download flexslider, and add it to my Drupal project as sites/all/libraries/flexslider.
Create a very short custom module that tells Libraries API about the library
In a custom module, use hook_libraries_info() to make the library available to the entire project. Once a library is registered, it can be used in custom modules, themes, whatever.
/**
* Implements hook_libraries_info().
*/
function MYMODULE_libraries_info() {
$libraries = array();
$libraries['flexslider'] = array(
'name' => 'FlexSlider',
'vendor url' => 'http://flexslider.woothemes.com/',
'download url' => 'https://github.com/woothemes/FlexSlider/zipball/master',
'version arguments' => array(
'file' => 'jquery.flexslider-min.js',
// jQuery FlexSlider v2.1
'pattern' => '/jQuery FlexSlider v(\d+\.+\d+)/',
'lines' => 2,
),
'files' => array(
'js' => array(
'jquery.flexslider-min.js',
),
),
);
return $libraries;
}
One gotcha that seriously gotcha'd me is the necessity of providing a value for either version argument or version callback. The documentation for hook_libraries_info() says that both are optional, but if at least one isn't provided, the library isn't available to load. If you're not concerned about the version of the library, you can use a short-circuit function for the version callback:
/**
* Implements hook_libraries_info().
*/
function MYMODULE_libraries_info() {
$libraries = array();
$libraries['my_library'] = array(
// Etc etc.
'version callback' => 'short_circuit_version',
);
return $libraries;
}
/**
* Short-circuit the version argument.
*/
function short_circuit_version() {
return TRUE;
}
Add the library to the page where it's needed
In this case, I’d like to load the FlexSlider JavaScript with a specific view. Hence, a views hook is appropriate. Notice the nice trick for hooking specific views.
/**
* Implements hook_preprocess_views_view().
*/
function MYTHEME_preprocess_views_view(&$vars) {
// Uncomment the lines below to see variables you can use to target a view.
// This requires http://drupal.org/project/devel to be installed.
// dpm($vars['view']->name, 'view name');
// Hook view id specific functions.
// This is a super neato trick.
if (isset($vars['view']->name)) {
$function = 'preprocess_views_view__' . $vars['view']->name;
if (function_exists($function)) {
$function($vars);
}
}
}
/**
* Implements preprocess_views_view__VIEW().
*/
function preprocess_views_view__YOURHOOK(&$vars) {
$display_id = $vars['display_id'];
$classes = &$vars['classes_array'];
$title_classes = &$vars['title_attributes_array']['class'];
$content_classes = &$vars['content_attributes_array']['class'];
// Uncomment the lines below to see variables you can use to target a view.
// This requires http://drupal.org/project/devel to be installed.
// dpm($vars['view']->name, 'view name');
switch ($display_id) {
// Call flexslider scripts.
case 'page':
libraries_load('flexslider');
break;
}
}
Now that FlexSlider is loaded, I can bind it to my view!
(function ($) {
$(window).load(function() {
$('.slideshow').flexslider({
animation: "slide",
controlNav: false,
namespace: 'slide-',
selector: '.slide-list > .slide-list-item'
});
}); // end window.load
})(jQuery);
As you can see, Libraries API allows for a much more elegant and scaleable way of managing JavaScripts.