Blog

Tutorial: How to Group Fields in Views With a Div or Span Tag

This is a howto for wrapping a div around a few of your view fields (and not others). This is useful, for instance, for being able to group all one's content so that it floats left but does not float around an image.

EDIT: This technique is a good intro to views templates, however, an easier way exists which seems a little hackish, but would work for many use cases. Thanks to Sr. or Sra. Anonymous.

Just use one "Global:Custom" field with a single div tag in it. See screenshot. It will span from that element until the last field in the view row. You can insert another "Global:Custom" field which can be nested inside the previous. However, I do not see a way to use this to create two sibling field groupings, so this post is still useful for learning about views templating and will give you you complete control over your markup.

Carry on.

First, create a template for your view.

Create a template file in your theme directory with the same name as the views and paste the code from the level of specificity that you desire. For more information, read this introduction to views template files.

Here is the code from the stock Row Style Output:

<?php
// $Id: views-view-fields.tpl.php,v 1.6 2008/09/24 22:48:21 merlinofchaos Exp $
/**
 * @file views-view-fields.tpl.php
 * Default simple view template to all the fields as a row.
 *
 * - $view: The view in use.
 * - $fields: an array of $field objects. Each one contains:
 *   - $field->content: The output of the field.
 *   - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
 *   - $field->class: The safe class id to use.
 *   - $field->handler: The Views field handler object controlling this field. Do not use
 *     var_export to dump this object, as it can't handle the recursion.
 *   - $field->inline: Whether or not the field should be inline.
 *   - $field->inline_html: either div or span based on the above flag.
 *   - $field->separator: an optional separator that may appear before a field.
 * - $row: The raw result object from the query, with all data it fetched.
 *
 * @ingroup views_templates
 */
?>
<?php foreach ($fields as $id => $field): ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>
 
  <<?php print $field->inline_html;?> class="views-field-<?php print $field->class; ?>">
    <?php if ($field->label): ?>
      <label class="views-label-<?php print $field->class; ?>">
        <?php print $field->label; ?>:
      </label>
    <?php endif; ?>
      <?php
      // $field->element_type is either SPAN or DIV depending upon whether or not
      // the field is a 'block' element type or 'inline' element type.
      ?>
      <<?php print $field->element_type; ?> class="field-content"><?php print $field->content; ?></<?php print $field->element_type; ?>>
  </<?php print $field->inline_html;?>>
<?php endforeach; ?>

Now, what you'll eventually do is take the $id variable and print opening or closing tags based upon it's value. The $id variable represents the field that the view is currently printing.

So, right at the top, above the foreach(), insert a dpm statement so you can find the $id for your field. If you don't have the devel module enabled, install it or use a print_r statement instead.

<?php dpm(fields); ?>
<?php foreach ($fields as $id => $field): ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>
....

You'll see the names of your fields when you refresh the view. I want to group together the following fields:

$id are the names listed. So I will insert these two snippets of code:

  <?php if ($id == 'field_editors_value'): ?>
    </div>
  <?php endif; ?>

and

  <?php if ($id == title): ?>
    <div class="grouping_field">
  <?php endif; ?>

If you examine the code below you will see them in context.

<?php
// $Id: views-view-fields.tpl.php,v 1.6 2008/09/24 22:48:21 merlinofchaos Exp $
/**
 * @file views-view-fields.tpl.php
 * Default simple view template to all the fields as a row.
 *
 * - $view: The view in use.
 * - $fields: an array of $field objects. Each one contains:
 *   - $field->content: The output of the field.
 *   - $field->raw: The raw data for the field, if it exists. This is NOT output safe.
 *   - $field->class: The safe class id to use.
 *   - $field->handler: The Views field handler object controlling this field. Do not use
 *     var_export to dump this object, as it can't handle the recursion.
 *   - $field->inline: Whether or not the field should be inline.
 *   - $field->inline_html: either div or span based on the above flag.
 *   - $field->separator: an optional separator that may appear before a field.
 * - $row: The raw result object from the query, with all data it fetched.
 *
 * @ingroup views_templates
 */
?>
<?php dpm($fields);?>
<?php foreach ($fields as $id => $field): ?>
  <?php if ($id == title): ?>
    <div class="grouping_field">
  <?php endif; ?>
  <?php if (!empty($field->separator)): ?>
    <?php print $field->separator; ?>
  <?php endif; ?>
  <<?php print $field->inline_html;?> class="views-field-<?php print $field->class; ?>">
    <?php if ($field->label): ?>
      <label class="views-label-<?php print $field->class; ?>">
        <?php print $field->label; ?>:
      </label>
    <?php endif; ?>
      <?php
      // $field->element_type is either SPAN or DIV depending upon whether or not
      // the field is a 'block' element type or 'inline' element type.
      ?>
      <<?php print $field->element_type; ?> class="field-content"><?php print $field->content; ?></<?php print $field->element_type; ?>>
  </<?php print $field->inline_html;?>>
  <?php if ($id == 'field_editors_value'): ?>
    </div>
  <?php endif; ?>
<?php endforeach; ?>

Drupal 6.x + jQuery 1.4.2 = New Possibilities

Déja Augustine's picture

