I'm working on a simple module that allows different teaser lengths per content type.
In both places that node.module calls the node_teaser() function, there's a comment about "Extract a teaser, if it hasn't been set (e.g. by a module-provided 'teaser' form item)." So far so good -- if you set the teaser yourself, then drupal core will refrain from doing it itself.
Setting the teaser that's saved is easy. In my hook_nodeapi:
switch ($op) {
case 'submit':
$node->teaser = 'whatever';
break;
}
The final thing I need to do is show the teaser as it will be saved on the node Preview form.
This is where I'm stuck.
I've looked at other modules that change the teaser (cck_teaser_field, excerpt, tweakbox) for hints, and they don't address this.
hook_nodeapi isn't called with a 'submit' operation during a preview, so I need an extra step.
This is the sequence of calls to hook_nodeapi during a node preview (this page is useful, by the way):
- op 1: load
- op 2: prepare
- op 3: validate
- op 4: view
- op 5: alter
- op 6: view
- op 7: alter
(You get view and alter twice because the node is shown twice on the preview page, as teaser and full.)
- load: this doesn't sound like the right place to do this at all. And anyway...
- prepare: whatever is set in $node->teaser here later gets blanked. By the time the flow gets to node.module's node_preview(), it's empty. (I think what's actually happening is that 'load' and 'prepare' get called with the $node object loaded from the database to populate the form. Later on, to insert the preview into the form, node_preview() is called with the form values, and treats that as a $node object -- which doesn't have the teaser since there's no field for the teaser in the form.
- view: you can test $node->in_preview to get the condition that a node is being previewed. (Note this is called twice for the two versions of the node shown.) But setting $node->teaser here has no effect. I could hack into $node->content['body']['#value'], but the only way of distinguishing the two calls to this in the $node object is that the second has HTML tags (not sure why). It's also unsuitable because input method filters have already been applied at this stage.
- alter: the same as view applies here.
The comment in node.module obviously suggests altering the teaser on preview is possible -- but as far as I can tell, it's not.
Any thoughts?
Comments
Found a way to do it...
Found a way to do it... though it's not *hugely* pretty:
I think your solution is as pretty as is possible ;-)
Hmm an interesting little conundrum.
The clue I suppose (and as you would seem to have concluded) being in the comment "Extract a teaser, if it hasn't been set (e.g. by a module-provided 'teaser' form item)" ... except that a module provided form item named 'teaser' is AFAICS the only way of setting the teaser and then having it appear on node Preview without code contortions. And faking such a form item is in essence what you have done, if I understand it correctly.
In Drupal 6 the code around node Previews has changed slightly, but without examining it or doing some tests I couldn't say whether it behaves the same or not. If it does, then a feature request should perhaps go in for Drupal 7 so that the node object (i.e. the $form_values) that is the subject a node Preview is handled in the same way as node objects generally i.e. so that there is an opportunity for modules to modify the about-to-be-Previewed object ... this might largely be a matter of adding a http://api.drupal.org/api/function/node_object_prepare to node_preview(), so that the object is properly prepared? Any thoughts?
Closing comment: the handling of $node and $form_values in http://api.drupal.org/api/function/node_form/5 seems a bit obtuse to me. For a start I'm not sure that $form_values is ever passed in. Then when http://api.drupal.org/api/function/node_content_form/5 is invoked, $form_values is passed but not listed in the arguments in the function definition, and never used. Then, as you've pointed out, the $node in node_preview() is actually global $form_values objectified. And finally, when previewing an existing node the node goes through the load and prepare phases and the form gets populated accordingly only for FormsAPI (I presume) to overwrite everything with the submitted form values.
gpk
----
www.alexoria.co.uk
gpk
----
www.alexoria.co.uk
For general information: bug
For general information: bug filed here http://drupal.org/node/218521
An update for Drupal
An update for Drupal 6...
The above method doesn't work in D6.
Instead, what I've found is adding a custom submit function to the edit form