“There is some decent documentation, but not too much because I am lazy.”
Today I Learned...
Drupal 6.x + jQuery 1.4.2 = New Possibilities
jQuery is the bread and butter of rapidly developing a highly-interactive websites, and Drupal has long made use of it, and indeed includes it as part of its core install.
There's only one catch... Drupal 6.x (the current stable version of Drupal) is still living in 2008, shipping with the antiquated jQuery 1.2.6. Over the intervening two years since the release of 1.2.6, there have been substantial additions and upgrades to the jQuery library, as well as several tools (such as the jQTouch library) that rely on those changes. As of the writing of this post, the current jQuery version is 1.4.2.
The jquery_update module has done a fantastic job of letting users upgrade the version of jQuery used by Drupal, but unfortunately the jquery_update module got stuck at 1.3.2.
The culprit: a bug in Drupal's core function drupal_to_js(). This function exports a PHP variable into the JS space. The issue is that it preforms some text modification to convert characters such as ampersands, angle-brackets, and line endings into their escaped unicode equivalents. Unfortunately, it does not do a very complete job and as a result, many issues arise when jQuery is upgraded to 1.4.2.
As is often the case, the Drupal community stepped up and created a patch that fixes the issue (for your convenience, I've attached this patch below). Unfortunately, after more than six weeks, there has been little-to-no movement to include the patch in future releases of Drupal 6.x. This leaves us with the distasteful, but worthwhile, task of repatching the core whenever a new core update is released.
Shared Multisite Sign-on the Easy Way
This weekend I discovered (quite by accident) a very simple way to enable shared sign-on across multiple Drupal sites running in a multisite configuration.
Suppose you have the following sites:
- phones.com
- htc.phones.com
- iphone.phones.com
- motorola.phones.com
The first requirement is that all the sites be running on the same domain. The examples above work — they're all subdomains of phones.com.
The second requirement is that all the sites share the same user tables. If all your sites are sharing one big database, you don't need to do anything, since all your tables are already shared. (This was my setup.) If some or all of your sites are using separate databases, though, use table prefixing to share the following tables among all your sites:
- users
- sessions
- roles
- authmap
If you use something like content_profile to store profile data, and you want to share that across sites, you'll need to share those tables, too.
So now you've got your users shared at the database level, but a person who logs in at htc.phones.com still won't stay logged in when they visit iphone.phones.com. That's because the 'host' parameter for the cookies on each site are still tied to their individual domains: htc.phones.com for htc.phones.com, iphone.phones.com for iphone.phones.com, and so on. As far as the browser is concerned, each site is entirely separate.
You can break the cookie barrier down pretty easily though (after all, it's just a cookie). Just add the following line to all of your 'settings.php' files:
$cookie_domain = '.phones.com';
The key is the leading period, which functions as a subdomain wildcard.
Drupal picks up on this and rewrites your cookies for you. Now, once you log in to any subdomain on phones.com, you'll be logged in to all the subdomains. Done.
Note that there are a few more requirements for cookie sharing than the ones I talked about.
Block Visibility with Context and Zen
Turns out that if you're using Context with a Zen 2.x-based subtheme, any block visibility rules you set up with Context get blown away by Zen. The reason is that both Context and Zen implement the `theme_blocks()` function, but Zen, being unaware of Context, clobbers all the work done by Context.
The solution is pretty simple: apply this patch to Zen. Note that you must be using at least Context 3.x for the patch to work; otherwise, you'll get a WSOD.
And for those who are interested, here's some background on the issue.
Dropbox CLI for CentOS 5 the easy way
Dropbox hardly needs any introduction; put files in your Dropbox and they show up everywhere else you have Dropbox installed and dropbox.com. A feature about Dropbox that is probably not as widely known is that free accounts come with 30 days of undo history and Pro accounts can get "Pack Rat" that keeps unlimited history of changes. The history of files, including reverting deleted files, was particularly interesting to me, since I could hook in my latest daily MySQL dumps from AutoMySQLBackup to Dropbox and have 30 days of backups for free available from anywhere dropbox.com is accessible.
The problem is that we use CentOS for our servers and the Dropbox Linux builds are geared for distributions like Ubuntu and Debian that have updated versions of required software like Python, libc, and others, that I did not want to upgrade by hand on my systems and risk the integrity of the system packages. But, I got it to work anyway, read on for how I got Dropbox CLI installed on CentOS without replacing any system files.
How to Configure Eclipse PDT with Zend Server Debugger on MAMP for Drupal
Anything involving Eclipse is always epic. First, you have to get your head around what distribution of it to use, as confusing as one's first introduction to Linux distributions (there are different kinds of Linux?).
Next, you have to grok the fact that the Zend Debugger must be installed on your server. In this case, MAMP.
Then, you have to make Eclipse listen to the debugging information being outputted, on the debug port.
Finally, you have to figure out how to use a debugger effectively (not in scope, but careful, debugging will blow your mind).
I started with this screencast, lulled by his easy manner of speech. The directories in MAMP are slightly different, like 5.2 and 5.3 instead of whatever he said. Not a big deal, just noting it.
Great! I hit "Test Debug" and...
Test Debug Server: Web server connection failed. Please verify that the address ....
So then I went to:
Eclipse -> Preferences -> Debug -> Installed Deguggers
And change the Zend debug port to whatever the output of your phpinfo gives you, which in my case was 65535.
I knew something was happening at that port because
telnet 127.0.0.1 65535
and typing some random stuff produced errors with the word "debugger" in it (thanks for the tip, Dan).
But it turns out the real problem was that there was a superfluous
zend_extension = "/Applications/MAMP/bin/php5.2/lib/php/extensions/no-debug-non-zts-20060613/xcache.so"
in my php.ini file. Anyone else notice that these config files get kinda crufty even without touching them?
Commented it out and now I get a happy:
Test Debug Server: Success!
Thanks much to Rebecca Janine Wise for her excellent post with configuration errata. Definitely worth a read if you are configuring Eclipse PDT.
Upgrading Open Atrium past the beta4 boundary
Open Atrium (http://www.openatrium.com) is best described as an "Intranet in a box" that sits atop Drupal 6. With the release of Open Atrium 1.0-beta4, Development Seed made a few crucial changes to the way OA is configured and structured. Now at beta7, there are still some older OA sites out there that are still running versions prior to beta4. Those sites require a little extra work to upgrade since they need to be upgraded to beta4 first, and then can be upgraded to beta7 and beyond.
It should also be noted that each release of Open Atrium contains a version of the Drupal core as well. I do not personally know if there are any potential issues with upgrading the version of Drupal independently of Open Atrium, but I do know that updating Open Atrium will typically upgrade the Drupal Core as well.
The basic steps for upgrading Open Atrium to beta4 are straightforward, but there are a couple pitfalls that you should watch out for:
1. Make sure you have a backup of EVERYTHING (your codebase, your database, etc)
2. Do NOT visit your site in a browser until you've finished all of the steps
After observing the above pitfalls, start with a fresh beta4 codebase and copy over your files and contributed modules.
Next, make sure you follow the section titled "Upgrading from Atrium 1.0-beta3.x to 1.0-beta4" located here: http://drupalcode.org/viewvc/drupal/contributions/profiles/openatrium/UP...
Items 1, 2, and 3 are mission critical. Using drush:
drush vset install_profile openatrium
drush cc all
drush updatedb
Before beta4, OA did not use the install_profile variable. Starting with beta4, if you don't have this variable, you will at best be stuck with the pre-beta4 themes and features. At worst, you'll be stuck on either an unthemed site or a garland Drupal.
Using Tokens in Comment-Triggered Email Notifications
The stock "Send Email" action type that ships with Drupal 6 does't offer a whole lot of options for including content from comments in your triggered emails.
In fact, it doesn't offer any.
There has been a good deal of discussion on this: a patch has been proposed and a stop-gap helper module has been posted to drupal.org.
Before you go that route, though, check out this post on using the Token Actions module to provide access to the full array of available tokens in your email. Thanks to Erik Weik at New Rivers Digital for the great post.
We're using Trigger-based email notifications to fight spam and help our clients be engaged with their commenters.
How do you use and implement comment notifications?
Hiding text in IE7 with CSS
Negative indent. Hackish solution, but it gets the job done... most of the time. It fails spectacularly in IE7, however.
If you're ever looking to hide that special text from your evil seventh aunty thrice-removed (i.e. ie) try this handy trick
#selector {
color: transparent;
text-transform: capitalize;
}
Interesting tidbit. IE will ignore the transparent color UNLESS you apply a text-transform to it as well. That seems to be the cue that IE waits for before doing anything TOO crazy.
Downloading Modules and Themes when ftp.drupal.org is Down
As of this posting, ftp.drupal.org has been down for about five hours. This is kind of a bummer, because as long as FTP is down, you can't download new modules.
Or so I thought. If you use Drush, you can easily check out the code for the latest stable release of a module from CVS using the --package-handler argument:
drush dl betterselect --package-handler=cvs
As always, Drush figures out which version of the module (or theme) is the latest and grabs that for you. The only difference from using ftp.drupal.org is that you'll get the CVS folder in your sites/…/modules directory, but you can just delete it. Or not. It's not hurting anything.
Even if you're not using Drush, though, you can always check the code out from CVS directly.
The really funny thing, however, is that if you're not already using Drush, you can't use Drush to download Drush, which you could do if you were already using Drush — in which case, of course, you would not need to. I believe the lit kids call this "irony".
Drupal Boost Module Caches CSS: Can't Change File After Boost Uninstall
So when working with a dev site, I couldn't figure out why my changes to CSS weren't propagating.
I turned off the boost module, cleared the cache, restarted apache.
Then I realized that Apache must be actually not getting to the file. And the only place to do that in Drupal is the .htaccess file.
Viola! Remove this from your .htaccess:
### BOOST START ###
AddDefaultCharset utf-8
<FilesMatch "(\.html|\.html\.gz)$">
<IfModule mod_headers.c>
Header set Expires "Sun, 19 Nov 1978 05:00:00 GMT"
Header set Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0"
</IfModule>
</FilesMatch>
<IfModule mod_mime.c>
AddCharset utf-8 .html
AddCharset utf-8 .css
AddCharset utf-8 .js
AddEncoding gzip .gz
</IfModule>
<FilesMatch "(\.html|\.html\.gz)$">
ForceType text/html
</FilesMatch>
<FilesMatch "(\.js|\.js\.gz)$">
ForceType text/javascript
</FilesMatch>
<FilesMatch "(\.css|\.css\.gz)$">
ForceType text/css
</FilesMatch>
# Gzip Cookie Test
RewriteRule boost-gzip-cookie-test\.html cache/perm/boost-gzip-cookie-test\.html\.gz [L,T=text/html]
# GZIP - Cached css & js files
RewriteCond %{HTTP_COOKIE} !(boost-gzip)
RewriteCond %{HTTP:Accept-encoding} !gzip
RewriteRule .* - [S=2]
RewriteCond %{DOCUMENT_ROOT}/cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.css\.gz -s
RewriteRule .* cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.css\.gz [L,QSA,T=text/css]
RewriteCond %{DOCUMENT_ROOT}/cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.js\.gz -s
RewriteRule .* cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.js\.gz [L,QSA,T=text/javascript]
# NORMAL - Cached css & js files
RewriteCond %{DOCUMENT_ROOT}/cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.css -s
RewriteRule .* cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.css [L,QSA,T=text/css]
RewriteCond %{DOCUMENT_ROOT}/cache/perm/%{SERVER_NAME}%{REQUEST_URI}_\.js -sRun Mac Script on Wake from Sleep: Login to iChat
Having switched to the Mac for my work environment, I missed some of the built in scripting that Linux offers natively. Turns out, the Mac offers this too. There are a few minor hurdles to clear in order to start scripting on the Mac. The trick is the interplay between AppleScripting and shell scripts.
My problem was that iChat wasn't waking up after resume from sleep. You may say, "Use Adium!" But Adium crashes and crashes, and doesn't let me add new contacts. Tried the beta, etc.
So I wrote a script which logs into iChat and sets status to "available" that runs on resume from sleep.
First off, install MacPorts.
Next, sudo port install sleepwatcher
Sleepwatcher is invoked in daemon mode to run a command on wake, sleep, or other things. Check out the man page: man sleepwatcher It's pretty powerful.
In order to find out more about the commands that iChat would accept, I created a shortcut to Applescript editor (it's under Utilities) on the dock, then dragged iChat onto it, which revealed the Applescript Dictionary for that program. I tested this:
#!/bin/sh
osascript -e 'delay 10
tell application "iChat"
log in of service "youruseraccount"
log in of service "yourotheruseraccount"
set the status to available
end tell'
save as /path/to/wake.sh
Now, set up an Applescript to run that script. Paste in this code:
do shell script "/opt/local/sbin/sleepwatcher -w /path/to/wake.sh &> /dev/null &"
Compile it, then save it as an application. This program runs the AppleScript app you've created as an background process and runs the terminal command also. In this way you can add it as a login item.
Go to System Preferences -> Accounts -> Login Items and add it there.
Done. Now, ten seconds after login, iChat will log in and set status to available.
Is it Safe to Upgrade a Module? Is My Module Hacked?!?! Oh NO!!!
So, in my last post, I upgraded to bleeding-edge jquery, hacking the jquery update module. Yay.
How do I tell my systems administration not to blindly drush upgrade that module?
The answer? The hacked module.
It will diff your module files against those in Drupal's CVS and tell your sysadmin not to upgrade a module.
Here's what you see:

Add Bleeding Edge Jquery to your Drupal
In the process of implementing a design today, the javascript provided required jquery 1.4 as a dependency.
What is the answer to this problem?
NOTE: See this more recent post on adding jQuery 1.4 to Drupal
A couple of resources:
jQuery No Conflict allows you to load multiple version of jQuery on the same page for different code.
jQuery update module allows you to get up to jQuery 1.3 in Drupal 6.
If you try to upgrade to 1.4 on your global Drupal install, you will break your Drupal.
Youtube's Flash Controls Broken on 64-bit Ubuntu in Firefox
In Firefox, in 64-bit Ubuntu, using flashplugin-nonfree, the controls for Youtube don't work.
I found this answer on the Ubuntu Forums.
sudo nano /usr/lib/nspluginwrapper/i386/linux/npviewer
Then add:export GDK_NATIVE_WINDOWS=1 before the last line of text.
Restart FF, and it's all good.
Drupal Fails to Set Active Menu Trail, Causing Context to Fail
While trying to use the Context module's menu context conditions, I noticed that certain pages, though in the menu tree "Primary Links" were not properly passing the proper active menu to the context module.
Helpful: Using the Devel module's Context Inspector block to figure out if the context was failing to be called.
Bryn and I worked out that this was likely a problem with Drupal's menu system.
Helpful: Using Devel's PHP Execute block to call various menu functions from Drupal's Menu API page to inspect what the active menu trail was.
Helpful: pasting in this block of code to see what was the matter dpm(menu_get_active_trail());
We found that calling menu_set_active_menu_name('primary-links') set the active menu properly.
Now, where and how do we call that function?
Ctools uses a nice snippet that can be pasted into a helper module.
Here's what worked
<?php function your_module_init() {
//menu_set_active_menu_name($menu_name = 'primary-links');
if (menu_get_active_menu_name() == 'navigation') {
$item = menu_get_item();
$mlink = db_fetch_object(
db_query("SELECT * FROM {menu_links}
WHERE link_path = '%s'", $item['href']));
if ($mlink && isset($mlink->menu_name)) {
menu_set_active_menu_name($mlink->menu_name);
}
}
} ?>
The module Menu Breadcrumb uses a variant of this function to unbreak the Drupal menu system.
So as an alternative to pasting this code into a module, you can try installing Menu Breadcrumb and see if your life is magically better.