jQuery is the bread and butter of rapidly developing a highly-interactive websites, and Drupal has long made use of it, and indeed includes it as part of its core install.

There's only one catch... Drupal 6.x (the current stable version of Drupal) is still living in 2008, shipping with the antiquated jQuery 1.2.6. Over the intervening two years since the release of 1.2.6, there have been substantial additions and upgrades to the jQuery library, as well as several tools (such as the jQTouch library) that rely on those changes. As of the writing of this post, the current jQuery version is 1.4.2.

The jquery_update module has done a fantastic job of letting users upgrade the version of jQuery used by Drupal, but unfortunately the jquery_update module got stuck at 1.3.2.

The culprit: a bug in Drupal's core function drupal_to_js(). This function exports a PHP variable into the JS space. The issue is that it preforms some text modification to convert characters such as ampersands, angle-brackets, and line endings into their escaped unicode equivalents. Unfortunately, it does not do a very complete job and as a result, many issues arise when jQuery is upgraded to 1.4.2.

As is often the case, the Drupal community stepped up and created a patch that fixes the issue (for your convenience, I've attached this patch below). Unfortunately, after more than six weeks, there has been little-to-no movement to include the patch in future releases of Drupal 6.x. This leaves us with the distasteful, but worthwhile, task of repatching the core whenever a new core update is released.

Warning: if you are not comfortable working with PHP, I'd advise against patching as it can occasionally call for hand-editing. As always BACKUP DRUPAL before you upgrade or patch anything.

There is excellent documentation on applying patches over at drupal.org (and a really good babysteps patching guide as well), so I won't go through it all again here. One very handy technique I will share, though, is to create a folder in your sites folder (call it patches, or hacks, or something along those lines) to store your .patch files in so that the .patch files aren't lost when you upgrade your core, so you can easily re-apply them.

Once the bugfix has been applied to the Drupal 6 core, make sure that your jquery_update module is up-to-date and apply this patch to coax jquery_update to use jQuery 1.4.2. This patch is also included in the package attached to this post.

With both patches applied, enable jquery_update and bask in the glory that is jQuery 1.4.2, and welcome Drupal 6.x to 2010!

Patch: drupal_to_js() bug fix - http://drupal.org/node/479368#comment-3198886
Patch: jquery_update to 1.4 - http://drupal.org/node/775924#comment-3274706

Shared Multisite Sign-on the Easy Way

Paul Venuti's picture

This weekend I discovered (quite by accident) a very simple way to enable shared sign-on across multiple Drupal sites running in a multisite configuration.

Suppose you have the following sites:

  • phones.com
  • htc.phones.com
  • iphone.phones.com
  • motorola.phones.com

The first requirement is that all the sites be running on the same domain. The examples above work — they're all subdomains of phones.com.

The second requirement is that all the sites share the same user tables. If all your sites are sharing one big database, you don't need to do anything, since all your tables are already shared. (This was my setup.) If some or all of your sites are using separate databases, though, use table prefixing to share the following tables among all your sites:

  • users
  • sessions
  • roles
  • authmap

If you use something like content_profile to store profile data, and you want to share that across sites, you'll need to share those tables, too.

So now you've got your users shared at the database level, but a person who logs in at htc.phones.com still won't stay logged in when they visit iphone.phones.com. That's because the 'host' parameter for the cookies on each site are still tied to their individual domains: htc.phones.com for htc.phones.com, iphone.phones.com for iphone.phones.com, and so on. As far as the browser is concerned, each site is entirely separate.

You can break the cookie barrier down pretty easily though (after all, it's just a cookie). Just add the following line to all of your 'settings.php' files:

$cookie_domain = '.phones.com';

The key is the leading period, which functions as a subdomain wildcard.

Drupal picks up on this and rewrites your cookies for you. Now, once you log in to any subdomain on phones.com, you'll be logged in to all the subdomains. Done.

Note that there are a few more requirements for cookie sharing than the ones I talked about. Most people will meet these requirements, but see Nate Haug's article on the subject for more information about the requirements, and for more on setting up table prefixing.

Echo Nest Remix API: The Next Level

Ethan's picture

EchoNest has basically taken the web API to a completely new level with their new Remix API.

The API allows not just the analysis of beats and musical characteristics that their basic API offered, it additionally allows coders to modify audio and video files based on the analysis information for programatic remixing.

To get a sense of the amazing results, check out these initial exploratory vids: http://musicmachinery.com/2009/06/21/wheres-the-pow/

More info: http://code.google.com/p/echo-nest-remix/

Does anyone know of any other multimedia API's that allow for the modification of audiovisual assets via API calls?
Any on your wishlist?

Personally, I'd love some good web-based speech to text and face recognition APIs.

(via O'Reilly Radar)

Block Visibility with Context and Zen

Paul Venuti's picture

Turns out that if you're using Context with a Zen 2.x-based subtheme, any block visibility rules you set up with Context get blown away by Zen. The reason is that both Context and Zen implement the `theme_blocks()` function, but Zen, being unaware of Context, clobbers all the work done by Context.

The solution is pretty simple: apply this patch to Zen. Note that you must be using at least Context 3.x for the patch to work; otherwise, you'll get a WSOD.

And for those who are interested, here's some background on the issue.