There's a well known problem with node theming and the flat all-inclusive $content variable :
if you want to use the more fine-grained $FIELD_NAME_rendered variables or custom markup for some field, you cannot use $content at all because you'd get duplicate output. Your template then needs to handle the display of all the node components itself.
#134478: Refactor page (and node) rendering attempts to fix that, but it's not there yet.

Attached patch builds on a suggestion by theabacus in #294897: CCK theme problems and possible solutions, and lets themes define a list of fields and groups that will *not* end up in $content.
The theme's templates are then free to use whatever custom markup for those, and let print $content; take care of the rest.

No UI for now - I'm not sure we'll want one, and we can probably start without. The list of excluded fields and groups is defined by a 'theme function', that returns an array of field names / group names.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

alanburke’s picture

I don't have a chance to test the patch right now.

But on the concept, a big +1

I'm here at Drupalcon [drinking the beer I owe you...] and at the Node Templating presentation, this came up as an issue.
http://szeged2008.drupalcon.org/program/sessions/node-templating

The suggestion given was to use panels 2 for more flexible layout of a node - but I want to avoid using panels until really needed.

This is a much more elegant solution, and it also solves the problem of when fields get added to node types AFTER the template has been written.

The UI would be difficult. I reckon this is pretty advanced themeing requirement, and would almost be better as a seperate module, and keep CCK ui simple.

Regards
Alan

gleroux02’s picture

yched,

I personally love the concept of this patch.

I work with colleen from http://www.palantir.net/blog/graycor-drupal-theming-works. Our goal is to always try to keep the $content variable intact, and to reduce the amount of modified tpl files (Where the content variable is stripped out of tpl file in place of custom placement of the cck fields). From what I can understand this patch will make this goal even easier to reach. And I cant wait to try this out on the next d6 project I work on. Unfortunately the next d6 site I will be working on will also be my first.

That being said I was wondering if you or anyone else has seen a similar patch, or a similar solution for the same problem on a d5 site.

JohnAlbin’s picture

Yeah, the solution I just stumbled upon in D5 is to hide fields in the CCK "display" tab and then render the field with the appropriate field formatter in the preprocess function. But that's a lot of work for a themer.

If there was a UI for this, it would just need to be a single checkbox for "include in $content". But I'm ashamed to say I haven't used CCK 6.x yet. :-(

Any solution at this point would be an improvement over my work-around.

I like the theme_content_excluded_fields okay, but does this give themers a way to provide different fields depending on whether we are rendering a teaser or full node, etc.?

[edit: I just realized my "single checkbox" idea is incompatible with the question/suggestion I posed at the end. :-p ]

yched’s picture

Yeah, the solution I just stumbled upon in D5 is to hide fields in the CCK "display" tab and then render the field with the appropriate field formatter in the preprocess function. But that's a lot of work for a themer.
Same here, same drawbacks...

does this give themers a way to provide different fields depending on whether we are rendering a teaser or full node, etc.?
Not the original patch, but I thought about it later - attached patch allows that.

About the checkboxes : main problem is that the list of fields that need to be removed from $content is actually dependent on the theme itself and on its node templates.

eaton’s picture

Something I've ben wondering about is the inclusion of additional 'display locations' in the Field Display tabs. Currently, it lists options for Teaser, Full, RSS, And Search Index. The code for that tabbed screen was originally designedto accept an arbitrary number of options -- wouldn't it be possible to supply a hook for modules to add more 'connection points' for a node? $node->build_mode = 'block' could be used to display fields that should appear in a sidebar block, for example.

yched’s picture

@Eaton: heh, I was *just* looking for you on IRC to ask for your opinion about this patch :-)

