Organizing the history of Ingersoll Scout Reservation (in Drupal)

Since 1998 I have been maintaining an online history of Ingersoll Scout Reservation -- specifically, a history the staff who have worked there every summer since 1965. It's an impractical obsession -- both the maintenance of the history and the summers at camp.

Sometimes I wonder why I do it. At the outside, only a thousand or so people -- all of the staff since 1965 -- could possibly be interested. What use is my time investment there? What does it matter?

But what the hell? I learned most of what I know about leadership and communication and responsibility there. I tend to latch on to that experience as a fixed reference point from which I can measure my progress. Ultimately I don't justify my work on that website in terms of productivity or utility or page hits or any practical measure of success or failure. For good or for ill, that is my tribe, and my goal is to celebrate them and keep them in contact with each other.

In April I was going to write a story here about how I organized all of the staff rosters from 1965 to 2010. It was going to be an arcane story about the wizardry I performed with MediaWiki, how I linked each staff member to the years they worked at camp, and each year to the staff member who worked there, and each staff member to the various program areas where they worked. It was a maze of wiki templates and taxonomy. It was thorough to the point of being clinically obsessive. It was elegant and massive.

I did the bulk of it in one day. I woke up irritated one Saturday morning, 4am, then worked until 2am transcribing the old rosters to the wiki, then creating individual pages for each staff member.

It felt good to complete it. It felt good to sit down, decide that it was going to be Done, and then do it -- even if it was covered in the strange rime of total social inadequacy that is demonstrated by sitting immobile on a couch for nearly a full day.

The wiki was wonderful, but it was inflexible. To change the layout of the rosters or the individual pages would require changing every... single... page, all one thousand or so pages. What I wanted was all of that information to be stored in a database so that I could mix it whatever way I wanted.

I had no idea how to do this. I needed to break down the information into fields. My first thought was to make this all happen on a single page, that is, that each staff member page would have enough fields to store info about each of their years. The information that needed to be stored for each summer camp consists of a program area, a position, and the year itself. That's only three fields -- not so bad. But someone who worked at camp for 10 years would need thirty fields. Ranger Kevin would need over 60 fields. So this all needed to be decentralized somehow. How?

Then I had an ah-ha moment. Each year at camp was a separate event. One table in the database could be just these events. Each record would have the previous three fields (year, program area, position) plus the name of the staff member in another field. Then the database could be queried to show the records for a certain staff member or a certain year. Now I could deal with a maximum of four fields instead of 60 or more.

This is an intensely dull thing to get excited about. But I'll take it where I can get it.

I created a mockup. I tested it. It worked. And I jumped in for another round of Total Immersion to transfer information from one place to another. Thousands of nodes later I got the job done. I wrote more about that at isrstaff.org/node/2695.

Now I'm done with the structural elements of maintaining the staff history. There remains the task of finding missing rosters, collecting photos, and getting the old I mean former staff to share stories, but this is the fun part. It is a limited history -- limited time, limited place -- but the people and the experiences are rich when you get to know them.


What follows from here is how I set this up in Drupal. It is not interesting to read. I post it here in case someone out there finds it useful.

Setup

Custom content types

The history relies on three custom content types: names; staff records; and pictures. Each of these content types uses the Content Construction Kit (CCK) module to define extra fields.

First, names of all staff members must be added to the database. Names have two fields: first name; last name. Names come first because the the other two custom node types refer to names.

Staff records note the details of one person's experience at one year of summer camp. Staff records contain six fields: name; year; area; position; camp; and sort order.

  • Name. This is a Nodereference field that refers to the Names content type. This associates the staff record with a particular person.
  • Year. The year will do two things: (1) this record will be shown on the corresponding year's roster; (2) this record will be shown in the list of years on a staff member's bio. For example, the staff record of me in Scoutcraft in 1998 will be shown (1) on the 1998 staff roster and (2) on my staff bio.
  • Area. There are different program areas at camp, e.g., aquatics (the pool and lakefront), handicraft (woodcarving, etc.), Scoutcraft (camping, pioneering, orienteering, etc.). Each roster is organized by program area: first the camp administration, then the aquatics staff, and so on.
  • Position. This is the staff member's job for the summer, from counselors in training to assistants to camp director.
  • Camp. This is for future improvements, namely capturing the histories from former Boy Scout camps like Camp Wokanda.
  • Sort. This is an integer that sorts the records on the roster page. The rosters are organized by program areas, each of which has its own hierarchy with directors at the top and assistants at the bottom. Smaller sort numbers rise, larger numbers sink. So, a program area director will be given a low sort number and a program assistant will be given a high sort number.

