Jonathan Hedstrom's blog

  • DrupalCon San Francisco, departing thoughts

    Apr 23, 2010

    I have just returned from DrupalCon San Francisco 2010, the largest DrupalCon ever. With over 3000 attending, and $72,000 worth of coffee consumed, it was a very lively event. Thanks to the awesome work of those organizing, nearly all of the sessions now have high quality video available on the DrupalCon site, and on Archive.org. Below are the sessions that really left an impression on me regarding the future direction of Drupal.

    Advanced Drush

    While there is no video for this as of this writing, the highlight here was the sudo drush make-me-a-sandwich moment (as well as the Drush core-cli command).
    Drush: make-me-a-sandwich

    The Heart of Open Atrium: Context, PURL and Spaces

    While we've been using context on most projects for quite some time, the work presented here around the spaces presets has me itching to try integrating them into some upcoming projects.

    Page render drill down in Drupal 7

    The page rendering system in Drupal 7 waits much later in the process to transform structured data into the relevant output format (which is typically HTML). Practically speaking, what this allows for is hook_page_alter, which has access to the contents of the entire page, in a structured array. Two highlights:

    • The block module will no longer be a required module in Drupal 7. Rather, it is simply an optional UI for placing blocks in the page. This means that the Context module in Drupal 7 won't have to implement weird workarounds to steal block placement from the block module (and as such, should work seamlessly with the i18n module).
    • Instead of only having to caching options (page and block level), any part of the page can be cached. Furthermore, by using the query string and qrguments as the cache key, these caching mechanisms can work with content that is under access control.

    PubSubHubbub to the rescue-- Real-time feeds and the future of social networks

    This talk wasn't specific to Drupal (yet anyway), but rather, provides a sort of roadmap to the future of Drupal and the social web. By combining 4 rather new protocols (PubSubHubbub, WebFinger, ActivityStreams and Salmon), Brett Slatkin of Google walks through the potential for realtime feeds being used to contect people like never before.

    It would be very powerful if any Drupal site out there were capable of sharing, in real time, at the level Brett outlines in this talk. The Feeds module is already capable of consuming PubSubHubbub, and support for ActivityStreams have a little momentum. Salmon and WebFinger, as well as publishing to hubs for PubSubHubbub are the pieces that need to be filled in.

    Drupal 7 and the State of Drupal

    At Dries' keynote, he showed a best case scenario (June 2010), a worst case scenario (October 2010), and an ideal scenario (lock the 3000 attendees in until it was released at the conference) for the Drupal 7 release.

    While we already missed the ideal scenario, the progress made on critical bugs at the conference has the community working at a velocity that should come in closer to the best case scenario. Over the course of the week, thanks to the awesome gatherings at the chx coder lounge, the number of critical bugs dropped from 114 to 94 as of this writing.

  • Roll your own context conditions

    Oct 07, 2009

    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.

  • Simple usability enhancements for a site workflow

    Jul 27, 2009

    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.

    Views edit screen showing workflow current state field

    Workflow w/o enhancements

    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:

    Workflow with CSS enhancements

    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:

    Individual node page with workflow enhancements