Voting starts in March for the Drupal Association Board election.
In Drupal 5, we took the first steps toward building nodes the way we build forms -- structured arrays with useful meta-data, rendered to HTML as needed. The work that made it into that version was only a first step, though, and there are still major weaknesses in our current system that need to be resolved. Webchick's epic signatures patch (http://drupal.org/node/132446) is being held up by one of these weaknesses, for example, and crufty bits of duplicated code still litter Drupal core in places where the 5.0 system wasn't flexible enough to deal with various rendering scenerios. (Print-friendly versions and RSS feed generation are two glaring examples).
- We build portions of the node as a structured array, but immediately collapse it to text -- the structural information is lost to themers and template designers.
- Our node rendering workflow is still not flexible enough to remove hard-coded calls to comment.module and ugly functions like node_show(), stymieing anyone who wants to display comments in a nonstandard style.
- Themers who want to print out small portions of a node, or 'reshuffle' the layout, go back to square one, printing out raw properties from the node obejct and taking on the burden of security and output filtering at the theming layer
- When building nodes for different purposes (feeds, print-friendly mode, etc.) modules that modify the node via nodeapi have no way of knowing the intended use of the node, save the coarse 'teaser/full' boolean
The proposed solutions
- Rather than building just the node's body and teaser with a structured array, build the entire node using our array data structures. Title, submitted information, main content, links, comments, etc.
- Rather than rendering this to a string and then passing it on to the theming engine, pass the structured array itself to theme_node().
- Use this richer pool of information in the theme engine layer to expose more options for template designers without forcing them to circumvent our normal output-cleaning and rendering pipeline.
- Replace the teaser/full boolean flag with a richer 'style' parameter, supporting four options by default: teaser, full, print, and feed. Allow other modules to expose new styles for their own purposes.
- End hunger, war, and strife.
This sounds big -- and it would be foolish to say that it's a simple set of steps. But the foundation for all of these changes has already been laid. I'd like to propose a three-phase patch process to get these changes into core. If any of them make it in, we'll benefit quite a bit, but if all three somehow make it in, I believe that Ewoks will dance happily.
- Refactoring node_view()
- First, we need to build the entire node structure as one of our standard #arrays, rather than just the node body.
- Next, we migrate nodeapi op view and nodeapi op alter to to the node-standard
drupal_alter('node', $node_array);syntax. This lets modules use hook_node_alter() to add stuff to nodes, while nodeapi focuses on CRUD operations.
- Next, we eliminate the node_show() function and move its hard-coded calls to comment.module to a standard will allow comments to be added to the node the same way all other data is, not using ugly hard-coded hacks like node_show(). (Look that function up. Read it and weep.)
- Refactor theme_node() to accept our structured array rather than a raw node object. Map top-level array elements like 'submitted' and 'content' directly to variables for template designers.
- Allow template designers to manipulate the structured data, not just pre-rendered bits of it
- Right now, our theme engines expose a discrete set of variables for themers. We should expose helper functions that let template designers selectively print sub-chunks of the element they're designing a template for. We do this already when writing hard-coded theme_* functions for forms -- drupal_render($foo['bar']), drupal_render($bar), etc. Something along the lines of output('content-image-2') or output('comments') or output('links-new-comment') would be ideal. Obviously, exposing drupal_render() itself at the template layer is not desired. But the theme engine's job should be mapping drupal_render()'s flexibility to whatever tag/language syntax the template designers need... not heavy-lifting bits of node data from one place to another.
- This portion of the plan needs to be fleshed out, and I'm SURE will be the subject of debate. I am not married to an specific course of action, just the end goal: exposing the rich nested metadata we build to themers who can properly utilize it.
- Replace the hard-coded 'teaser', 'page', and 'links' params in node_view with a flexible $style param, and an $options array:
node_view($node, $style = 'full', $options = array())
- Expose hook_node_styles(), allowing modules to expose their own custom node rendering styles. node.module will expose the four core defaults: teaser, full, print, and feed.
- Expose node_get_styles(), a function similar to node_get_types(). Modules that currently allow users to select behavior based on teaser/full state should instead allow users to configure behaviors for each of the new styles.
- Optional overrides (like, 'build this in full mode, but don't show the comments,' or 'don't show the links for this node') can be configured by flags in the $options parameter. These are little-used flags, and collapsing them into a single optional array mirrors the new technique used by the l() function. It's more flexible and easier to use in edge cases without disrupting the function's signature.
There's a lot in there. An awful lot. This is a proposal, though, and while I have pseudocode for most of the steps in here, I want to get others in the community on board to hammer out the details and help figure out where the pitfalls are.
What do we gain from this refactoring effort? More consistency, reduced duplication of code, and the preservation of meaningful metadata later in the rendering pipeline. That, in turn, means more possibilities for robust theming engines and more possibilities for template designers who don't want to learn to hack PHP and write hook_foo_alter() functions to get things done.
Code coming shortly -- discussion encouraged in the meantime.