Finally, there are pictures. Staff can upload photos from camp, which include the following fields:

  • Picture. This is the picture to upload. It relies on the ImageField (and, subsequently, FileField) module.
  • Year. Including the year allows the picture to be shown on the corresponding roster page for that year.
  • Staff. Same as the staff record, this is a Nodereference field that refers to the Names content type. Choosing a staff member here will show the picture on his or her bio.

After creating these three content types I copied and pasted the data from the wiki, creating nearly 1,000 names and nearly 1,500 staff records. This was as much fun as it sounds.

Image setup

An uploaded photo could be large, over 2000 by 3000 pixels, which is too big to be useful in screen displays. I wanted a medium size image to display on screen, plus thumbnails to show on other pages. To accomplish this I installed the ImageCache module, which depends on ImageAPI. ImageCache requires installation of either GD or ImageMagick toolkits. I used ImageMagick because GD tended to choke on the full size picture uploads.

In the ImageCache settings, I created two new settings:

  • Medium. Action: Scale. Settings: 500x500. The original file would be scaled to fit in a 500 pixel by 500 pixel box; the longer edge of the photo would be scaled down to 500 pixels and the shorter edge would be scaled down to match the original aspect ratio of the image.
  • Thumbnail. Action: Scale. Settings: 100x100.

Staff biographies

Staff biography panel, take 1

To display a staff biography, I used Views and Panels. First, from the Panels page manager, I enabled the "node template" page then added a new variant.

  • Title: Staff biography
  • Variant type: Panel
  • Optional features: Selection rules
  • Selection rule: Node: type
    • Node: Node being viewed
    • Node type: Name

What this means is that anytime someone visits a staff biography (remember: a name content type) this panel will be shown. What I want to show on this panel is a staff member's years of experience, pictures, and a text biography.

The text biography is simple. This is the standard "body" of a node. I pull it into the panel via Add content > Node > Node body. I pull in the other two -- years, pictures -- with views.

View 1: bio_years

I called the first view bio_years, which displays years and positions on staff.

Filters

  • Node: Published > Published: Yes. A standard thing -- I only want published nodes shown, not drafts.
  • Node: Type > Operator: is one of > Node type: Staff record. I want this view to only show staff records.

Relationships

  • Content: Name. This is the nodereference field from staff records.

