Notes from today’s Drupal hacking

  • Avatar selection/upload during registration: Oddly enough, avatar_selection doesn’t handle this. You need the reg_with_pic module, too.
  • Shared and per-site file directories: We’re segregating uploaded files by microsite, but we want to share some files as well. Hacking the shared path into is a kludge, but it works. Like so:
    ---    (revision 1046)
    +++    (revision 1589)
    @@ -66,6 +66,11 @@
    else if (file_check_location($file_path . '/' . $dest, $file_path)) {
    return $file_path . '/' . $dest;
    +  // Not found, check by going up one more
    +  else if (file_check_location($file_path . '/' . $dest, $file_path . '/../')) {
    +    return $file_path  . '/' . $dest;
    +  }
    // File not found.
    return FALSE;
  • Group names with signed-up events: signup.module doesn’t make it easy to theme the list of events, so I created my own block based on the code in signup_list_user_signups. To determine the possible group a node came from, I check for the intersection between $node->og_groups and the array keys of $user->og_groups.
  • Fixed panes: I couldn’t figure out a way to set a block as fixed in Panels 2, but a workaround is to define a custom layout that includes the block in the right place. Here’s an example:
     * Implements hook_panels_layouts
    function mymodule_panels_layouts() {
      $items['my_panel'] = array(
        'title'  => t('My Panel Layout'),
        'icon'   => 'my_panel.png',
        'theme'  => 'my_panel',
        'css'    => 'my_panel.css',
        'panels' => array(
          'top' => t('Top'),
          'left' => t('Left'),
          'right' => t('Right'),
      return $items
     * This function uses heredoc notation to make it easier to convert
     * to a template.
    function theme_my_panel($id, $content) {
      if ($id) {
        $idstr = " id='$id'"
      // Pull in the Organic Groups - 0 block.
      $group_details = og_block('view', 0)
      $group_block = < <<EOT
      <div class="block block-og" id="block-og-0">               
        <h2 class="title">$group_details[subject]</h2>
        <div class="content">
      $output = < <<EOT
    <div class="panel-2col-stacked clear-block panel-display" $idstr>
      <div class="panel-col-top panel-panel">
        <div class="inside">$content[top]</div>
        <div class="center-wrapper">
        <div class="panel-col-first panel-panel">
        <div class="inside">
        <div class="panel-col-last panel-panel">
        <div class="inside">
      <div class="panel-col-bottom panel-panel">
        <div class="inside">$content[bottom]</div>
      return $output;

    To limit the choices to just that layout, put this in your installation profile:

      $allowed_layouts = new panels_allowed_layouts();
      $allowed_layouts->allow_new = TRUE;
      $allowed_layouts->module_name = 'panels_common';
      $allowed_layouts->allowed_layout_settings = array(
        'threecol_33_34_33_stacked' => 0,
        'twocol' => 0,
        'flexible' => 0,
        'threecol_25_50_25' => 0,
        'threecol_25_50_25_stacked' => 0,
        'onecol' => 0,
        'threecol_33_34_33' => 0,
        'twocol_stacked' => 0,
        'twocol_bricks' => 0,
        'my_panel' => 1
  • Organic Groups RSS feed: There’s an og_aggregator module, although it doesn’t quite fit in neatly with everything else.
  • Organic Groups tag cloud: I was surprised to find that this wasn’t built in. I ended up defining my own block using a SQL query like this:
            if (($node = og_get_group_context()) && node_access('view', $node)) {
              $result = db_query(
                'SELECT COUNT(*) AS count, d.tid,, d.vid FROM {term_data} d
                 INNER JOIN {term_node} n ON (d.tid=n.tid)
                 INNER JOIN {og_ancestry} og ON (og.nid=n.nid)
                 WHERE og.group_nid=%d AND d.vid=0 GROUP BY d.tid,, d.vid ORDER BY count DESC', $node->nid);
              $steps = 6;
              $tags = tagadelic_build_weighted_tags($result, $steps);
              $tags = tagadelic_sort_tags($tags);
              $output = theme('og_tagadelic_weighted', $node, $tags);
              $block['content'] = $output;

    og_tagadelic_weighted was a custom theme function that constructed a link to a faceted_search using the og: and taxonomy: filters. I had to hack faceted_search, too. First I needed to enable the og filter, and then I needed to make taxonomy_facets.module recognize free tags (vid=0). Patch for taxonomy_facets.module:

    --- taxonomy_facets.module	(revision 1046)
    +++ taxonomy_facets.module	(revision 1582)
    @@ -147,6 +147,7 @@
           // and create facets from it.
           if ($found_text = search_query_extract($arg, 'taxonomy')) {
             $vocabularies = taxonomy_get_vocabularies();
    +        $vocabularies[0] = 1;
             // Extract separate facets
             $paths = explode(',', $found_text);
             foreach ($paths as $path_index => $tids) {

It’s a good thing I can find my way around sparsely-documented code with few or no examples… <laugh>

  • These examples and patches are great, Sacha. What’s your plan for giving back / integrating upstream?

    For example, I can tell you that dww, maintainer of signup, would welcome feedback / a patch that would “make it easy to theme the list of events” — probably a theme_ function of some kind.

    Keep up the good work, and thanks for sharing directly here.

  • thanks for those nice hacks/patches.

    Suggestion: it could be nice if you could add attachments with patches.