Notes from today’s Drupal hacking

| drupal
  • 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 file.inc is a kludge, but it works. Like so:
    --- file.inc    (revision 1046)
    +++ file.inc    (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">
        $group_details[content]
        </div>
        
    EOT
      $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>
        <div class="center-wrapper">
        <div class="panel-col-first panel-panel">
        <div class="inside">
        $content[left]
        </div>
        </div>
        <div class="panel-col-last panel-panel">
        <div class="inside">
        $group_block
        $content[right]
        </div>
        </div>
      </div>
      <div class="panel-col-bottom panel-panel">
        <div class="inside">$content[bottom]</div>
      </div>
    EOT
      return $output;
    }
    

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

      panels_load_include('common');
      $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
      );
      $allowed_layouts->api_save();
    
  • 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.name, 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.name, 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>

You can comment with Disqus or you can e-mail me at sacha@sachachua.com.