Drupal 7, #states, and mutually exclusive checkboxes

This post will be a bit techy. I confronted and solved a minor problem yesterday, and in the spirit of the internet, thought I’d share the solution, in case anyone else tries something similar.

This is about Drupal forms, and specifically within forms, the #states capability, which is a way that form designers can tell Drupal to do jQuery magic things on the form elements, enabling or disabling some of them based on the state or value of others.

The typical example is a checkbox, that when checked, will either enable (css ‘disabled: false’) or make visible (css ‘display: block’) a dependent textbox. Simple enough, right? and for that kind of simple case, it works well.

Drupal’s Forms API is described here, and the related
drupal_process_states here.

This is what it looks like to configure a Form in Drupal:

That says, show the textfield only when the referenced checkbox is checked. The reference to the checkbox is with a jQuery selector. This one works, really straightforward. And, the state is managed by Drupal in both directions. When the referenced checkbox is checked, then the textfield is visible. When the referenced checkbox is unchecked, then the textfield becomes not visible.

But what if you want a set of mutually exclusive checkboxes?

Mutually Exclusive Checkboxes

One approach is to just use the above model, and have each checkbox depend on the other. In other words, something like this:

This will not work. The reason this does not work, is that the state is managed by drupal in both directions. When checkbox #1 is checked, then checkbox #2 becomes unchecked. Which means checkbox #1 gets checked. Which means checkbox #2 becomes unchecked. And if you turn on the Firebug debugger, you can see the logical loop going round and round, endlessly.

There was an approach described here that suggested using two conditions in the array. But that didn’t work for me; I still had the endless loop. After fiddling with this for an hour, searching around for hints, I decided to just do it myself with my own jQuery. The logic was simple to write. And, I didn’t want to fight the Drupal Forms API any longer.

So here’s the solution. Include this JavaScript in your module:

As you can see, it registers a ‘change’ hook for a specially-marked checkbox. And when the checkbox is affirmatively checked, it unchecks the other checkbox. When the checkbox is unchecked, it does nothing.

How does that JS get loaded? In the Drupal module code, do this:

And finally, how do we set up the checkboxes in the Forms API? Like this:

And that gets the desired behavior: It is possible for zero or one of those checkboxes to be checked, but not both.

It took more time to write this post than it took to build the solution shown here! And of course I never did manage to figure out how to do the same just using the Forms API. This is an example of an API, the Forms API in Drupal, that does some things well, and this one thing….? Not so well. Much easier to just jump out and solve it this way.

Maybe this will help some one else!

By the way, this is included in a Drupal module that allows administrators to verify / validate user registration.

Use PHP code to make WordPress redirect to secure site

Lots of people use the .htaccess redirect rules to force their wordpress sites to load with the secure option.

It looks like this:

But if you have a hoster that does not provide you the ability to modify the .htaccess file, that won’t work. These hosters typically set up your server behind their load balancer which means the wordpress code sometimes cannot directly infer whether HTTPS is in use. In other words, the $_SERVER[‘HTTPS’] is not correct.

It is possible to introduce code into your theme that will do what you need. This is the PHP code:

Insert that in your theme header.php file. Or maybe the functions.php file. Invoke the maybe_redirect_to_ssl_site() function in the theme header before emitting any HTML.

PHP Makes People Sad

Just read an enjoyable rant entitled PHP: a fractal of bad design by a nerd who calls himself Eevee.

A good effort!

I also found a link to PHP Sadness there, and a bunch of other links to sites that complain about PHP.

This kind of criticism is correct, and valid, but it’s also pretty common, and low-hanging fruit.  I mean, come on.  We all know this stuff, right?  We just haven’t bothered to catalogue all the problems.

The other problem with this criticism is … reality.   PHP has had these problems since forever, and if they were really so significant, then no one would use it at all.  So there is something of value in PHP, and some part of it’s design is helping people get things done.

Yes, there are a million pitfalls.  Yes, there is a lack of consistency across a broad swath of the PHP built-in libraries. But apparently the people using PHP don’t suffer all that much for it.  Lots of people use PHP to build simple systems quickly, without getting all tangled up about whether to check exceptions or not, or whether “1” is the same as 1.

