Copyright © 2004–2010 OpenSourcery, LLC. This work is licensed under a Creative Commons Attribution 3.0 United States License.
The context module provides great flexibility in terms of the available ways to set a context, but it's also remarkably straightforward to define custom conditions.
In order to set arbitrary contexts, hook_context_conditions() is implemented to define values and such. This example will use the value of a CCK field, called field_foo:
/** * Implementation of hook_context_conditions(). */ function mymodule_context_conditions() { $items = array(); // The key used here will be used below when setting the context. $items['mymodule_foo'] = array( '#title' => t('Field Foo Value'), '#description' => t('Set this when field_foo has a certain value.'), '#options' => array( // Note, these are hardcoded here for simplicity, but could // easily use something like CCK's content_allowed_values() api // function for more dynamic population. 'value1' => t('Label 1'), 'value2' => t('Label 2'), ), '#type' => 'checkboxes', ); return $items; }
The only other step is to actually fire the code that sets the context somewhere. In the example of setting a context based on the value of a CCK field, this can be done in hook_nodeapi(). But something like hook_init() can also be used.
function mymodule_nodeapi(&$node, $op, $teaser, $page) { if (isset($node->field_foo[0]['value']) && $op == 'view' && $page && menu_get_object() === $node) { // Use the same key here as used to define the context condition // above. Note, this logic would need some re-working if // field_foo allowed multiple values. context_set_by_condition('mymodule_foo', check_plain($node->field_foo[0]['value'])); } }
That's it. Contexts can now be added through the UI or through code that react to the value of field_foo.
The workflow module allows a piece of content to be transitioned through arbitrary states. It is most commonly used (as I've seen it) as a replacement to the core node workflow of published/unpublished. Recently I was working on a pair of sites that required a very simple workflow of draft/published (if you're wondering why core couldn't be used in this case, it has to do with the very high level of permissions required to toggle the published/unpublished bit). The sites also made extensive use of node reference, views and context for positioning various parts of the node. Not having visual indicators within those views for the end user to determine which nodes were in a draft state, and which ones were published quickly became an obvious usability issue.
The first step in the improvements applied was to add the workflow state field to every view in question.

However, as packaged with workflow, it doesn't provide a very nice output, and only nodes in the Draft state needed a visual indicator.
Using the following preprocess function, the fields for undesired workflow states are removed, and a key CSS class is added (in this case, Published content didn't need to be highlighted in such a manner).
/** * Preprocess function for template_preprocess_views_view_fields(). * * - Adds workflow class for rows in the 'Draft' state, while * removing results in 'Published state'. */ function os_custom_preprocess_views_view_fields(&$vars) { foreach ($vars['fields'] as $name => &$field) { if ($name == 'sid' && $field->handler->table == 'workflow_node') { // Get complete workflow state. $state = workflow_get_state($field->raw); if ($state['state'] != t('Draft')) { // Hide workflow if not in draft mode. unset($vars['fields'][$name]); } else { // Add workflow-{state} class. $field->class .= ' workflow-' . strtolower($state['state']); // Replace default 'Worfklow name: workflow state' formatting with // only the workflow state. $field->content = $state['state']; } } } }
Then, by borrowing some CSS that has been hanging around in the Zen theme for the core workflow, the content in draft state is easily brought to the attention of those working on the site:
The same is then done for nodes by a different preprocess function,
/** * Preprocess function for template_preprocess_node(). */ function os_custom_preprocess_node(&$vars) { $state = workflow_get_state($vars['node']->_workflow); if ($state['state'] == t('Draft')) { $workflow_class = 'node-workflow-' . strtolower($state['state']); // Prepend content with workflow state information. $vars['content'] = '<div class="' . $workflow_class . '">' . $state['state'] . '</div>' . "\n\n" . $vars['content']; } }
and and using the aforementioned, and slightly-modified, Zen CSS:
.node-workflow-draft, .workflow-draft, .node-unpublished div.unpublished, /* The word "Unpublished" displayed beneath the content. */ .comment-unpublished div.unpublished { height: 0; overflow: visible; color: #f77; font-size: 75px; line-height: 1; font-family: Impact, "Arial Narrow", Helvetica, sans-serif; font-weight: bold; text-transform: uppercase; text-align: center; word-wrap: break-word; /* A very nice CSS3 property */ } .workflow-draft { font-size: 42px; /* Smaller font for workflow display within views. */ }
the result is again obvious to people staging content:

The Linux Foundation serves a worldwide community of developers and users. Their stated mission is to Promote, Protect, and Standardize the Linux ecosystem by providing unified resources and services needed for open source to successfully compete with closed platforms. More than ever, LinuxFoundation.org helps further that mission with web-based tools and vital user-generated content.
Story
The Linux Foundation and OpenSourcery began working together in the summer of 2008, with the goal of transforming the Linux Foundation's corporate site to reflect the vibrant community it supports. Their existing site was informative and, in some ways, well loved. Long-time users knew how to access the information they needed and were familiar with the site's architecture. But in the final analysis their site architecture was not tenable. The Foundation had accumulated a number of web properties, including the Linux OpenPrinting site and a number of Programs sub-domains, which had been cobbled together to serve immediate needs. Moving forward, the combined properties needed to coalesce under a single, forward-thinking architecture. Enter OpenSourcery.
Developing a new Linux Foundation site presented several challenges, which can largely be grouped into two buckets: 1) unifying deep and diverse content into a well-architected site and 2) developing a clean interface that doesn't overwhelm visitors with options.
Solving the primary challenge required open communication between OpenSourcery and the Linux Foundation. We had to ask the right questions, consider the variety of use cases, and design the site accordingly. The discovery process is well suited to our Agile development process, which you can read about in more detail below.
Perhaps the most creative solutions employed during the development have to do with the second challenge: Linux Foundation's user interface. We realized that visitors could easily get overwhelmed by an overabundance of tabs and conflicting images. On the other hand, we wanted to avoid Flash and non-accessible JavaScript so the site could remain accessible and easily indexed by search engines. Jonathan Hedstrom solved both of these problems with a combination of contributed and custom modules, details of which can be found below.
The result is an attractive site that makes it easy for each user to quickly access what she needs, without sacrificing the Linux Foundation's goals of completeness and accessibility. OpenSourcery is proud to have collaborated with such a talented team, and we look forward to supporting the Linux Foundation's mission in the future.
Development Process
OpenSourcery had assembled a Linux Foundation team during the development of a previous project: the Linux Foundation Video Site. From the start of their corporate site refactor, we were familiar with the Linux Foundation's project team and goals.
We employed our Agile development process from the project's beginning. We maintained close contact throughout, iterated in short bursts, and frequently pushed code so the Linux Foundation would know where their project stood at all times. Our process also allowed them to guide development by prioritizing tasks, which kept the complex project on budget and on time.
Technical Details
Tagged as: custom theme development, Drupal, Drupal 6, panels, Views
I am writing an application where I have a block whose data is coming from a 3rd-party service. Since querying that service can take some time, I am caching the data locally, so pages load very quickly. However, in the interest of keeping the data more up-to-date than the hourly updates that happen during cron runs, I had the idea to have the client browser periodically poll for updated data. Fortunately javascript (and Drupal's jQuery implementation) makes it fairly easy to set up this periodic polling from the client side.
Tagged as: Drupal, Drupal 6, javascript, jQuery
Drupal's core contact module allows users of a site to contact one another via email. Unfortunately, it also reveals the sender's email address. Normally, this is seen as fine behavior because the only person's email address that is at stake is the one taking the action. However, for a recent site, this violated the site's stated COPPA compliance, so we needed to alter the From and Reply-To headers sent with the email. As it turns out, this is quite an easy thing to do thanks to hook_mail_alter().
/** * Implementation of hook_mail_alter(). */ function somemodulename_mail_alter(&$message) { if ($message['id'] == 'contact_user_mail') { // Set 'From' address to a no-reply rather than leaking student's email address. $mail = 'NO-REPLY@example.com'; $message['from'] = $mail; foreach (array('Reply-To', 'From') as $header) { $message['headers'][$header] = $mail; } } }
On a recent project, there was a need to exactly mimic a set of paper forms students take out into the field to collect water quality and macro-invertebrate data on. Unfortunately, the person who designed these paper forms did not model them off of the default Drupal form appearance and layout.
Tagged as: CCK forms, Drupal, Drupal 6, Drupal theme layer

We recently remade our company newsletter from a simple plain text affair to a simple, but elegant HTML newsletter. The first attempt at this utilized a combination of the Simplenews and Mimemail modules. This, however, didn't work as expected, so we went with a partially custom solution.
The Simplenews module is still at the heart of our new newsletter, but a few custom tweaks (no hacking of the original module, of course) were added to make things simpler on Thomas when he creates these.
The first addition, was a preview button to view the newsletter using the themed HTML template (the one used to actually mail the newsletter, rather than the node template for viewing on the site). This was a simple matter of altering the newsletter node form, and adding a callback to compile the preview.
Tagged as: Drupal, Drupal 6, HTML email, Simplenews