How To Create A Social Review Site

ADDING EXTRA FIELDS -- Review Foundry Tutorial 04

Adjust Text:  a a a a
« Review Foundry User Manual   |   Tutorial Table Of Contents   |   Obtain Review Foundry »


ADDING EXTRA FIELDS

Definition of a Field

The topic of discussion in this section is member fields. In particular, how to go about adding new member fields to the default ones available at installation. Once again, this discussion borrows from another tutorial--namely, How To Create An Adult Review Site, where in addition to the re-iterated discussion on image fields found in the current tutorial, details were presented on how to go about adding Age, Location, and Likes/Dislikes fields. To recap, the Age field was a special DATE column type that actually stored the member's birth date and then converted it to an age in years before presenting it. The other two fields were VARCHAR and TEXT column types, which are used when you wish to let the member describe some aspect of themselves by typing in a bunch of characters. Other useful column types for describing aspects of a member are the ENUM column type, which allows the member to pick from a list of mutually incompatible choices, and the SET column type, which allows them to pick an assortment of describing features from a list. Both these were discussed in How To Create A Graphic Artist Review Site. Because the ENUM column type is so useful, we'll see another example of it discussed here, when we set up a Gender field (man/woman). We will also see how a special Zipcode field can be added, which will allow members to search for other members based on their proximity to a supplied zipcode. In other words, if you live in New York at zipcode 01001 and want to find other members with 10 miles of your location, you'll be able to do that.

The Member table has several standard fields to characterize each member: name and full_bio being the two most important ones. Each field represents a column in the table. Other standard fields include the member avatar_image (actually a foreign key into another table that stores information about the associated image), a member_image (another foreign key), and a url for a member homepage. But like most webmasters, Kyla has ideas for additional fields she wants to put in. Not all of them need to appear on the member detail pages, but some might be appropriate there. This also applies to the Member Profile page--in order for added fields to appear, Template Toolkit tags need to be explicitly added to handle them. Review Foundry will allow Kyla to add as many fields as desired, and offers a range of "field types" that facilitate the integration of data into the page. A discussion of how to add extra fields (columns) to an existing Review Foundry table is treated in detail in the Review Foundry User Manual. See the section on ADDING COLUMNS TO A TABLE.

Gender Field (ENUM column, SEEKER form type)

As we saw in the Favorite Period field example of the tutorial How To Create A Graphic Artist Review Site the ENUM column type is easy to set up and provides for unambiguous responses from the member--they have to choose from a provided list of possibilities. In this case Kyla will be creating a special type of ENUM column, known as a SEEKER. In fact SEEKER refers to the Form Type attribute that is attached to each field. The property of SEEKER column (which should only be used with the Member table) is that is allows users to seek out members of one type who wish to be found members of another type. In Kyla's case we will assume she wishes to account for 6 possibilities (allowing us to see how this works in a realistic scenario). Kyla would like her members to categorize themselves as one of the following: Man seeking a Woman, Man seeking a Man, Man seeking Anyone, Woman seeking a Man, or Woman seeking a Woman. Woman seeking Anyone. The rules for constructing this list of possibilities are simply these:

  • Elements of the list should be of the form A seeking B, where the first and last non-whitespace-containing strings represent two possible seeker types A and B, and the intervening text separating the types (here " seeker ") is irrelevant. You can think of the separating text as an arrow pointing from one seeker type to the other.
  • If the element A seeking B is present in the list, then the "reciprocal element" B seeking A should also be present. The exception is the A seeking Any form (the word "Any" or "Anyone" is a special seeker type representing ALL seeker types), which does not have an explicit reciprocal element. Note that B seeking B is its own reciprocal and should appear only once in the list. A list can thus have either an odd or even number of elements depending on whether or not it contains self-reciprocal elements.

In regards to the second requirement of Kyla's list, if Woman seeking Anyone is present, it means the member wishes to be found by any other member seeking a Woman regardless of whether they themselves are a Man or a Woman.

These choices will appear on the page, when the member is editing their Profile, as a drop down SELECT menu. Here is the form Kyla fills out when she adds the Gender column:

ENUM Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

VARCHAR Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

Once the field is added it will appear something like this on the Edit Page for the Member Profile:

Gender  

