Article Update: Creating a Compound Field Module for CCK in Drupal
I just updated my article on Creating a Compound Field Module for CCK in Drupal. It's a programming tutorial on how to create a custom field module for the Drupal content management system and its Content Construction Kit module. In particular, the article covers how to create a custom field that packages an image upload, a caption, and taxonomy term, as one "compound" field.
The article and the accompanying module download have now been updated for compatibility with the released 6.x-3.0 versions of ImageField and FileField. Unfortunately, these modules changed a lot between the Alpha releases and the final releases, so the earlier version of the compound field module was totally incompatible with the released versions. The version in the article now is compatible. (Thanks to Greg Dunlap AKA heyrocker for pointing out the incompatibility.)
I also added more examples for compound fields that don't contain an image.

Comments
If possible, please provide
If possible, please provide an example of how to build a compound field from "simple" types, such as, text and number.
For example, annual scores in a student record with:
- Year (number), Subject (text), Score (text)
I am still struggling how to master the _field_settings hook when filefield_field_settings is not available.
Thanks~
Horace: The current article
Horace: The current article does have examples of the "office location" type, which should help... check out the office_locations_field_settings() hook that is in the article (not in the zip), for instance.
Either that, or you can look at the "Link" CCK field module (which you can download from drupal.org), which combines a several text fields. There is also I think a "full name" text field avaiable on drupal.org, for another example.
Good luck!
--Jennifer
Thanks for this guide. I'm
Thanks for this guide.
I'm in a similar position to Horace, trying to adapt the example to use a link field & an imagefield. I can't figure out why only the image data is saved, not the link's url & title.
I have added the link fields to the hook_elements(), should the data be saved by CCK?
It's not clear to me if hook _widget_process() should adjust the data to make it savable. What part of the returned $element is saved? If I have no code active in hook _widget_process() the image data still gets saved.
Sorry if this is inappropriate to ask in your comments, I just can't find much info anywhere else.
Thanks for the guide, at least it give us somewhere to start.
Dear Jennifer, Thanks your
Dear Jennifer,
Thanks your great article and the updates! I am able to create a compound field now.
Thanks!
horace
Drew -- If you put the extra
Drew -- If you put the extra information inside the "data" array that FileField/ImageField provides for extra data, it should be saved. If you do not use the "data" array, then you will need to use the 'database settings' operation of hook_field_settings to tell CCK to save your information.
Hope this helps,
Jennifer
Thank you jhodgdon, I was
Thank you jhodgdon,
I was adding the link modules $elements to the array returned by hook_elements() instead of adding the extra fields to the $elements within hook_widget_process(). It makes more sense now.
For some reason I thought link module would be involved in the data saving & processing of the input, similar to how filefield & imagefield are doing the saving for us in the img_cap_tax_fld module. It means I need to validate the link input independently right?
Link uses several _functions() for cleanup, sanitizing & validation, I should use the ones without the underscores because the underscores mean they are private functions?
Thanks, I think I'm getting to grips with this now.
The link module would only be
The link module would only be involved if you explicitly call link module functions, they way I called FileField functions in my sample module. Then you would have to look at the link module functions you are calling, to see what they do. There is nothing automatic about it!
You are correct about _ functions. Generally, calling module functions that start with _ (such as _link_xyz() or whatever) is not recommended. Module authors put the _ prefix on a function to indicate that the function is for internal use only, and is subject to change.
Good luck!
Jennifer
I will try to document how to
I will try to document how to create a simple compound CCK field here: http://ho.race.hk/blog/
I'm trying to get the CCK
I'm trying to get the CCK Time module to work in D6. It uses three select fields for holding the time elements (hr, min, meridian). Only one database column is used to store the data. So that means the three time elements need to be merged when the node is saved. I can't figure out how to merge the fields. Or maybe they are merging BUT right now all that is saving to the database is the first numeral. So for example, when I save 12:00PM, only "1" is saved to the database! If I save 8:00AM, only "8" is saved, etc. Any ideas, tips? Thanks in advance... and thanks for the article.
Ian: I am not familiar
Ian:
I am not familiar with the CCK Time module, but the Date module can do times as well as dates, so you might look at that.
If you are committed to writing your own module, and need to store information in the database, you can either modify the module so it uses 3 databaes columns (as in the "office location" examples in my article), or you can serialize the data so that an array can be stored in one TEXT field in the database (this is what FileField does with its data array).
If you are only getting one character saved, probably your databaes field is a varchar(1) type instead of TEXT (which would be unlimited size).
Hope this helps,
Jennifer
Thanks for the quick
Thanks for the quick response! I checked the columns and they are text(longtext). How do I serialize the data?
There is something odd going
There is something odd going on if those fields are only storing/retrieving the first character of your data.
To indicate that a database column is serialized for CCK, all you should have to do is add 'serialize' => TRUE to the database columns in hook_field_settings. Then CCK should take care of serializing and unserializing the data for you.
Then you will need to make sure that at the time CCK would be saving the data, your widget has put all of it into an array. For instance, if the column is called "foo" and you've declared it as "serialize", then you would need to have that foo component of the data to be saved look like
array( 'hr' => 12, 'min' => '30', 'meridian' => 10)
or something like that. You can look in the FileField module to see how they do this -- the 'data' column is serialized -- see what FileField does for those various CCK hooks.
One more note: CCK doesn't seem to always unserialize your data when you think it should, so you may have to occasionally unserialize it yourself -- check the examples in my article (search for "serialize" in the text of the article) for examples of that.
Good luck!
Jennifer
Hey Jennifer, Thank you for
Hey Jennifer,
Thank you for this tutorial its helping me to get where I want.. I have a few questions tough.
In the end there is little information to what to do with some functions if youre following the \Office\ example.
Here:
Q-Do I need the img_cap_tax_fld_field.inc if Im doing the “Office” example?
Q-What do I do with this part if I im doing the “Office” example?
function img_cap_tax_fld_widget_settings_form( $widget ) {
$form = imagefield_widget_settings_form( $widget );
$form['custom_alt'] = $form['alt_settings']['custom_alt'];
$form['custom_alt']['#type'] = 'hidden';
$form['custom_alt']['#value'] = 1;
$form['alt'] = $form['alt_settings']['alt'];
$form['alt']['#type'] = 'hidden';
$form['alt']['#value'] = '';
unset( $form['alt']['#suffix'] );
unset( $form['alt_settings'] );
$form['custom_title'] = $form['title_settings']['custom_title'];
$form['custom_title']['#type'] = 'hidden';
$form['custom_title']['#value'] = 1;
$form['title'] = $form['title_settings']['title'];
$form['title']['#type'] = 'hidden';
$form['title']['#value'] = '';
unset( $form['title']['#suffix'] );
unset( $form['title_settings'] );
$rows = (isset($widget['rows']) && is_numeric($widget['rows'])) ? $widget['rows'] : 5;
$form['rows'] = array(
'#type' => 'textfield',
'#title' => t('Number of rows in caption field'),
'#default_value' => $rows,
'#element_validate' => array('_text_widget_settings_row_validate'),
'#required' => TRUE,
'#weight' => 8,
);
$cols = (isset($widget['cols']) && is_numeric($widget['cols'])) ? $widget['cols'] : 40;
$form['cols'] = array(
'#type' => 'textfield',
'#title' => t('Number of columns in caption field'),
'#default_value' => $cols,
'#element_validate' => array('_text_widget_settings_row_validate'),
'#required' => TRUE,
'#weight' => 9,
);
$form2 = content_taxonomy_options_widget_settings( 'form', $widget );
$form2['settings']['#title'] = t( 'Settings for Taxonomy' );
$form = $form + $form2;
return $form;
}
Q-Also this part:
function img_cap_tax_fld_widget_settings_save( $widget ) {
$arr = imagefield_widget_settings_save( $widget );
$arr[] = 'rows';
$arr[] = 'cols';
$arr2 = content_taxonomy_options_widget_settings( 'save', $widget );
$arr2[] = 'allow_multiple';
$arr2[] = 'required_term';
return array_merge( $arr, $arr2 );
}
Q-And what to do with this part for the Office example since there is no image/taxonomy field to return?
function theme_img_cap_tax_fld_formatter_default( $element = NULL ) {
if( empty( $element['#item'] )) {
return '';
}
$img = theme( 'imagefield_formatter_image_plain', $element );
$cap = $element['#item']['safe_caption'];
$tax = '';
$sep = '';
$val = $element['#item']['data']['value'];
if( !is_array( $val )) {
$val = array( $val );
}
foreach( $val as $tid ) {
$term = taxonomy_get_term( $tid );
$tax .= $sep . check_plain( $term->name );
$sep = ', ';
}
return '' .
'' . $img . '' .
'' . $cap . '' .
'' . $tax . '' .
'';
}
Hi Gill, Sorry for any
Hi Gill,
Sorry for any confusion!
Here are attempts at answers to your questions:
Q-Do I need the img_cap_tax_fld_field.inc if Im doing the “Office” example?
A: No, that's just needed for compound fields that involve a FileField or ImageField component.
Q - Q-What do I do with this part if I im doing the “Office” example?
function img_cap_tax_fld_widget_settings_form( $widget ) { }
function img_cap_tax_fld_widget_settings_save( $widget ) {}
A - (from the article) Our "office location" form, like many CCK fields, doesn't have any widget settings -- there are no choices to be made to customize the widget. [Leave both of these functions out.]
Q-And what to do with this part for the Office example since there is no image/taxonomy field to return?
function theme_img_cap_tax_fld_formatter_default( $element = NULL ) { }
A - You can do something similar to what the caption part of this function does, for the office location fields.
Hope this helps...
--Jennifer
Compound field with date
Hai Jenni,
I am trying to create a compound field with date as value. could you give me some hint.
ty.
Post new comment