Arguments

  • Node: Nid
    • Relationship: Name. This is the key setting. When someone visits a staff bio, I want only the records related to that particular bio to be displayed. The Nid (node ID) is a unique number for a node. When a staff record is created, the nodereference field refers to a specific Nid. "Relationship: Name" allows only nodes where the Content:Name nodereference field refers to the node being visited.
      For example, my staff bio is located at isrstaff.org/node/102 -- the Nid is 102. On all staff records related to me, the Content:Name refers to Nid:102; so when you visit my staff bio only the staff records referring to node 102 are shown.
      (Maybe it's a bit overwrought to describe this, but it took me a long time to wrap my head around how relationships worked in Views. Once I figured it out, it opened up a world of possibilities. Clearly I am no genius.)
    • Action to take if argument is not present: Display empty text.

Fields

  •  Content: Year.
  • Content: Name.
  • Node: Edit link. If you were a logged in member, you would see beside each record a link to edit that record.
  • Global: Custom text. This field combines the year, name, and edit link into a single line.

Sort criteria

  • Content: Year > Sort order: Ascending. Orders the staff records by earliest year first.

To test this view I used 102 as the argument for Nid. What is displayed is the following, a list of each of the years and positions I worked at camp:

View 2: bio_pictures

The second view, bio_pictures, is similar to the previous view except it will find the uploaded pictures related to a given staff member.

Basic settings

  • Style: Grid
  • Row style: Fields

Filters

  • Node: Published > Published: Yes.
  • Node: Type > Operator: is one of > Node type: Picture.

Relationships

  • Content: Staff. This is the nodereference field that notes the staff members in the picture.

Arguments

  • Node: Nid
    • Relationship: Staff. This shows only pictures related to the bio being displayed.
    • Action to take if argument is not present: Display empty text.

Fields

  • Content: Picture.
    • Format: Thumbail image linked to node. This is the thumbnail created earlier with ImageCache.

This will show, using Nid 102 again, uploaded pictures tagged with my name:

Staff biography panel, take 2

Now we can go back to the staff bio panel and add the views. In a single column format, I add the following content:

  • Views > bio_years
    • Node: NID: Node ID. This is the context selected for the view. This is what sends the Node ID of the node being viewed to the views so that only the relevant person's records are shown.
  • Views > bio_pictures
    • Node: NID: Node ID.
  • Node > Node body. The names also have a text area for further description of the staff member.

And that is how an individual's staff bio is created. Mine looks like this:

Staff rosters

I wanted a page for every year of summer camp from 1965 to 2010, each with a list of the staff and their positions, each with a custom /history/YYYY URL. I did this by creating a custom panel page called staff_years that pulls in two views, staff_years and gallery.

View 1: staff_years

Filters

  • Node: Published > Published: Yes.
  • Node: Type > Operator: is one of > Node type: Staff record.

Relationships

  • Content: Name. This is the nodereference field that connects the staff record to a particular name.

Arguments

  • Content: Year
    • Title: %1 Staff. The title of the page will be set to whichever year is being called, e.g., 1972 Staff.
    • Action to take if argument is not present: Display empty text.

Fields

  • Content: Area.
  • Content: Position.
  • Content: First name.
    • Relationship: Name. Each staff record node has a Content:Name nodereference field that selects from the list of names. Each name node has a field for Content:First name. This field looks for the name that the staff record is related to (i.e., that the nodereference refers to) and then finds the first name entered in that node.
  • Content: Last name.
    • Relationship: Name.
  • Node: Edit link. Users with edit permissions will see a link to edit each record.
  • Global: Custom text. This field combines all of the previous fields on a single line.

Sort criteria

  • Content: Area > Ascending.
  • Content: Sort > Ascending. Sort by hierarchy within the area.

Basic settings

  • Style: HTML list
    • Grouping field: Content: Area. The program areas are a major division in the camp hierarchy. Instead of showing the program area on each line, putting it as a grouping field will use the program area as a sort of header between lists, as shown below.

Using 2005 as an input argument, this is what this view will produce:

View 2: gallery

Basic settings

  • Style: Grid

Filters

  • Node: Published > Published: Yes.
  • Node: Type > Operator: is one of > Node type: Picture.

Relationships

  • Node: Content profile. The website uses the Content profile module for collecting profile information from users. This relationship will find the profile information of the person who created the picture.

Arguments

  • Content: Year
    • Action to take if argument is not present: Display empty text.

Fields

  • Content: Picture.
    • Format: Thumbnail image linked to node. This is the 100 pixel thumbnail defined earlier in the ImageCache settings.
  • Node: Title.
  • Content: First name.
    • Relationship: Content profile. This field looks for the Content profile of the user that uploaded the file, then finds the first name of that profile.
  • Content: Last name.
    • Relationship: Content profile.
  • Global: Custom text. This field combines all of the previous fields.

The finished view, using 2005 again for the argument, looks like this:

Panel

To create a single panel that would serve for all years, I created a placeholder, %year, to be derived from the URL: http://isrstaff.org/history/%year. I assigned the context for the %year argument to be a string.

I added the staff_years and gallery views as content to the panel. In the configuration for both views, I set the context for Content: Year to "Raw string." This means that the year derived from the URL will be used as an argument for the two views.

The end result for the year 2005 can be viewed here: isrstaff.org/history/2005. Or you can view any of the other years at isrstaff.org/history.

Pictures

First -- and I won't explain this because it was an easy view to set up -- there is a gallery that shows all uploaded pictures.

Second, I went back to the Panels page manager and created a variant of the node template for picture content type. In this panel, I added content for:

  • Node > Field: Picture (field_picture) - File. This is the picture itself. The default for the picture content type, before creating the panel, was to display the uploaded picture -- which could be a 3000 pixel wide monster that stretched far off the page. However, when adding this field to the panel, there is an option in the configuration settings called "Field formatter." The default is "Generic files." Switch that to "medium image linked to image" and it will display a nice, neat medium-sized image that will fit in a 500 pixel box as defined earlier in the ImageCache settings.
  • Node > Field group: Picture information in Picture. This containts the fields for the year and tagged staff in the picture.
  • Node > Node body. Description of the picture.

For an example, see this photo of Andy and I.

Add new comment