I'm using a Zen subtheme.
I've got a CCK field called "subtitle".

I'd like to do something like:

function mytheme_preprocess_node(&$vars, $hook) {
  $vars['subtitle'] = $content->field_subtitle_value;
}

or words to that effect, so that I can just put this in my node.tpl.php:

<?php if($subtitle): ?>
   <div class="subtitle">
      <?php print $subtitle; ?>
   </div>
<?php endif; ?>

But the variants I've tried in that preprocess function just haven't worked out.

What am I missing? Or is this even supposed to be possible without, say, node_loading?

Comments

dnewkerk’s picture

Is there a reason you want to preprocess it? You can just simply print the field into the node.tpl.php file like this: <?php print $node->field_subtitle_value[0]['view'] ?>
More info in my guide here: http://www.davidnewkerk.com/book/30

nevets’s picture

The above comment should get you going but to help you learn your code is missing some concepts, the function only takes one parameter (&$vars) and $content is undefined. As a start your function might look something like

function mytheme_preprocess_node(&$vars) {
  $node = $vars['node'];
  // Check the node  type to make sure
  // we have the one we want
  if ( $node->type == 'your_node_type_here' ) {
      $vars['subtitle'] = $node->field_subtitle_value[0]['view'];
  }
}
datawench’s picture

I am actually using

<?php print $node->field_subtitle_value[0]['view'] ?>

now.

But I'm trying to move closer to what I understand are new best practices, that reduce theming to the simplest possible layout and variable output.

Thank you for the code fragment. I'll work with that and see if it resolves some of my misunderstandings.

Edit: I need to point out, though, that the two arguments to the function I showed actually come directly from the Zen subtheming example.

dnewkerk’s picture

I see what you're referring to in the Zen sub-theme. I believe though that it is incorrect, as $hook does not belong in that example (it's used in the template_preprocess function though). A function like template_preprocess_node already has the hook built into the function name. See http://drupal.org/node/223430 about the available preprocess functions. You can read about when it's appropriate to use $hook at the spot in the page which begins with "When using a preprocessor not specific to a theming hook..."

I can't speak for everyone, though I believe most people don't go as far as to preprocess the fields of a node. The amount that it simplifies the look of things in the theme itself isn't a big enough payoff to me to be worth the extra level of complexity in case things have to be changed. A case where I think it would be more beneficial would be with multi-value fields, since they actually "do" require a few lines of PHP to render all the values (a foreach loop), so getting that out of the template would be more worthwhile perhaps. Nothing "wrong" with preprocessing them all though if you prefer to (well I can't say for sure if there's a performance impact, maybe someone could confirm).

datawench’s picture

