Last updated 4 December 2008. Created on 6 September 2006.
Edited by Chris Johnson, ksenzee, AjK, KarenS. Log in to edit this page.

NOTE: This page is still very much under construction and prone to blatant errors.. I'm filling stuff in as I figure it out. -- webchick


CCK is comprised of 2 things:

  • fields: These refer to the data that's being stored. For example, Text or Number.
  • widgets: These refer to how the input widget an end user uses to enter the data looks. For example, Text field or Check boxes.

Data Model

CCK Data Model

CCK's data model consists of 3 base tables:

  • node_type_content: A table containing the CCK node type defninitions: name, label, description, help, and the label given to the node's Title field.
  • node_field: A table containing the various field definitions: field name, type, and various settings.
  • node_field_instance: An individual instance of a field applied to a content type, along with its widget settings. For example, field_description in the content_blog type and field_description in the content_product type.

In addition, each new content type creates its own table, called node_content_X, where X is the name of the content type. This table contains a node ID (nid) and revision ID (vid) field, along with the values of any extra fields, if the field is specific to that content type.

If, however, a field is shared among more than one content type, a table called node_data_field_X, where X is the name of the field, is also created to track the field's settings between node types.


Note: More detailed hook information is available from the file field.php in the CCK module.


  • hook_field_info(): Here you declare the label for your field type(s). This will show up when you click "add field" on a CCK content type.
  • hook_field_settings($op, $field): Handles displaying, validating, and saving field settings forms. In addition, manages how they're stored in the database and provides Views integration.
  • hook_field($op, &$node, $field, &$node_field, $teaser, $page): Define the behavior of a field type.
  • hook_field_formatter_info(): Declare information about a formatter.
  • hook_field_formatter($field, $item, $formatter, $node): Prepare an individual item for viewing in a browser.


  • hook_widget_info(): Here you declare any widgets associated with your field type. These will show up below the fields when you click "add field" on a CCK content type in 4.7.x and 5.x. Fields show up in the first drop-down and widgets in the second drop down when adding content types in 6.x.
  • hook_widget_settings($op, $widget): Handle the parameters for a widget.
  • hook_widget: Define the behavior of a widget.


  • While developing CCK, you may notice oddities such as settings you made not appearing and other such things. Always remember to clear your cache!

Looking for support? Visit the forums, or join #drupal-support in IRC.


mooffie’s picture

Thanks for this valuable overview!

If, however, a field is shared among more than one content type, a table called node_data_field_X, where X is the name of the field, is also created

The node_data_field_X table is also created when the field is of type "Multiple values". This happens even if the field is not shared among content types.

When the field is multiple-valued, the node_data_field_X table contains an additional column: delta.

mooffie’s picture

I think you have an error in the diagram for the node_data_field_X table. The picture shows two fields in that table: field1 and field2. However, one node_data_field_X table holds data for one field only, so you need to remove "field2" from this table. (And, you must rename the remaining "field1" to "field3", or whatever, because "field1" already exists in node_content_X.)

(BTW, what software did you use to create this beautiful diagram?)

mooffie’s picture

(You should add the _value suffix to the appropriate column names in your diagram.)

Have you ever wondered about the "_value" suffix in column names?

A field's data may actually occupy more than one DB column. It's true that the simple Text and Number fields occupy only one column (field_X_value), but the more complex Date field, for example, occupies two DB columns: field_X_value and field_X_timezone.

There's nothing "holy" in a _value suffix:

Let's say I want to create a new field type: Color. This field will occupy three DB columns (for the red, green and blue intensities). I'll define my hook_field_settings as:

