Home

Lullabot

Lullabot Ideas

We know stuff. We empower you to know stuff too.

Drupal Module Development Deep Dive Week

London, UK
September 20-24, 2010

The Great Pretender: Making your data act like a field

Article by Jeff EatonJune 26, 2009 - 12:50pm

These days, almost every major Drupal site is using CCK, the module that lets you add custom fields to any content type. Among other things, CCK lets administrators rearrange a node type's contents using a simple drag and drop interface. In the past, this only worked for fields that CCK itself managed. If you worked with a custom module that altered a node's content, it was up to you to manage its position in the node content.

Now, though, it's possible for any module to tie into CCK's field management page to control the positioning of custom content. The key is hook_content_extra_fields(), and in this article we'll show you how to use it.

To demonstrate this technique, we'll fix something in Drupal that normally can't be re-ordered: the contextual links that go below each node, like "Add a comment" and "Bookmark this." While a Drupal theme can tweak the location of those links, there's no way to move them around from the administrative UI, and no easy way to position those links between two CCK fields.

The first step is to use hook_nodeapi() to create a new entry in the $node->content array that contains the rendered links. $node->content is a collection of data that's ultimately used to build the $content variable used by themes when printing a node. Data inside of $node->content can be easily tweaked and reordered by any module.

/**
* Implementation of hook_nodeapi().
*/
function link_mover_nodeapi(&$node, $op, $teaser, $page) {
  if ($op == 'view') {
    $links = module_invoke_all('link', 'node', $node, $teaser);
    drupal_alter('link', $links, $node);

    if (!empty($links)) {
      $output = theme('links', $links, array('class' => 'links inline'));
      $weight = content_extra_field_weight($node->type, 'links');

      $node->content['links'] = array(
        '#weight' => !empty($weight) ? $weight : 100,
        '#value' => $output,
      );
    }
  }
}

One of the key lines in that function is the call to content_extra_field_weight(). It's a utility function provided by the CCK module that returns the current 'weight' of a given item in relation to other parts of a node's content. If CCK isn't keeping track of the item we ask about, it will return a zero -- the 'default' weight of an item. If that happens, we substitute 100, so that the links will fall to the bottom of the node's content by default. How, though, can we get CCK to handle our new "links" element?

/**
* Implementation of hook_content_extra_fields.
*/
function link_mover_content_extra_fields() {
  $extras['links'] = array(
    'label' => t('Node links'),
    'description' => t('Links displayed when a node is viewed.'),
    'weight' => 100,
  );
  return $extras;
}

hook_content_extra_fields() is provided by CCK as well; it gives modules a chance to tell it what items they have that need to be considered when reordering a node's component fields. In it, we just need to return an array defining the name, description, and default weight of our item. Once we've done that, visiting the CCK 'Manage Fields' page for a given content type will give us the following:

Ta-da! CCK now lets us reorder the node links like any other field. There's only one piece left, though: removing the default $links variable so that the theme won't print it out in addition to our reorder-able version. That's easy enough, using hook_preprocess_node().

/**
* Implementation of hook_preprocess_node().
*/
function link_mover_preprocess_node(&$vars) {
  unset($vars['links']);
}

Once that's in place (and we've cleared the cache to ensure Drupal recognizes the new preprocess function), everything should work fine. Below is a screenshot of the final results after moving the 'Links' item above the node's body and other fields. I've also attached a zip file containing the sample code. Feel free to tweak it and experiment -- CCK is immensely popular, and tying into its configuration forms is a great way to make things easier for a site's administrators.

AttachmentSize
link_mover.zip1.11 KB

Comments

Larry Garfield (not verified) on June 26, 2009 - 1:22pm

Release?

So are you going to release link_mover as an actual module? You should. :-) It seems like a perfectly self-contained little utility, and a useful one to boot.

June 26, 2009 - 1:26pm Jeff Eaton

Possibly...

...But then I'd also have to support it! ;-) In all seriousness, that was my plan initially, but I realized that it was only a few dozen lines long and might make a more interesting example article. Perhaps a 'fleshed out' version that can control more of the default node variables like 'Submitted by' would make an interesting release...

agentrickard (not verified) on June 26, 2009 - 1:36pm

Sounds like a nice project

Sounds like a nice project to hand to an eager developer who wants to get more involved with Drupal.

Maybe the next time someone bugs you for a feature in IRC, you can ask them to inherit and release the code.

/me is _not_ volunteering.

Anonymous (not verified) on June 26, 2009 - 1:38pm

hook_preprocess_node

Thanks for this very useful Just one question: What's hook_preprocess_node ? I can't find it on the drupal API. Did you mean template_preprocess_node? Or is that hook implemented by a contrib module?

June 26, 2009 - 1:42pm Jeff Eaton

hook_preprocess_node()

template_preprocess_node() is very close -- it's the default implementation of hook_preprocess_node(). Basically, any time Drupal is about to use a tpl.php file to output some HTML, it calls 'preprocess' hooks for that template to allow other modules to get data ready. Usually this means sanitizing data for safe printing, formatting things like the 'Submitted by' line, and so on. It also, though, lets modules (like this one) change or remove variables that would otherwise be present in the tpl.php file. In this case, we're nuking the $links variable that node.tpl.php normally spits out.