It finally occurred to me to just print_r($vars) right in the preprocess routine and pull it apart. Not surprisingly (though it's always nice to see it confirmed), it's pretty much the entire $node object that gets pulled into the theme layer. The question is just accessing the nested array correctly.

So this is what worked:

function mytheme_preprocess_node(&$vars, $hook) {
	//print_r($vars);
	if ($vars['type'] == 'story'){
		$vars['subtitle'] = $vars['field_subtitle'][0]['safe'];
	}
}

At the moment it barely does anything... as has been pointed out earlier, I could have just put that assignment in the theme itself, the way I was used to doing. But this gets me closer to "pure" theming and gets me started in understanding what eventually I might be able to do in those preprocessors.

My thanks for the hints.

yakker’s picture

Thank you, datawench, and everyone else for this thread. Finally, theming Drupal is unlocking for me.
A question: I gather that using the 'value' of a field array is unstable, but does anyone know if there is a good reason to preprocess field array data in template.php, with something like:

<?php
mytheme_preprocess_node(&$vars){
  vars['dummy_variable']=$node->field['fieldname'][0]['value'];
}
?>

and then printing with:

<?php print $dummy_variable;?>

Instead of printing it directly to the tpl file with something like the below code, when all you to do is print it directly (you don't need to actually work with the data before it's displayed)?

<?php print $field_fieldname[0]['value'];?> 
or
<?php print $field_fieldname[0]['view'];?>

Again, my grateful thanks!

nevets’s picture

I would just print directly from the tpl.php file and in general you should use the 'view' value.

datawench’s picture

I'm not so conversant with this technique as to be able to offer more than a general sense of what might be done with it. But consider the example I've been working with. Think of $subtitle as a derived field. In this instance it's extremely simple, but in another it might turn out to be more complicated. By creating this variable at the preprocess level I make it available at the theme level to all node templates. If I were to decide to derive it differently, then I simply change the preprocessor function, whereas if I had done the work on the tpl.php level I would have had to make the changes in every tpl.php where the value was required.

It's a potentially useful abstraction that I'm just learning to exploit. What I've also learned is that once you start thinking in these terms, more and more possibilities present themselves.

yakker’s picture

Thanks, both of you.

I'm leaning towards your suggested structure, datawench, for exactly that reason - I like the idea of just being able to say "print this" in the tpl layer, and to do all the work about what "this" is in the template.php file. Working great so far.

Have you ever run into troubles preprocessing node variables in template_preprocess_page() while using a View (from the Views module)?

oknate’s picture

In Drupal 6, you can use this hook from CCK. I had to clear my cache for it to work. But this is one way to edit the field output in a node without rewriting the $content variable completely or ignoring it and using the raw output. Generally, it keeps your code cleaner to do these adjustments in your custom module, rather than in the template.php file in your theme folder, or the actual node template (e.g, 'node-myspecialcontenttype.tpl.php')

/**
 * My custom implementation of CCK (content.module) Theme preprocess function for field.tpl.php.
 */
function mycustommodule_preprocess_content_field(&$variables) { 


	if($variables['field']['field_name'] == "field_myspecial_field") {

		$variables['items'][0]['view'] = 'TEST TEST TEST';
	}
	

}
oknate’s picture

To remove cck fields on certain pages, you have to go to a step earlier. use the nodeapi to hide cck fields based on parts of the URL (see the drupal's arg() function).


function demolibrary_nodeapi(&$node, $op) {


	if($node->type == "voice_actor_profile") {
	
	switch($op) {
	
	case "insert":
	
	break;
	
	case 'load':

	break;
	
	
	
	case 'view':
	
		if( (arg(0) == 'edge-demos' || arg(0) == 'talent-library')) {
			unset($node->content['field_actor_first_name']);
			unset($node->content['field_actor_last_name']);
			unset($node->content['field_actor_phone']);
			unset($node->content['field_actor_email']);	
	
		}
		
		if(arg(0) == "talent-library") {
			unset($node->content['field_actor_cc_blurb']);
		}
		
		if(arg(0) == "edge-demos") {
			
			unset($node->content['field_gender']);
			unset($node->content['field_actor_age']);	
			unset($node->content['field_ivo_languages']);
			unset($node->content['field_ivo_languages_other']);
			unset($node->content['field_ivo_accent']);
			unset($node->content['field_ivo_accent_other']);
			unset($node->content['field_actor_skills']);
			unset($node->content['field_actor_skills_other']);
			unset($node->content['field_actor_unions']);
			unset($node->content['field_home_studio']);
			unset($node->content['field_home_studio']);
			unset($node->content['field_actor_rates']);
			unset($node->content['field_actor_location']);
			unset($node->content['field_actor_scheduling']);
			unset($node->content['field_actor_scheduling']);
			unset($node->content['field_actor_statement']);
		
	}

	break;
	
	} // end switch
	} // end if

}


dsnoeck’s picture

It did the trick.
- Damien

- Damien
:: Keep Open Spirit ::

Pav-2’s picture

How could I use this for adding, e.g. h2 tags for all cck fields used as standfirst - field_standfirst or h1 for all cck fields called field_headline.

Cheers

yurtboy’s picture

nice!

fedExpress’s picture

Thanks. it worked for me (needed to include field values into ).