About additional contexts : definitely - the list of contexts is generated in _content_admin_display_contexts().
It is currently a fixed list, but we could call a hook that lets modules add to that. Probably as simple as that, code-wise.
Another issue would avoiding an overcrowded 'Display fields' tab. We already split it into 'simple' (full node', 'teaser') and 'advanced' (RSS, search...)

eaton’s picture

Yeah, I can definitely see that being a problem... I think it could provide some real benefits, though, allowing modules to add possible types to the list. 'NodeAsABlock' is one example that springs to mind, as well as the 'CCK blocks' module. Both go through some odd contortions to intelligently split things into sidebar blocks, and it's be cool to see it handled cleanly.

I wonder if there's any good way to break these up without inventing a new, ungainly interface paradigm...

Crell’s picture

Subscribe. (I know, I should add something intelligent but at the moment "yes please!" is all I can think of...)

KarenS’s picture

The new method of handling contexts is at #310219: Extensible display contexts and could use some reviews. That needs to go in before this, then this patch will probably need to be adapted to that change.

KarenS’s picture

I'm getting close to a release and I don't have time to work on this patch, but if others can update and test it and let me know if it's ready, I can still get it in.

agentrickard’s picture

Seems to work as designed. Here's a little test that I ran on Garland, with a node field 'field_test' attached to blog posts, this is in template.php:

function garland_content_excluded_fields($type_name, $context) {
  return array('field_test');
}

And the specified field is removed from output (specifically, from $content). Need to explore the $context variable some more.

agentrickard’s picture

We were talking about making a UI for this at the office today. Problem is, our themers would want the settings to be _per theme_.

If this were not the case it would be pretty easy to add a UI on the field settings form and manipulate the $content object in content_view().

You could also:

1) Set the rules for the field and depend on the theme layer to load them with the current theme override.
2) Set the rules for the field and use a setting on the theme configuration to implement them or not. (Maybe.)

Ideas?

moshe weitzman’s picture

Multi themed sites are extremely rare in my experience. And ones that need to differ this particular feature per theme even rarer. IMO we could ignore them and proceed with a field settings form

mattiasj’s picture

This would be very helpful. Subscribing.

agentrickard’s picture

@Moshe

I would typically agree. But we have 4 Palantir folks on this thread, and the two themers already have use cases for this.

Now, we can get around this be implementing the settings in the theme function that yched already wrote -- that will allow for theme-based overrides. The other option is to remove the fields during content_view().

So I suppose I vote for loading the settings into theme_content_excluded_fields to allow for these overrides. The settings would then be global and administered on the field settings screen.

In my mind, the settings would be options for each context set within a separate fieldset. So you end up with a function like so:

function theme_content_excluded_fields($type_name, $context) {
  $excluded = variable_get('cck_excluded_fields_'. $type_name, array());
  return $excluded[$context];
}
Crell’s picture

Moshe is right that multi-themed sites are an edge case.

However, #12.1 does suggest an option. Use a theme_ function as now that by default uses whatever is configured in the UI. 99.9% of sites will never override it, but if you really really need to you can override that function per-theme like any other theme function, at which point you're on your own to decide how to respond to the UI or not.

It's something of an abuse of the theme system, so I'm actually tempted to suggest that it not be marked @ingroup themeable. But it would allow us to have our UI and theme it too. :-)

agentrickard’s picture

Updated patch against 6--2. Working on a UI patch now.

agentrickard’s picture

Attached is a version with a very rudimentary UI. It creates a 'Theme fields' tab for each content type.

The form saves to the variables table -- which might not be preferred, but changing the cck tables is a more extensive patch.

Form also needs theming love, since right now it is just plain ugly checkboxes.

KarenS’s picture

I think this looks interesting. And I think the checkboxes are OK, maybe we just wrap each context in a fieldset to give them some definition.

I think the explanation needs some work though, it's a little obtuse :)

Anyway, this seems like it would be a nice addition.

KarenS’s picture

I mean wrap each field in a fieldset, not each context.

KarenS’s picture

My biggest concern is that we've reversed context and field so that this page works the opposite of the Display fields page. I think that will be confusing to everyone.

I understand the logic behind the switch, but I think the two screens should be consistent.

I'm open to discussion though.