Wim Mostrey (not verified) on June 26, 2009 - 3:48pm

Awesome!

I was doing this manually two years ago, but this integrated solution is awesome!

Rob Loach (not verified) on June 26, 2009 - 4:22pm

Yay!

Definitely CCK core worthy!

Tom Geller (not verified) on June 27, 2009 - 12:30am

How about moving the Body? Location?

If I remember correctly, neither the Body nor the Location form (via Location module) can be moved. Could this trick be applied to make those items movable?

And could it all be packaged up into a module so non-coders like me have a shot at it? :)

Cheers,

--Tom

Dave Reid (not verified) on June 27, 2009 - 4:25am

The YAEM

The YAEM (Yet-another-Eaton-module) is now available at http://drupal.org/project/eldorado_superfly

Drupal Development Services (not verified) on June 27, 2009 - 5:54am

I came across this site and

I came across this site and it was extremely helpful!really interesting and well written article.

Benjamin Melançon (not verified) on June 27, 2009 - 8:46pm

Great tutorial

Eldorado Superfly is a module that takes control of the "Submitted by..." text, node links, user pictures, and comments. It moves them to $node->content, where they can be re-ordered on CCK's Manage Fields tab. However, this means they are no longer under control of the theme. Whether this is a good thing or a bad thing is a question best debated late at night during Drupalcon.

Sign me up for the "Debate Eldorado Superfly" session, some hotel, Paris, 2:30 a.m...

Sean (not verified) on June 28, 2009 - 8:59pm

Very cool :) LOL at the

Very cool :) LOL at the name, good to see it describes the module accurately.

Wonder if it'd be possible to make each individual Node Link movable so you could move "add new comment" to the top while keeping "Read more" at the bottom.

- Sean

Stephen (not verified) on June 29, 2009 - 7:17am

Thanks for the details

Nice little module for those that need this control and have never understood why we never had it.

Thanks for explaining the code in the module -- a great help to budding module developers as we can see just how simple a powerful module can be.

Steve (not verified) on June 30, 2009 - 10:14pm

Anyone know how to use this without editing every module?

Well this helps me get a step closer to fix the order of fields that are on my node edit pages.

I'm wondering if anyone has yet to figure out how to implement this without going through every module that one is using that doesn't already make use of this hook.

Seems like there should be a way to take an array of fields and fieldsets that are being used for given node and add them in to the CCK manage fields.

If anyone has any ideas on doing this, I would really appreciate it!

Thanks in advance!
Steve

Anonymous (not verified) on September 15, 2009 - 2:58am

Display Part

Any way for the CCK display settings to work on the 'links' so we would be able to disable the links for certain types of post?

Nancy Wichmann (not verified) on September 15, 2009 - 5:27pm

Fabulous!

Fabulous! But now that CCK knows about the fields, shouldn't Views be seeing them? How about other modules, such as Node Export?

indytechcook (not verified) on September 16, 2009 - 9:41am

Interface Module

Have you seen the interface module? I haven't tried these two together. I know the interface module works for cck fields.

http://drupal.org/project/interface

About this 'bot

Jeff Eaton

Jeff Eaton is a long-time web developer. He's been designing, administering, and implementing web projects since he pieced together his first HTML file in 1996. He's built ecommerce sites for florists, helped implement enterprise web systems for multinational corporations, and juggled web architectures from legacy Perl to ASP.Net. (With some Windows desktop development thrown in for good measure...) Yes...

more

Recent

Drupal Voices 160: Moshe Weitzman on Page Rendering in Drupal 7

Podcast 9.02.2010

Drupal Voices 159: John Albin Wilkins on Drupal 7 Theming

Podcast 9.01.2010

Drupal Voices 158: Emma Jane Hogbin on PHP for Designers

Podcast 8.31.2010

Command Line Basics: More Editing with Vi/Vim

Video 8.31.2010

Lullabot's Back to School Sale

Blog 8.30.2010

Popular

Drupal Voices 160: Moshe Weitzman on Page Rendering in Drupal 7

Podcast 9.02.2010

Photo galleries with Views Attach

Article 6.01.2009

Drupal Voices 159: John Albin Wilkins on Drupal 7 Theming

Podcast 9.01.2010

Drupal Voices 158: Emma Jane Hogbin on PHP for Designers

Podcast 8.31.2010

Assembling Pages with Drupal

Article 7.17.2010
 
  • Home
  • Services
  • Events
  • Ideas
  • Store

Connect the Bots:

Twitter Facebook YouTube blip.tv All Posts Newsletter
  • Ideas
  • Blog
  • Podcasts
  • Videos
  • About
  • Contact
  • Jobs
  • Services
    • Training
  • Events
    • Training Workshops
    • Other Events
    • Conferences
    • Calendar
  • Products
    • Videos
    • Books
    • Swag
  • Ideas
    • Blog
    • Podcast
    • Videos
  • About
    • Philosophy
    • Team
    • Presskit
  • Contact
    • General
    • Work Inquiries
    • Mailing List