A Modest Proposal: Node Attributes

(Submitted Sun, 2007-01-28 20:16)

Here's a wacky idea - arbitrary attributes that can be assigned on an individual node basis.

Even wackier - a brokerage system to allow these attributes to be globally registered.

What do I mean, and what's the point?

Right now, developers do all sorts of strange things to coax desired behaviour out of Drupal. Consider the case of featured content. You want certain types of content to be "featured", and you want to perform certain types of actions for featured content that you don't want to perform for other content. Perhaps a featured icon graphic next to the title in a teaser view.

There are countless ways that a scenario like this gets tackled, three in particular which are most common.

The cloned node type:

Ok, so you create a new node type: Featured Story. It has a title and body, just like a story node. But we know it is different than a story or a page. We gave the node type a different name after all, and we will treat it differently, even if it is identical in every other way with a story or a page node.

In Drupal 4.7.x you do this with CCK, in Drupal 5 you can do it directly through the core installation. Great. So now at the theme level, you can add your featured icon image on nodes that match node->type 'featured article'.

It works well, and if you've done any amount of development with Drupal, you've probably used similar techniques. The support forums are full of people explaining to newcomers that it really isn't as tricky as it sounds. But it can quickly get unwieldly.

What if you have a node type of Review, and it occurs to you that some reviews should be featured as well?

Well, you could create another new node type - Featured Review. And what if down the road you realize that you need to feature some recipes? Well, another new node type Featured Recipe that is identical to your Recipe node type.

You go on and theme these nodes at the theme level, and on it goes. Everything that we might want to designate as "featured", we create a new node type for and a new template. Or we find a higher level at which to template and add in some cursory logic such as

