Integrating external JavaScript libraries is a common task for Drupal developers. Whether you are adding a tracking script, a mapping API like Google Maps, or a popular library like jQuery Tools via a CDN, you need a reliable way to inject these scripts into your theme. While it might seem intuitive to list them in your theme's .info file, Drupal handles external assets differently than local ones.

In this guide, we will explore why the standard .info file approach doesn't work for external URLs and provide the best-practice solutions for adding external scripts in Drupal 7, while also touching upon the modern approach for Drupal 8, 9, and 10.

The Limitation of the .info File

In Drupal 7, the .info file is the heart of your theme's configuration. You typically add local JavaScript files using the scripts[] property like this:

scripts[] = js/local-script.js

However, the .info file is designed to look for files relative to the theme's root directory. If you attempt to add an external URL directly, such as:

scripts[] = http://cdn.jquerytools.org/1.2.6/jquery.tools.min.js

Drupal will attempt to find that file on your local server within your theme folder, leading to a "404 Not Found" error in your browser console and a failure to load the library. To handle external scripts, you must move beyond the static configuration file and utilize Drupal's PHP-based API.

Solution 1: Using drupal_add_js in template.php

The most robust method for adding external JavaScript in Drupal 7 is using the drupal_add_js() function within a preprocess hook in your template.php file. This function is highly flexible and allows you to specify that the script source is external.

Implementing hook_preprocess_page

By using hook_preprocess_page, you can inject the script only when a page is being rendered. Add the following code to your theme's template.php file (replace YOURTHEME with your actual theme machine name):

/**
 * Implements hook_preprocess_page().
 */
function YOURTHEME_preprocess_page(&$vars) {
  drupal_add_js('http://cdn.jquerytools.org/1.2.6/jquery.tools.min.js', 'external');
}

Why This Works

The second parameter, 'external', is critical. It tells Drupal's asset manager not to look for a local file and not to attempt to aggregate (minify/combine) this script with your local files. This preserves the integrity of the CDN link and ensures the browser fetches it from the correct remote location.

Solution 2: Conditional Script Loading

One advantage of using PHP over the .info file is the ability to load scripts conditionally. Loading a heavy external library on every single page can negatively impact your site's performance and SEO rankings.

If you only need a script on a specific content type or a specific page, you can wrap your code in logic:

function YOURTHEME_preprocess_node(&$vars) {
  // Only load the script on 'article' content types
  if ($vars['node']->type == 'article') {
    drupal_add_js('https://example.com/special-library.js', 'external');
  }
}

This approach keeps your site lean by ensuring users only download the assets they actually need for the current page.

Advanced Options for drupal_add_js

The drupal_add_js() function accepts an array of options as its second argument, providing even more control over how your external script behaves.

drupal_add_js('https://cdn.example.com/library.js', array(
  'type' => 'external', 
  'scope' => 'footer', // Move script to the bottom of the page
  'weight' => 5,       // Control the loading order
  'every_page' => TRUE // Hint for caching
));

Common Parameters Explained:

  • type: Set to 'external' for remote URLs.
  • scope: Defaults to 'header', but changing it to 'footer' can improve perceived page load speed by allowing the HTML to render before the script is fetched.
  • weight: If you have multiple scripts that depend on each other, use weight to ensure they load in the correct order (lower numbers load first).

Best Practices for External Assets

When working with external JavaScript, keep these best practices in mind to ensure security and performance:

  1. Always Use HTTPS: Even if your site is currently on HTTP, always use https:// for CDN links. This prevents "mixed content" warnings and ensures compatibility when you eventually move to SSL.
  2. Subresource Integrity (SRI): If security is a high priority, consider that external scripts can be compromised at the source. While drupal_add_js doesn't natively support SRI attributes easily in D7, it is a factor to consider for modern web standards.
  3. Local Fallbacks: If the CDN goes down, your site's functionality might break. Some developers choose to load a local version of the script if the external object is not detected in the browser.
  4. Avoid Aggregation Issues: External scripts are generally excluded from Drupal's internal aggregation. This is good because CDNs are already optimized, and trying to aggregate a remote file would cause significant server-side latency.

Modern Context: Drupal 8, 9, and 10

If you are working on a more recent version of Drupal, the process has changed significantly. Drupal moved away from drupal_add_js() in favor of the Library system.

In a modern theme, you would define the external script in your YOURTHEME.libraries.yml file:

external-jquery-tools:
  remote: http://cdn.jquerytools.org
  license:
    name: MIT
    url: http://opensource.org/licenses/MIT
    gpl-compatible: true
  js:
    http://cdn.jquerytools.org/1.2.6/jquery.tools.min.js: { type: external, minified: true }

Then, you would attach this library to your render array or via your .info.yml file. This structured approach is much cleaner and fits the modern Symfony-based architecture of Drupal.

Common Mistakes to Avoid

  • Hardcoding in html.tpl.php: While it is tempting to just paste a <script> tag into your theme's template files, this bypasses Drupal's asset management system. This can lead to duplicate scripts being loaded or conflicts with other modules.
  • Missing the 'external' flag: Forgetting the 'type' => 'external' argument is the #1 reason external scripts fail to load in Drupal 7.
  • Dependency issues: Ensure that if your external script requires jQuery, it is loaded after Drupal's core jQuery. Drupal usually handles this, but you can use the weight parameter to be certain.

Frequently Asked Questions

Can I add external CSS the same way?

Yes, Drupal 7 provides drupal_add_css(). Similar to the JS version, you should use the 'type' => 'external' option to load stylesheets from a CDN or external domain.

Does adding scripts in template.php affect performance?

If done correctly within a preprocess hook, the impact is negligible. However, you should always aim to load scripts in the footer ('scope' => 'footer') unless the script is required for initial page rendering (like an anti-flicker script for A/B testing).

Why isn't my script showing up in the source code?

First, clear your Drupal caches. Drupal caches the theme registry and preprocess functions. If you've just added the code to template.php, Drupal won't see it until the cache is cleared.

Wrapping Up

Adding external JavaScript to a Drupal theme requires moving from the static .info file to the dynamic world of PHP hooks. By utilizing drupal_add_js() with the external flag, you gain full control over where, when, and how your scripts are loaded.

Whether you are supporting a legacy Drupal 7 site or building for the future in Drupal 10, following these API-driven methods ensures your site remains maintainable, performant, and bug-free. Always remember to test your site's performance after adding external assets to ensure your users are getting the fastest experience possible.