If you want a beautifully designed and consistent programming language environment, PHP is not it.  Ok, then.  Move along. No one is forcing you to use PHP.

 

PHP and JSON and Unicode, Oh my!

Today I had a bit of a puzzle.  The gplus widget that I wrote for WordPress was rendering Google+ activity with a ragged left edge.

Google+ Widget
The ragged edge is shown for *some* activities

As geeks know, html by default collapses whitespace, so in order for the ragged edge to appear there,  a “hard whitespace” must have crept in, somewhere along the line.   For example, HTML has entites like   that will do this.  A quick look in the Chrome developer tool confirmed this.

I figured this was a simple fix:

$content = str_replace(" "," ", $content);

Simple, right?

But that didn’t work.

Hmmm…. Next I added in some obvious variations on that theme:

$content = str_replace(" "," ", $content);
$content = str_replace("\n"," ", $content);
$content = str_replace("\r"," ", $content);

That also did not work.

This data was simple json, coming from Google+, via their REST API. (But not directly. I built caching into the gplus widget so that it doesn’t hit the Google server every time it renders itself. It reads data from the cache file if it’s fresh, and only connects to Google+ if necessary). A call to json_decode() turns that json into a PHP object, and badda-boom. Right?

Turns out, no. The json had a unicode sequence 0xC2A0, which I guess is a non-breaking space if you speak Unicode. Not sure how that got into the datastream, I certainly did not put it in there myself, explicitly. And when WordPress rendered the widget, that sequence somehow, somewhere got translated into  , but only after the gplus widget code was finished.

I needed to replace the unicode sequence with a regular whitespace. This did the trick.

$content = str_replace("\xc2\xa0"," ", $content);

PHP, JSON, HTTP, HTML – these are all minor miracle technologies. Sometimes when gluing them all together you don’t get the results you expect. In those cases I’m glad to have a set of tools at my disposal, so I can match impedances.

A Google+ Widget for WordPress

I looked for, but did not find, a reliable, easy to use, solid Google+ widget for WordPress. All I want to do is display on my WP blog a little sidebar listing of the 4 or 5 most recent activities from my G+ account.  Is that so hard?

Not sure why I couldn’t find it, but since I am interested, I looked into building a plugin. How hard could it be?  Turns out: not very.  You can see the results to the right.

Google is encouraging programmatic use of their social network.  They’ve published the network protocols – the HTTP request and response messages required to do various things. They also produced and released client-side libraries that implement these protocols – very nice. They’ve got one for PHP.   So, yeah, obviously, that seems like the right thing to use as a base for WordPress interaction with Google+ .

The “Hello World” of PHP-to-Google+ apps:

<?php 
$apiKey = "xxx-double-secret-xxxx";
$id = "101866550969463527083";

require_once 'src/apiClient.php';
require_once 'src/contrib/apiPlusService.php';

$client = new apiClient();
$client->setDeveloperKey($apiKey);
$plus = new apiPlusService($client);
$person = $plus->people->get($id);

echo "<h1>User info</h1><pre>\n";
print_r($person);
echo "</pre>\n<hr/>\n";

$collection = 'public';
$results = $plus->activities->listActivities($id, $collection);

echo "<h1>Activites</h1><pre>\n";
print_r($results);
echo "</pre>\n<hr/>\n";

echo "<h1>Comments</h1>\n<ul>\n";
foreach ($results['items'] as $item) {
    if ($item['verb'] == 'post' && is_array ($item['object'])) {
      print('<li>' . $item['object']['content'] . "</li>\n");
    }
}
echo "</ul>\n";

That worked pretty well, and took about 60 seconds of download and install. With that kind of momentum I went right into constructing my first wordpress plugin.   It’s a simple model – implement a class that extends WP_Widget .  Provide a widget() method that renders the thing. Inside the render function, include a subset of the code from the Hello, World app above. Ba da boom.

WordPress seems very nice to use, and very easy to extend.

This plugin is prety simplistic. It uses the API Key method, rather than OAuth2, for authentication to Google. It works just fine.  For a highly-loaded website, I’d need to insert some caching to eliminate unnecessary hits on the Google+ service. But for my nice and friendly blog, it’s just fine.

Here’s the code if anyone else wants to try it out.