Drupal Module, Node Multi-Parenting
Nerd alert: If you don’t use or care about Drupal, feel free to ignore this.
Drupal is a popular PHP framework/CMS for constructing small to medium-scale websites, and it has an extremely extensive (and complicated) set of hooks available in a modular architecture. One of the framework-y things that Drupal does is to create and maintain a one-to-one relationship between URLs and content. If you only maintain sites where each section is completely different, and content can be segregated cleanly, this isn’t an issue. However, this can’t always be done. In some cases, it’s a requirement to have content duplicated in multiple sections, and to maintain breadcrumbs, menu locations, etc – in general, contextual stability.
One of my friends had such a project, and he asked me if I’d be willing to work on a module that would fit into Drupal’s framework and allow for a single piece of content to be published to multiple places on a site. The first thing I did was to look around for an existing module that might fit his client’s needs. Node aliases were already part of the drupal core semantics, but those were more of a URL alias. Searching through the modules section, I found something pretty close – the Node Symlinks module from Vojtěch Kusý. Unfortunately, it was basically a proof of concept with several major flaws, and Vojta, the maintainer, was busy completing his university degree. It was a good start, though, so I began taking a look at what this module did. In order to meet deadlines, I ended up writing a significant portion of new code, redoing the user interface, and rewriting a large portion of old code as well.
It’s never straightforward whether to fork or to patch and existing open source project, so i’ve basically forked the module at this point. I’m willing to try and re-merge the work into Node Symlinks, but the user interface and operation is quite different now, and the maintainer is busy, so i’m not sure how that will work. I’m going to hold off attempting to do anything on drupal.org’s module repository until we figure that out. Anyway, for the time being, i’m just offering a download of this code from my blog until we get it sorted out. This works with Drupal 6.12, requires ahah_helper, and the following patches applied: #435826 on ahah_helper, and #336517 on teaser.js. Update: It looks like some of the AHAH / AHAH helper stuff is breaking the Delete button on the node edit form, so i’ve made a quick and dirty workaround update to help with that. The link has been updated below.
http://getluky.net/downloads/nodemultiparent-6.X-1.3-dev.tar.gz
How it works
Node Multi-Parenting uses a similar approach to Node Symlinks to generate alternative links to content nodes that maintain contextual state within the menu system. It does this by inserting and maintaining menu_links entries within Drupal manually. Instead of /node/node_id, these links look like /node/node_id/dup/menu_link_id, and the menu hook is registered to handle these. However, since this is essentially denormalized data within Drupal, it gets wiped out every time a module is enabled or disabled, and is relatively unstable within the architecture. Thus, i’ve added in a new table to the drupal schema in which serialized data is stored and maintained so that re-enabling the module can re-populate the menu_links table.
The UI has been modified to change language to be more intuitive – instead of “Symlinks”, which nobody outside of UNIX programmers will know, i’ve changed to “Locations”. Users of drupal can then think about these as alternative locations in which to show content.
There’s an administrative menu now available to show all of these alternative locations on one page. It doesn’t have pagination, so it’ll be slightly cumbersome if you put this to heavy, heavy use.
The node edit form is modified to add a collapsible menu which now works via AHAH and ahah_helper, instead of multi-step forms in the original Node Symlinks (it should degrade gracefully if JS is not enabled, though). This was kind of challenging to get working, but it seems to do fine now. I’ve edited the instructions somewhat for clarity. It should auto-expand and collapse depending on whether there are any locations currently available for that node.
As in the original Node Symlinks, a META ROBOTS FOLLOW, NOINDEX tag has been added to the header on each of these duplicate pages. This should avoid the #1 objection to such duplicated content schemes, which is the potential duplicate content penalty that google can levy if you don’t include specific robots instructions to avoid it.
Controversy and a Caveat
If you use this module, you should be aware of two things:
- There are those within the Drupal community that are vehemently opposed to doing this, because of the philosophical decision to make content uniquely addressable via one URL. However, this does not permit multiple contexts as was a specific requirement of my friend’s client. I am sure that this blog post will catch some flak about it. I’ve done my best to try and make this work for Drupal 6.X without getting in the way, and without relying too heavily on the denormalized menu_links table. In commercial programming, you know the rules so that you can break them safely, so please be aware that the use of this module does diverge from the Drupal philosophy.
- Because this goes a bit against the grain, I can offer no guarantees that this module will work in future versions of drupal, or that some upgrades may change the functionality of Drupal in ways that might break this module. I believe that since data is stored in a separate table, you should always be able to program or hire a programmer to get you out of any binds, but be forewarned that this module should be considered slightly fragile in upgrade scenarios, especially as I haven’t ported or tested it on 7.X
- I performed this work under sponsorship, and although i’m happy to contribute back to the Drupal community, I don’t have the time to really dedicate a huge chunk of time to answering questions or maintaining this on a volunteer basis.
- I can’t count. Sorry!
With that out of the way, give it a shot and let me know what you think. Feedback on code quality or approach (especially the AHAH stuff, which was kind of mind-bending) is appreciated.
