Drupal

Optimizing Drupal7 CSS and JS

Even though Drupal (since long ago) supports merging CSS and JS into one file each, after I upgraded from v6 to v7, I still ended up getting more than one of each. It turns out, Drupal has some notion of groups, and it would only merge the CSS / JS elements within each group. I did some web searches, and came up with the following:

function pixture_reloaded_js_alter(&$js) {
  if (arg(0) === 'admin' || strpos($_GET['q'], 'search/google') === 0) {
    return;
  }

  uasort($js, 'drupal_sort_css_js');
  $weight = 0;

  foreach ($js as $name => $javascript) {
    $js[$name]['group'] = -100;
    $js[$name]['weight'] = ++$weight;
    $js[$name]['every_page'] = 1;
    $js[$name]['scope'] = 'footer';
  }
}


function pixture_reloaded_css_alter(&$css) {
  uasort($css, 'drupal_sort_css_js');

  $print = array();
  $weight = 0;
  foreach ($css as $name => $style) {
    $css[$name]['group'] = 0;
    $css[$name]['weight'] = ++$weight;
    $css[$name]['every_page'] = TRUE;

    if ($css[$name]['media'] == 'print') {
      $print[$name] = $css[$name];
      unset($css[$name]);
    }
  }

  $css = array_merge($css, $print);
}

This goes into the Theme's template.php file, in my case I use the Pixture Reloaded theme. I don't know much about Drupal nor PHP, so I don't know what this might break. But this accomplishes three things:

  1. Merge all CSS into one single CSS.
  2. Merge all JS into one single JS.
  3. Move the JS to the "footer" of the page (this is important for improved page rendering, but could potentially break some sites I'd imagine).

Hacking: 

Druapl 7 problems behind a proxy

I run Drupal behind an Apache Traffic Server caching proxy. In my setup, the proxy listens on port 80, and the real Apache HTTPD server listens on port 82 (which is firewall off). In my Traffic Server remap.config, I have a rule like

map http://www.boot.org  http://www.boot.org:82

Granted, in retrospect, this is not the best of setups, but it does however causes serious problems with Drupal 7, whereas it does not cause problems with Drupal 6. In D7, the favicon.ico and all JS and CSS URLs in the head are created to use absolute URLs. I don't set an explicit $base_url in my Drupal settings.php, more on that later, and this causes the URLs to get the wrong base! These URLs are all getting a form like

http://www.boot.org:82/misc/favicon.ico

Yikes! This obviously fails, since port 82 is not accesible from the outside. Browsing the forums, the "solution" seems to be to set the $base_url in the Drupal settings.php configuration file, e.g.

$base_url = 'http://www.boot.org';  // NO trailing slash!

This does indeed solve the problem, however, it now breaks when I want to use e.g. https://www.boot.org for admin access. Besides, why these URLs should be absolute, is a mystery to me, they certainly were not in D6.

The solution I'm ending up with is of course to change Apache Traffic Server to use what we call "pristine host headers", so that the Origin server (Apache HTTPD and Drupal) sees the original client Host: header. I could not get any help from the Drupal IRC, or forums, but if anyone has any insight on why D7 is doing this crazy stuff with absolute URLs, please post. In an ideal world, they really should change these to be relative, e.g. /misc/favicon.ico.

Hacking: 

Drupal, Traffic Server, HTTPS and CDNs

I use Drupal for most of my sites. It generally works well, despite all the weirdness it does (Drupal 7 is doing strange things behind a proxy, more later). One thing is, I've started using a CDN (NetDNA) for my site. With HTTPS, this generally doesn't work well, since I'm not enabling HTTPS for the CDN (at least not yet). The CDN module in Drupal generally works well, but I couldn't see an option to prevent it from using the CDN with HTTPS. This would generate those annoying warnings from Internet Explorer for example.

Since I'm also using an Apache Traffic Server proxy in front of Apache HTTPD, the protocol information was lost oncey it hit Apache, PHP and Drupal. Bummer. I browsed through the CDN code, and noticed they do indeed honor a header of X-Forwarded-Proto, which if set to "https" will prevent the CDN from being used. I added a plugin for my remap rules, with a config like

[SEND_REQUEST_HDR]
        X-Forwarded-Proto =https=

And I activated this for the https remap.config rules for Apache Traffic Server. With this, my Drupal site now stops using the CDN when Apache Traffic Server maps from https:// to the http://localhost URL.

Hacking: 

Filtering Drupal comment spam

I get a fair amount of comment spam on my blog, and even after I changed all comments to be moderated, the spammers still persist. I decided to do something about this, and working under the assumption that most spammers are from a few countries, I decided to implement a Geo-location filter for Apache Traffic Server. The code is currently available at http://svn.apache.org/repos/asf/trafficserver/plugins/geoip_acl/, and only works with MaxMind's APIs (but I'd be more than happy to add support for other Geo-location APIs). This plugin also requires PCRE, but that's already a requirement for building ATS, so shouldn't be a problem.

Once compiled and installed (see the README), setting this up is fairly straight forward. In my remap.config, I now have the following rule

map http://www.ogre.com http://localhost:69 @plugin=geoip_acl.so @pparam=country \
       @pparam=regex::/home/server/etc/deny_spam.conf


This says to apply a country based Geo-location filter on this rule, using the additional configurations from deny_spam.conf. This file contains one single line:

^comment/       deny    CN RU IN

This might look draconian, but for now I'm disabling all comment posts from China, Russia and India. For more details on the plugin configurations and features, again see the README from the source above.

Enjoy!

Hacking: 

Drupal and e-commerce

I recently helped a friend setting up his new E-commerce site (http://www.weinerwraps.com/) using Drupal. We were considering a few modules, and finally decided on using UberCart. Now, our site isn't flashy, or have fancy graphics, but getting it functional was really easy. What we currently have working is

  • Paypal payment option
  • USPS shipping (with shipping calculations)
  • Basic cart features, different products, checkout options etc.

We've had a few issues on the way, most notably (and very confusing) was that the shipping cost calculator stops working if you disable the country field from the user entry for the shipping address. This made absolutely no sense to me (since we only ship to the US), and there were no errors or indicators whatsoever. Clearly someone didn't think through a typical use case scenario here ... Other open issues include

  • We have an optional addition to each order, for embroidery, where we'd like the price to be adjusted based on the length of the entered text.
  • There's no way to make the product picture adjust to selected options. There are a few modules that claim to do this, but none that really works.

All in all, setting up an E-commerce site with Drupal and UberCart has been a pretty good experience.

Hacking: 

Must-have Drupal modules

This collection of pages is my own personal experience with various 3rd party Drupal modules. I'm not really saying you must have these modules, but I personally find them incredibly useful. I'm not ranking these modules in any particular order, instead I'm trying to organize them by functionality. If you have suggestions for modules that I ought to include here, please let me know, and I'll be happy to add them (after I try 'em of course).

Content related modules

The modules in this section either create new content types, or let you manipulate or create content types.

Hacking: 

Pages

Subscribe to RSS - Drupal