if (teaser == 1 && (node->type == "Featured_Article" || node->type == "Featured Review" || node-> == "Featured_Recipe")) {
  // code to add featured image next to title

But every time we think of a new type of content that might need to be featured, we are in the position of creating a cloned node type, tracking down our theme logic, and adding in a conditional to account for it. We could get very clever, of course, and parse the node->type string for the word "Featured" and if found, then add our image. That way we don't need to anticipate each node type in advance, or alter our theme logic, we simply create our cloned node type and off we go.

But it's still a pretty messy way to handle things. What are we really trying to do? We are simply trying to designate -- to communicate -- that this content is featured in a way that other content is not. The actual nodes are hardly different; in fact they are identical in everything but name. So we move on to a more sophisticated approach ....

CCK Fields:

We're all familiar with this. Rather than that nasty business of creating cloned node types, we'll add a CCK field to any of our node types that we might want to feature called "Featured" with a boolean value. To feature an article, we edit our node and set the "Featured" CCK field to true. At the theme level, we check if the node has a "Featured" CCK field that is set to true, and if so, we add our image.

Much nicer.

One of the drawbacks to this approach is that we can't feature "story" or "page" nodes in 4.7.x, because we can not add CCK fields to core defined node types. However, Drupal 5 does allow us to do so.

This approach works very well, except that we still must anticipate in advance each type of node that we may sometime in the future want to feature, create those node types with CCK (in 4.7), and add a CCK field to all of them. And what if there are other attributes we might want to arbitrarily associate with nodes? Say, "perishable" or "votable" or "private" or "commentable". We quickly end up in a scenario where we have to add a monster amount of CCK fields to each type of node and we greatly increase our workflow when creating content by having to iterate through each one and select the appropriate value.

Ah, but there's another approach.

Meta Taxonomy:

Glorious, flexible taxonomy. It can be used for so much. We can bend in to our will to perform all sorts of interesting functions that it was never designed for. (No wonder newbies find it so difficult to come to grips with -- for seemingly every conceivable development hurdle, there is a solution or three based on taxonomy)

Quick and dirty: we create a vocabulary called something appropriately vague like "Meta". To this vocabulary we add any of the attributes for which we might want to flag content as terms, without having to anticipate in advance what content that might be, or even what type of nodes that may be. So we add the terms "featured", "perishable", "votable", "allows_comments", and whatever else we may think of.

At the theme level, we make sure to not output any taxonomy terms that belong to our vocabulary "meta", but we act on the presence of those terms in appropriate ways. A story node has the term "featured" associated with it? Add the icon. It also has the term "votable" associated with it? Add a voting widget. What's this, it also has the "perishable" term associated with it? Unpublish it once it drops off the front page.

This is our cleanest solution so far, and taxonomy is well suited for it. It allows us to arbitrarily flag content and to act on it in appropriate ways. The trouble is, it simply isn't what taxonomy was designed to do. And we have to do some hacking to take that into account, such as suppressing some taxonomy output (our meta tags) while preserving and displaying others (the actual taxonomy tags used for categorization ... which is what taxonomy, ultimately, is about).

A Better Way?

So the question is: why don't we handle this explicitly through a mechanism by which we allow nodes to be flagged with appropriate attributes?

It would look and feel a lot like a streamlined, unhierarchical taxonomy -- but it would be decoupled from taxonomy proper. It could allow modules to register certain attributes that the module would then take into account.

Consider the vast amount of various voting and ranking modules. The responsible ones make use of Voting API, which is great. Now some automatically add a widget to every node. Some allow you to choose which types of nodes a voting widget will show up on. Some allow fine-grained control by which you can specify which individual nodes will or will not have a widget. Some are meant to be called explicitly at the theme level. Each has a different mechanism, and a different interface for interacting with that mechanism.

What if Voting API could simply register the attribute "VotingAPI: votable" at the time of installation. The various voting/ranking modules could then make use of attribute -- if a node has "votable" set, show the widget. You could swap in a different voting module, and it would perform consistantly.

A developer could add his or her own attribute terms through a taxonomy like admin page, and act on those accordingly.

I recognize that so far, I have been speaking of attributes, but talking more of something resembling a simple flag. Content is either tagged or not tagged. Attributes proper might look more like key/value pairs. In this way, content could still easily be flagged ("votable" == "TRUE") or have more complex behaviour ("perishable" == 2008-01-01) or ("allows_comments" == "anonymous,authenticated"). Futhermore, attributes could be integrated with Views and Actions, etc..

I'm interested in hearing feedback on this. Am I out to lunch? Perhaps some time off from Drupal development has left me not thinking in the Drupal Way. Maybe this has been discussed to death in the early days and dismissed for good reason, although I didn't have too much luck digging up conversation of the same in the drupal.org forums.

I'd see this starting its life, at least, as a contrib module and would be willing to do the grunt work if there is any interest.

Submitted by Jeff Eaton (not verified) on Sun, 2007-01-28 22:04.

This is what nodeapi is designed for, essentially. Am I missing something?

Submitted by anuity (not verified) on Tue, 2009-03-17 04:44.

Nope. It works just fine.

Submitted by drawk on Sun, 2007-01-28 22:41.

No, you're absolutely right.

Really on the module level this is already accomplished via nodeapi -- the upload module for example adding the 'Attachments' dialog, which is like attributes on steroids.

I guess what I'm thinking of is something at a higher level for those using Drupal as a CMS, rather than those coding for Drupal. So that "registered attributes" (the terminology needs to be clearer, granted) would be as straightforward to manage and assign as terms in a taxonomy. The underlying mechanism would certainly be handled primarily via nodeapi, but should be transparent to the user.

Essentially the functionality of nodeapi brought into the backend admin interface for use by those who aren't interested or don't have the skills to add code to a custom module. Presently, those who are just trying to assemble a website with Drupal tend to rely on methods like the ones I described above -- they aren't writing custom code that makes use of the apis, they are finding workarounds through the tools available to them in the admin section and theme hacks. There are good reasons why they do this -- they aren't developers, and aren't interested in Drupal internals.

You're completely right, I just suspect that we are thinking of different types of users.

It also provides incentive for those of us who are coding modules to build consensus around certain terms so that our modules can act on those in predictable ways. (The "votable" or "allows_voting" example)

Submitted by Crell (not verified) on Sun, 2007-01-28 23:27.

It sounds like there's two things here:

1) The Publishing Options. Right now there's a hard coded set: Promote, Sticky, Moderated, Published, etc. You want this to be an arbitrary list that you can add to and filter on programmatically and via the UI. Big +1 here.

2) Value-add modules. A lot of modules already have this sort of "Add stuff to", but they each implement their own method and UI for doing so. Event, Location, and OG come to mind. A shared API for that would be very nice.

#2 operates on node types. Option #1 operates on nodes, but via #2 on only nodes of selected types.

Yeah, this sounds like an API module of some sort, perhaps even something that could eventually end up in core if it's thin enough. It could also provide a common UI location for Event, OG, etc. on the node-configure form. "Enable the following value-adds for this node type: Event, Location, OG, Case Tracker".

Submitted by merlinofchaos (not verified) on Sun, 2007-01-28 23:31.

Two alternate solutions:

4) Use the workflow module. Workflow, in some ways, is nothing more than a flat taxonomy that 1) triggers changes in the node when you change the flags and 2) allows gating to control who can change the flags and when.

You can create a 'votable' workflow, default it to no, and let administrators flip the votable switch on.

The downside is that currently I think there's only one workflow per node, but last I checked it was on the TODO list to allow multiple workflows per node.