The addition of a table row to the member_data.ttml template allows the Gender field to show within a Member Profile:


	[%# this table row would appear in the PERSONAL INFORMATION SECTION of member_data.ttml %]

		[% column = member_def.cols.gender %]

	<tr><td align="right"
		style="background: [% cell_dark %];
			border-right: 1px solid [% border_color %]" nowrap>
			<b><!-- setfont_base(+0) -->
			[% column.form_display %]:
			<!-- setfont_end --></b> &nbsp;
		</td>
		<td colspan="2" style="background: [% cell_pale %]">
			<!-- setfont_base(+0) -->
			[% member.gender || unknown %]
			<!-- setfont_end -->
			</td></tr>

Age Field (DATE column, DATE_SEEKER form type)

We saw how to add an Age field in the tutorial How To Create An Adult Review Site. However, in this instance Kyla wants something slightly different. Instead of just displaying a member's age on their Member Profile page, she wants to allow users searching for members to be able to specify the range of ages associated with members who tyurn up in a search. As we shall see, this extra functionality can be achieved simply by choosing the correct Form Type attribute when creating the Age field.

As discussed in How To Create An Adult Review Site: ADDING EXTRA FIELDS: Age Field Kyla needs to record the date of birth of the member so that the member's age can then be calculated accurately each year. Thus, a field named Date of Birth will be added. As in the previously discussed tutorial, the column will be of DATE type, but the Form Type shall not be DATE_SELECTABLE, but DATE_SEEKER. The difference will be discussed shortly. When Kyla goes to add the column to the Member table the filled out form should look like the following:

DATE Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

DATE Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

Had Kyla selected a Form Type of DATE_SELECTABLE, instead of DATE_SEEKER, the column behavior would otherwise be identical but for the fact that nowhere on the search form would the user be presented with a form element to restrict search results by the members age.

Also, because the new column will assist with searches, it is ESSENTIAL to add an index to the column, which Kyla can do by clicking on the Add Key link found at the bottom of the page, and setting up an index with the following parameters:

Key Name: dobndx
Key Type: INDEX
Key Definition: date_of_birth

When the Date of Birth column has been added with a DATE_SEEKER form type the form element used to specify a birth on the Member Profile page will appear like this:

* Date of Birth  
year month day

But of more interest to us right now is the extra form element that appears on the search page for members. Because now Kyla gets an age restriction form element:

Between  
and years of age

Now a member can restrict their search to, say, Women between the ages of 22 and 40, who are looking for Men. To adjust the possible age values appearing in form above, Kyla can go to the admin panel Configuration > Search and make the adjustment.

Once new columns have been added to the Member table additional code needs to be added to the public templates in order to display the data. In order to do this correctly Kyla will need to understand how the Review Foundry templating system works. In particular, because she wishes to display the age of a member on Member Profile pages, and not their date of birth, a little fiddling will be necessary within the templates. But THE TEMPLATE-TOOLKIT, the underlying mechanism by which data is translated into HTML in Review Foundry templates, is very powerful, and allows tasks like this to be performed with relative ease. In this case, Kyla might add the following code to the relevant template (say member_page_top.ttml or member_page_more.ttml which are used to construct the topmost and subsequent detail pages for a member) in order to display the member's age:


	[%# assuming that alias.member_info is passed into the template... %]

	[% member = alias.member_info %]

	[% year_of_birth = member.date_of_birth.split('-').shift %]

	[% USE date %]
	[% year_now = date.format(date.now,'%Y') %]

	<p><b>Age:</b> [% year_now - year_of_birth %]

What has been done here is to use the date module from Template Toolkit to calculate the current year, and then subtract from it the year in which the member was born to obtain their age. The year of birth is obtained by splitting the date of birth (in the format yyyy-mm-dd) on the delimiter '-', and then taking the first element by shifting it off the resulting stack of numbers.

Note: when dealing with templates, the first step is to locate the template responsible for handling the portion of HTML you intend to affect. To do this, try looking in the HTML source code of the page that your browser is showing. Each public template identifies itself by inserting comments at the top and bottom of the template, such as <!-- begin: member_page_top.ttml --> and <!-- end: member_page_top.ttml -->. So if you are looking at the detail page for a member you will discover that the member_page_top.ttml template contains the HTML that Kyla would likely want to modify when inserting extra fields for display. The template will have a section of code (near the top) that assigns the passed-in fields to a local variable, such as member in the code shown above. All Kyla has to do now is add a conditional statement for displaying the value of the relevant column.

In addition to adding template tags to handle displaying the member's age on detail pages (where reviews appear), there is also the Member Profile page too. To have the member's age appear there, Kyla would need to add code like this:


	[%# this table row would appear in the PERSONAL INFORMATION SECTION of member_data.ttml %]

		[% column = member_def.cols.date_of_birth %]

	<tr><td align="right"
		style="background: [% cell_dark %];
			border-right: 1px solid [% border_color %]" nowrap>
			<b><!-- setfont_base(+0) -->
			[% column.form_display %]:
			<!-- setfont_end --></b>  
		</td>
		<td colspan="2" style="background: [% cell_pale %]">

		[% formatted_value = '' %]
		[% IF member.date_of_birth %]
			[%# format as, say: July 12, 1975 %]
			[% year_month_day = member.date_of_birth.split('-') %]
			[% year_of_birth  = year_month_day.shift %]
			[% month_of_birth = year_month_day.shift - 1 %]
			[% day_of_birth   = year_month_day.shift %]
			[% month = global.skin.date_months_of_year.$month_of_birth %]

			[% formatted_value = month _ ' ' _ day_of_birth _ ', ' _ year_of_birth %]
		[% END %]

			<!-- setfont_base(+0) -->
			[% formatted_value || unknown %]
			<!-- setfont_end -->
			</td></tr>

There are a lot of possibilities inherent in the treatment of pulled data when using Template Toolkit to handle the data formatting. Studying the Template Toolkit in order to harness this extra flexibility is entirely optional, of course.

Musical Tastes Field (VARCHAR column)

To record the musical tastes of a member--a subject too broad to capture as with sometime like a SET column--Kyla needs to provide a textarea form input and a TEXT column to store the information, use of which allows up to 64K in character data. The columns to be added is therefore of the same type as the full_bio column. Here is how the musical_tastes column is created:

TEXT Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

TEXT Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

In this case Kyla has elected to have the Musical Tastes field be optional (the Not Null attribute has not been set) so that the musical tastes of a member need not be supplied each time the record for the member is edited. Additionally, Kyla has specified a Search Weight of 1 for the field. This means that the field will be indexed, with a weight of 1, and terms appearing in the Musical Tastes field will help power the search engine. Thus, if a member likes "red hot chili peppers", a search for either of the terms "red hot" or "chili peppers" should bring her up in the results. It is a good idea, however, not to go overboard and index every text column in sight, as search engine indexes take up memory in your database tables. One last note: in specifying that a TEXTAREA form element be used to collect the data, the size of the form element also needs to be specified--in this case, 40 columns and 3 rows (the two numerical terms being separated by a comma in the Form Size/Length attribute).

When the Musical Tastes column has been added it results in a new form element that looks like the following:

Musical Tastes:  

Once again, the addition of a table row to the member_data.ttml template allows the Musical Tastes field to show within a Member Profile:


	[%# this table row would appear in the PERSONAL INFORMATION SECTION of member_data.ttml %]

		[% column = member_def.cols.musical_tastes %]

	<tr><td align="right"
		style="background: [% cell_dark %];
			border-right: 1px solid [% border_color %]" nowrap>
			<b><!-- setfont_base(+0) -->
			[% column.form_display %]:
			<!-- setfont_end --></b> &nbsp;
		</td>
		<td colspan="2" style="background: [% cell_pale %]">
			<!-- setfont_base(+0) -->
			[% member.musical_tastes || unknown %]
			<!-- setfont_end -->
			</td></tr>

We suppose, in all reasonableness, that Kyla would NOT want to clutter up the member detail page with the Musical Tastes information, so there is no need to add tags to the detail page templates, member_page_top.ttml and member_page_more.ttml. That information can always be found on the member profile page, which is the characterizing page for a member. Detail pages are meant to be intermediate summary pages that carry reviews.

Zipcode Field (INT column, ZIPCODE form type)

In order for members to search for other members geographically located within a specified number of miles of a given U.S. zipcode (usually the zipcode at which the member is located) Kyla needs to add a Zipcode column with the special property that its Form Type is ZIPCODE. This field obviously will only be useful if a significant number of members are located in the U.S. and actually supply a value when filling out their member profile. So if Kyla was setting up a website that served a London-based membership she would have little reason to add a Zipcode column. We suppose that is not the case and that, at least in Kyla's case, the majority of members served will be U.S.-based.

Upon installation of the Review Foundry distribution, and provided that you downloaded the zipcode table data before installing (from http://www.randommouse.com/cgi-bin/rms/product/obtain/obtain_zipcodes.cgi), your zipcode tables will allow zipcode searching out to a range of 10 miles from a given zipcode. This allows you to test the feature without having to populate you zipcode tables with a large record set that is unnecessary if you will not be offering zipcode searches. For customers who have purchased a key, an extra script will be provided on demand so that you can extend this zipcode-based searching out to a distance of up to 100 miles.

When a Zipcode field is added to the Member table, member-based searches will acquire an advanced search form element that looks something like the following, allowing the results to be restricted to "nearby" zipcodes:

LOCATION
Include results within:   of zipcode

Kyla could make the Zipcode column a mandatory field by specifying that the Not Null attribute be set to Yes. In that case a member would be unable to save any changes to their member profile UNLESS they also specified a 5-digit zipcode for the Zipcode field. But unless you have a very good reason to force members to supply a zipcode, it is better to leave this as an optional field (as shown below). The form of the regular expression used to check the zipcode field allows for an empty value, otherwise Kyla might have used ^\d{5}$ (i.e. value must match exactly 5 integers) as the value of the regular expression attribute.

ZIPCODE Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

ZIPCODE Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

Because Kyla is adding the Zipcode column in order to enable zipcode-based searches, it is important to add an INDEX on the Zipcode column to make searches efficient. To do this she clicks on the Add Key link found at the bottom of the page after she has added the column. She then elects to add a key using the following parameters:

Key Name: zipcdndx
Key Type: INDEX
Key Definition: zipcode

When the Zipcode column has been added it results in a new form element that looks like the following:

Zipcode:  

There is probably NO need to place the member's zipcode on their member detail page (as it can be found in the member profile), but if you did, you would use something like the following in member_page_top.ttml and member_page_more.ttml:


	[% member = alias.member_info %]

	Zipcode: [% member.zipcode %]

In the member_data.ttml template used in the construction of the Member Profile the template code would look like this:


	[%# this table row would appear in the PERSONAL INFORMATION SECTION of member_data.ttml %]

		[% column = member_def.cols.zipcode %]

	<tr><td align="right"
		style="background: [% cell_dark %];
			border-right: 1px solid [% border_color %]" nowrap>
			<b><!-- setfont_base(+0) -->
			[% column.form_display %]:
			<!-- setfont_end --></b>  
		</td>
		<td colspan="2" style="background: [% cell_pale %]">

			<!-- setfont_base(+0) -->
			[% member.zipcode || unknown %]
			<!-- setfont_end -->
			</td></tr>

Location Field

Although Kyla has added a Zipcode field, form which one might assume that the corresponding location can be inferred, there is a good reason to add a separate Location field to any table that contains a Zipcode field. The reason is that the same 5-digit zipcode can be shared by many different (neighboring) cities. Therefore, it is not possible to look up a unique city name given a 5-digit zipcode value. Review Foundry will nonetheless do a city look up and return the first city name it finds if it has no other information to go on. But if there happens to exist a column with the name location in the same table, it will assume that this is a city, or place name, and use that instead. Therefore, when you add a Zipcode field, it is a good idea to also add a Location field, so that the person filling in the record can provide an unambiguous value for the location.

For this, Kyla uses a VARCHAR column of 255 character maximum (though perhaps 64 characters would be quite sufficent too):

VARCHAR Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

VARCHAR Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

Note that the VARCHAR column type can be used to record all sorts of characteristics easily captured as short strings of free form text, such as email addresses, favorite quotes, and so on. Longer strings are better suited to the TEXT column type, as discussed in the next section. When the Location column has been added with a TEXT form type it will result in a new form element that looks like the following:

* Location  

Adding a suitable Template Toolkit tag to the public templates to display the value of the Location field in the member_page_top.ttml or member_page_more.ttml templates is as simple as this:


	[%# assuming that alias.member_info is passed into the template... %]

	[% member = alias.member_info %]

	Location: [% member.location %]

Or in the member_data.ttml template used in the constrcution of the Member Profile:


	[%# this table row would appear in the PERSONAL INFORMATION SECTION of member_data.ttml %]

		[% column = member_def.cols.location %]

	<tr><td align="right"
		style="background: [% cell_dark %];
			border-right: 1px solid [% border_color %]" nowrap>
			<b><!-- setfont_base(+0) -->
			[% column.form_display %]:
			<!-- setfont_end --></b>  
		</td>
		<td colspan="2" style="background: [% cell_pale %]">

			<!-- setfont_base(+0) -->
			[% member.location || unknown %]
			<!-- setfont_end -->
			</td></tr>

Image Fields

Finally, Kyla intends to allow members to attach up to 6 images to their profile These will be displayed in a single row across the page beneath the other member fields, and before any reviews that might also be displayed on the member's detail page. These images will be clickable thumbnails that pop up the full-size images. Noting that the default setup includes an image field represented by the column named member_image, Kyla calls the next image column added member_image_02 and creates it with the following column specifications:

IMAGE Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

IMAGE Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

The interesting thing to note here is that the image is represented by an INT, or integer, column type. In fact, the actual image, and its thumbnail will NOT be stored within any table. But the integer value assigned to the image--which is stored in the file system--acts as an identifier for both the image and its thumbnail (if it has one). The integer is actually used as a PRIMARY KEY into the Upload table, so it should be a positive integer. That is why it has been specified as an UNSIGNED (non-negative) integer. Also, to allow any number of images to be added or removed, the field has its Not Null attribute set to No (so that these extra images are optional).

For the Form Type, Kyla has selected PUBLIC_IMAGE. What this means is that the field will be recognized internally by Review Foundry as one that represents an image, and various operations will be performed to store and then serve up the image. A "public image" is one that is considered to be viewable by anyone perusing the detail pages, regardless of whether or not they happen to be a member of the site.

It is also worth mentioning that the convention used for naming the image columns determines the default order in which they are placed on the page. The default rule is that images are sorted alphabetically on the column names. This is done inside a special template, named member_gallery.ttml, so if Kyla wanted more control over how the images (thumbnails actually) were placed on the page, that is the template she would customize. After adding the first such image column she goes back and repeats the process for the columns member_image_03 to member_image_07 (i.e. a total of 6 extra images).

The image columns have now been added, but there is perhaps one thing missing. A caption, or title, for each uploaded image. To add an image title which will appear beneath the thumbnailed image, Kyla adds a VARCHAR(32) column of the following type (the length of the string held by the column could be any number up to 255, but 32 is generally enough for a short descriptive title):

IMAGE TITLE Column Properties

Column Name

 

Column Type

 

Column Size/Precision

 

Column Values

 

Attributes

 

Not Null

 

Yes No

Extra

 

An AUTO INCREMENT column already exists

Column Position

 

Default

 

Search Weight

 
 

IMAGE TITLE Form Properties

Form Display

 

Form Type

 

Form Size/Length

 

Form Values

 

Form Regex

 

Hide on Add/Modify Forms

 

Yes   No

The choice of the column name is NOT arbitrary. The name of a column that represents the title of an image column MUST be the same as the name of the image column, but with the suffix '_title' appended to the end of it. Thus if member_image_02 is the name of the image column, the corresponding image title column, if it is defined, should be member_image_02_title. The Not Null attribute should be set to No for titles because the images are optional, thus the titles should be as well.

When the Image 2 and Image 2 Title columns have been added they result in new form elements that look like the following (shown in the state after an image has been uploaded):

Image 2:  
  kitchen.jpg
Image 2 Title:  

Gallery Presentation

Once extra images are available for presentation, these will automatically be formatted and displayed on the member detail page as tiled thumbnails, complete with an image title if one has been provided. The number of thumbnails displayed per row, and the separation distance between the table cells that contain individual images are configuration variables that can be adjusted on the Browse / Build page of the Configure area. The two variables are browse_member_thumbnails_per_row and browse_member_thumbnail_spacing. If Kyla wanted finer control over the formatting of the images she would directly edit the member_gallery.ttml template, which contains the code for tiling the images horizontally. If she wanted to tile them vertically, or add a border to the table cells, or do anything related to the positioning of the thumbnails, then this would be the place to start. Another thing she might want to do is ensure that thumbnails are all scaled to, say, exactly 100 pixels in height. To do that she would consult the Thumbnails page of the Configure area, where thumbnailing options are handled, including the choice of the image manipulation library to be used to scale the images. Possibilities include Image Magick, GD, and the NetPBM executables. A fuller discussion can be found in the User Manual on the Thumbnails page.

Summary

So let's recap. Kyla has added extra fields to handle Gender, Date of Birth and Zipcode, as well as 6 extra Images. Shown below are the new form elements as they might appear on the edit page for the member stacy:

* Gender  
* Date of Birth  
year month day
* Location  
Zipcode:  
Musical Tastes:  
Image 2:  
  kitchen.jpg
Image 2 Title:  
Image 3:  
  portrait.jpg
Image 3 Title:  
Image 4:  
  table.jpg
Image 4 Title:  
Image 5:  
  washline.jpg
Image 5 Title:  
Image 6:  
Image 6 Title:  
Image 7:  
Image 7 Title:  

The final result of Kyla's efforts are member detail pages which look like this one.

Next Section: VIEWING A MEMBER

« Table of Contents


Copyright © 2004 Random Mouse Software. All Rights Reserved.