KarenS’s picture

I think the confusion in the description is talking about 'should not be included' instead of saying 'should be excluded', I don't like double-negatives. And I would change the name of the tab from 'Theme fields' to something like 'Exclude fields' or 'Advanced options', since the 'Display fields' is actually the main 'theme' page and this is just a place to tweak the theme a bit more.

But remind me again why asking everyone to check a checkbox for each field is better than marking the field 'hidden' on the Display fields tab? It seems like that would accomplish the same thing and be about the same amount of work.

JohnAlbin’s picture

But remind me again why asking everyone to check a checkbox for each field is better than marking the field 'hidden' on the Display fields tab? It seems like that would accomplish the same thing and be about the same amount of work.

Because marking a field as "hidden" means that the field formatter doesn't get applied to the data available to the theme layer.

i.e. the field is raw and you need to figure out which/how to apply a field formatter to the raw data in the preprocess function.

Being able to select the field formatter you want and then be able to specify whether or not it gets displayed in certain contexts is much easier for the themer since they don't have to deal with the raw field.

agentrickard’s picture

Status: Needs review » Needs work

I would agree with #19, just don't have the time to push this all the way today...

KarenS’s picture

FileSize
9.73 KB

Here's a different way to handle the UI. It just adds a checkbox to the existing Display fields page next to each context. It eliminates the need for another tab and the need to explain the difference and I think would be pretty easy to use. It also has the advantage of storing the value in the display_settings array so that it's available in the $field information along with other field info.

This isn't fully tested, I just got far enough to get the UI looking the way I want.

KarenS’s picture

FileSize
9.66 KB

Try again, there was some wrong stuff in the last patch.

KarenS’s picture

The fieldgroup theme still needs to be adapted to the new method, I just got the regular field theme working so far.

KarenS’s picture

Status: Needs work » Needs review
FileSize
10.22 KB

Here's a working patch -- tested on fields and fieldgroups, able to hide fields either inside or outside of groups, or hide the group as a whole.

agentrickard’s picture

FileSize
9.96 KB

Yes. That is very slick. I approve ;-)

Patch was formatted with Window linebreaks (CRLF), though.

KarenS’s picture

That was just the one I posted, I didn't stop and take the linebreaks out, I won't commit the linebreaks :)

I am making a few more changes to add these new values to the default values for fields and groups and to add some more documentation of what is available in the theme. Then you can override the theme whereever you want to do something different.

I mostly wanted to be sure that format was going to accomplish what you need.

KarenS’s picture

Status: Needs review » Fixed

I have committed this to -dev. Please give it a good workout ASAP so we can fix any bugs that might be in it before we issue a new release.

I added an update function for both fields and groups to update the display information to include a new value for 'exclude', which obviously defaults to zero (don't exclude).

KarenS’s picture

I committed it without giving any credit to any of you that helped out, especially agentrickard. Sorry!! I meant to do that.

Crell’s picture

Make another commit that does nothing but credit people. :-)

yched’s picture

Thanks all for driving this home :-). A theme function that defaults to the UI settings was the good idea we were missing.

I have one minor gripe with the patch that got committed, about theme_content_content() returning the HTML to include in $content. Granted, this is more inline of what you'd expect from a theme function, but the initial goal here was simply a binary 'include in $content or don't include in $content' alternative, whereas we now have a new way to completely modify what gets printed.
I'd vote to keep field templates as the one-and-only way to do that, and use a theme_content_exclude() theme function that return TRUE or FALSE.

KarenS’s picture

Status: Fixed » Active

The output is completely rendered by this time, so I don't know what else you could do with it besides show it or not show it, and I thought it would be less confusing if the theme acted the same way other themes do. I guess I can re-work the theme to return TRUE/FALSE to make it clear that's the only thing you can do with it if that's a better way to go.

KarenS’s picture

Status: Active » Fixed

I committed that change.

yched’s picture

Great, thx Karen.

Anonymous’s picture

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.