5) Views Bookmarks

This is a simple flagging system, and is occasionally used as exactly that. It can be used to let users bookmark nodes for various purposes, but it can also be set 'global' and simply flag nodes on or off.

Submitted by fago (not verified) on Wed, 2007-05-02 10:35.

regarding 4) I'm currently working on worklfow-ng (https://more.zites.net/node/3030), which will be capable of multiple workflows per node type.

It uses the states (API) module as "flagging system", what basically a simple attribute system for nodes & users - but it's designed for state machines so there is only one state per attribute possible, code (http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/fago/workflow-ng/)

Submitted by elv (not verified) on Sun, 2007-01-28 23:48.

I can already lots of use cases for these Node Attributes
Crell imagined user created Publishing Options, and it seems like a good way to implement them.
Another way could be the ability to set taxonomies as "private" or "public". Public ones would be displayed on the website's pages, private ones wouldn't be visible to end users. The advantage compared to Publishing Options is they would not be limited to boolean values.

Submitted by drafnor (not verified) on Mon, 2007-01-29 11:19.

Darren, can I suggest you have a look at the "relationship" module.

http://drupal.org/project/relationship

It seems its exactly what you are thinking of .. ceratinly if you are considering a new contrib module, check it out first... Rgds, Mark

Submitted by Crell (not verified) on Tue, 2007-01-30 03:53.

I haven't worked with workflow, but am familiar with it by reputation.

Wouldn't one option, then, be to generalize workflow so that it can be used as a shared mechanism for other modules?

Submitted by drawk on Tue, 2007-01-30 21:35.

Thanks all, I appreciate all the feedback so far.

Workflow is fairly on target with what I'm thinking ... I notice that fago has proposed (on one of the Drupal groups) breaking it up into discrete layers, one of which would be an API layer. That might be the best level at which workflow proper and simple attribute tags might share some code.

Relationship module does a lot of extra stuff, although it does list as one of the features "Pluggable ontologies - a module can create its own predicates and define the behaviour of what happens when a node has (or wants to have) a user-defined property. (much like Taxonomy)" which is exactly the sort of thing I'm proposing.

It's primary purpose though is to do all the other relationships-between-nodes stuff, that I think it might still lead to the same types of support problems -- trying to explain "I know that you don't need relationships, but you can install the module and just use this one little part of it by doing such and such". A lightweight, direct approach seems more sensible and easier to come to grips with for average users.

It does seem like there is enough commonality though that all three and others could do well to work off of a shared, general API for these types of functions. In fact, if it were general enough, it would make sense for taxonomy itself to work off as well, but being in core that makes it more difficult to try to factor this stuff out of the taxonomy.module.

Submitted by Benjamin Melançon (not verified) on Sun, 2007-08-05 17:50.

Well, taxonomy is in need of a little refactoring to let people display different taxonomies differently (or not at all) without having to do fairly involved work at the theme level.

Given that, however, and options for taxonomy checkbox or other displays on the administrative side, and an option to have any taxonomy add a value to class="node ..." on the display side so theming could be done with CSS alone, wouldn't it be better to do this through taxonomy-- and have other modules let taxonomy do this part, rather than coming up with a new API?

That's just my thoughts, and I'm coming from a rather taxonomy-centric viewpoint, so let me stress that I agree that anything done well in the direction you talk about would be welcome.

Submitted by Siladitya (not verified) on Mon, 2009-03-30 19:43.

I accept ur proposal.I read ur full article.,its so good.
full tilt

Submitted by Anonymous (not verified) on Tue, 2009-04-07 04:56.

Nice article, it helped me a lot so thanks.

Now it might be a good idea for you to install a spam module to catch out all those spammers above!

Submitted by Crystal (not verified) on Thu, 2009-04-16 20:20.

very usefull info at this post thanks!!

Affiliate Promotion

Submitted by online live roulette (not verified) on Thu, 2009-04-30 07:04.

That worked!So, I went back to my functions and the problem is accessing the node's attributes. Here's what is in the last part of the that shows my two attributes, team_name and team_no, are there:
team_name="Celestial_Voices" team_no="106" unselectable="on">
I don't understand the unselectable because clicking on the node does highlight it and cause the onClick event to fire.
Sorry, if this is basic Javascript, but how do I access these attributes? Are they child nodes for ? this.team_name or this.getAttribute('team_name') don't work. And should my function be defined as "goto()" or "goto(this)"? Sorry for my lack of Javascript expertise.

Submitted by Anonymous (not verified) on Thu, 2009-05-07 01:44.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.

Hosted By Dreamhost.com