function color_field_settings($op, ...) {
  switch($op) {
    case 'database columns':
      return array(
        'red'   => array('type' => 'integer', ...),
        'green' => array('type' => 'integer', ...),
        'blue'  => array('type' => 'integer', ...)

Now, if I add such field, let's call it "favorite color", to my content type, my content type table would contain three new columns: field_favorite_color_red, field_favorite_color_blue and field_favorite_color_green. It would not contain field_favorite_color_value, because such a column ("value") was not defined in color_field_settings.

Similarly, the nodereference field doesn't define a "value" column. It defines "nid" instead:

function nodereference_field_settings($op, $field) {
  switch($op) {
    case 'database columns':
      $columns = array(
        'nid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'),
      return $columns;

A "value" column is defined in number_field_settings and text_field_settings.

BTW, contrary to what I've said, the Text field is not so simple: it may occupy two DB columns if an input format may be applied to the string (that is, when the "Filtered text" option is selected).

(BTW #2, in my previous comment I said you should leave only one field (in CCK terms) in the diagram for the node_data_field_X table. But this one field may occupy several DB columns (depending on its type and settings)).

KarenS’s picture

I wanted to convert some simple node types to cck to take advantage of the ability to add more fields to them. I had a couple custom types I created by copying the story.module that I wanted to convert, plus I wanted to make my basic event type into a cck event type and my basic og type into a cck type. I wanted to do all this without losing any of the data that existed. I thought I'd share the process and a php snippet that worked for me to do this. This should work for any simple content types (i.e. changing types that do not use revisions which only have a title and a body to a cck type with a single description field that will hold the body content).

  1. First, create the new cck content type you want to move to (in this example, it ended up named 'content_event')
  2. CCK doesn't use the body field, so you need to add a cck text field for the body content. Give the field more than 1 line to make it a textarea instead of a textfield, and be sure to indicate that it uses filtering. Note the name of the field that is created. For my example, I created a field called 'field_description'.
  3. Create a test node to be sure that everything got set up correctly and that you can manually enter data into your new content type and that it gets saved correctly. Be sure that you get a textarea field instead of a textfield and that the filter is available for selection.
  4. Make a good backup of your database. Go ahead and make another one just in case :-)
  5. Now run the following code to change the data in the database.

Note: I can see that the code gets cut off when posted. I tried several methods of posting it and none displayed correctly, so if it's getting cut off, just pick it up from the source of this page.

  // convert another node type to a cck type
  $from_type = 'event';
  $to_type = 'content_event';

  // the name of the cck field that will hold the value of the node body
  $to_body_field = 'field_description';

  // pull up nodes with the old content type
  $results = db_query("SELECT nid, title FROM node where type='$from_type' ORDER BY nid");
  while ($arr = db_fetch_array($results)) {
    $nid = $arr['nid'];
    drupal_set_message('Converting '.$arr['nid'].': '.$arr['title']);

    // create a cck record for this node and make sure it's not a duplicate
    db_query("DELETE FROM node_".$to_type." WHERE nid=$nid");
    db_query("INSERT INTO node_".$to_type." SET nid=$nid, vid=$nid");
    // change the node type in the node table
    db_query("UPDATE node SET type='$to_type' WHERE nid=$nid");
    // move the value in node body to the cck body field
    if ($to_body_field) {
      $node = node_load($nid);
      $results2 = db_query("SELECT format, body FROM node_revisions WHERE nid=$nid");
      while ($arr2 = db_fetch_array($results2)) {
        // if there is a body value save it to new field
        if ($arr2['body'] > '') {
          $node->$to_body_field = array(
              0 => array(
                'value' => $arr2['body'],
                'format' => $arr2['format'],
          $node = node_load($nid);
          $value = $node->$to_body_field;
          if ($value[0]['value'] == $arr2['body'] && $value[0]['value'] > '') {
            // if successful, erase the body and teaser (cck doesn't use them)
            db_query("UPDATE node_revisions SET body='', teaser='' WHERE nid=$nid");
  // update other tables that use content type name
  db_query("UPDATE vocabulary_node_types SET type='$to_type' WHERE type='$from_type'");

kiwibird’s picture

          $node->$to_body_field = array(
              0 => array(
                'value' => $arr2['body'],
                'format' => $arr2['format'],

I wondered a lot where to find out what the fields actually looked like, and how to set the fields of a CCK node from php like this, but then I installed the devel module, which lets you see the Object Structure of each node you create, making it easy to just create a node and then see what the arrays in the field_foobar's look like.

Bèr Kessels’s picture

Can someone with more intimite knowledge of CCK shine some light on this 'multiple' thing?
* why is it there?
* what is it for?
* how should developers handle this when storing their own data in private tables?

Professional | Personal
| Sympal: Development and Hosting

KarenS’s picture

This has been confusing many people and I'm not sure exactly what the original intention was. The clearest use case is when it is combined with optionwidgets or nodereference or userreference where it makes it possible to select and store multiple values in your selectors. It gets murky beyond that because it creates an undefined number of additional instances of whatever field you use it with, but with no ability to give those additional instances their own name or identifier (or even to specify how many of them you want). So you can use a text field to store phone numbers and store 2 different phone numbers by using the multiple option, but you won't be able to give them labels to identify which is which. You could also store multiple images with imagefield or multiple files with filefield, which might be more useful. I was also playing with the idea of storing multiple date fields in a single event node as a way to handle repeating events without creating duplicate nodes which might be another legitimate way to use this capability.

peterx’s picture

Multiple makes sense if you want multiple values of the same type. A book may have one author or many. You want the Author field to change from a single string to multiple strings.

What would be of use are examples of more complex relationships.

Similar fields with different means should be processed some other way and I am still looking for an example built with CCK. Suppose I have a Contact node and add a telephone field. I then want to have home and work numbers. I could change telephone to have multiple but that does not let me find out which is the work number. I could define separate fields named work_telephone and home_telephone but then I have to define the same format twice. It makes sense to define telephone then and telephone.home to inherit telephone's attributes. I think that is where widgets are used. You define a widget to handle the telephone format then apply the one widget to both telephone fields.

What makes sense next, and again I have not found a current example implemented with CCK, is to have minimum and maximum entries in multiple. You might have a field xyz that has to have a minimum of two entries or a maximum of 10 entires. I am thinking of polls where you ask people to nominate their top 10 choices or emergency contact details where you might ask someone to nominate a minimum of two forms of contact.

Perhaps we could start pages in the CCK documentation with the questions and leave space for more experienced users to add the answers.

Lionfish’s picture

The multiple values I've found very useful, and I've used it in several places already.
An example in my case is "People attending Events":
Many people can attend an event, and many events can be attended by one person.
In the database, as mentioned before, a new table is created which has foreign keys for both person and event. This means the many-to-many relationship can exist without having to have a 'list' in a field (thus keeping it 3rd Normal Form).

What I'm saying is, the multiple values thing is essential (at least for me :)

Thanks for the documentation. I didn't realise this was here until now - figured it all out from poking around the database...

mhuebl’s picture

In Drupal 5 node_content_X was named to content_type_X and node_data_field_X into content_field_X