A complex CCK module in Drupal

CCK is Drupal’s way of making rich content. It means that nodes of any content type can have any kind of data attached to them, so you can have e.g. a directory of superstore outlets, where the outlet records have their longitude and latitude (editable by a Google Map widget) whereas the contact records (e.g. Sales Manager, South-East) can have a portrait photo, selected from an image gallery in a dropdown widget. (A note on terminology: widgets are the structures which are used to edit the CCK data, typically defined in the same CCK submodule as the data types).

There’s already a tutorial with a CCK submodule available. The premise of the sample module is to provide two fairly generic numerical formats. In principle that simplifies the submodule, but in practice it also means it’s difficult to work out precisely why particular programmatic choices were made and what you can tweak. Also, at work we wanted a much richer content type. Here’s what we wanted to display:

  1. Build an “Available in” field for e.g. all the different formats that a book might come in.
  2. Record the dimensions DxWxH
  3. And some dscriptive information
  4. And let the user pick a thumbnail from a dropdown
  5. And let all of this be done multiple times

Here’s a mockup of what we wanted to appear on the admin page (excuse styling—Wordpress isn’t the best for this):


Available in










And here’s sort of what we wanted on the front end (again, sorry for the HTML: it’s table-heavy as it’s a one off):

Available in
Hardback Paperback Trade p/bk
ins cm ins cm ins cm
W 5.1 13 W 5.1 13 W 5.1 13
H 7.6 19.2 H 7.6 19.2 H 7.6 19.2
D 0.79 2.0 D 0.79 2.0 D 0.79 2.0

It was difficult, from the simplistic submodule available, to work out exactly how you leverage complex editing widgets, and how you get CCK to save all the database information in the five columns we needed: description, thumbnail image reference and three dimensions in inches. What’s worse is that a CCK submodule with an incomplete set of hook functions seems to do a fandango on certain areas of the database (possibly the cacheing of certain bits of the module’s behaviour): certainly developing a CCK submodule was quite painful, as the process of trial and error frequently required a database restore so as to try again. That tutorial does warn that “all hooks are required. CCK expects them to all be present and will not function correctly if some are missing.” But there’s a world of developer pain in those brief phrases.

Since I originally mentioned the problems we were having on the development mailing lists, a couple of people have asked me how to build a CCK submodule to support rich fields. With this in mind my employers Torchbox have very gracefully let me make the module we built public, with some minor edits (the client’s site isn’t live yet, so names and details changed to protect the innocent).

The module is available here. It consists of 4 1/2 pairs of functions, as follows:

  1. Declare:
    1. field types that the module supports
    2. widgets that the module supports, for editing fields on the node-edit page
  2. Settings for:
    1. field (so settings inherent to the way that particular field is stored e.g. decimal accuracy for numeric values)
    2. widgets (so e.g. the image gallery that populates the dropdown for the wireframes)
  3. Handlers for:
    1. field, so what happens to it when a node is loaded
    2. widget, so pre-processing of the field to fit a HTML form, or producing a chunk of Form API, or post-processing the HTML form into a database-saveable format.
  4. BONUS UNNECESSARY FUNCTION: cck_book_complex_input just produces the Form API for function 3b. Ignore this one!
  5. Formatters, which give you output options for fields on the “Display Fields” page.
    1. Declaring formatters
    2. Formatters

A few extra pointers:

  1. CCK does most stuff for you, so you don’t need to actually load/save field contents to the database; declaring the columns for widgets and fields is enough.
  2. If you’re in the developing phase with your CCK submodule, back up the database first. See above.
  3. We sidestepped formatters altogether as they don’t cope with e.g. multiple field values that need a header value. Instead, we just overrode theme('field'). One thing, though: you do need some formatters present, or the admin configuration page for “Display Fields” defaults every dropdown to “<Hidden>”, and you can’t get anything to appear.
  4. To reiterate, CCK needs all hooks present in its submodules from the start. The further you get from Drupal core, the more bleeding-edge APIs will get.

Note that as I say we had to peer into the node (use var_dump($node) and search for the right array) and then override the theme, because we wanted a fancy header to our field. But that was pretty painless—mostly a matter of knowing one’s PHP rather than one’s Drupal—and it all worked smoothly otherwise. And we ended up with by and large exactly what we wanted. It works and, in retrospect, Drupal has helped us to write readable, maintainable code.