“Faking” Single-Entry Pages With ExpressionEngine, FieldFrame, and FF Matrix

This adds some very cool and useful flexibility and functionality to ExpressionEngine sites.

Earlier this year, Brandon Kelly released FieldFrame, and it’s quickly become one of the more popular and useful add-ons for ExpressionEngine — in my opinion, anyways. In Kelly’s own words, “FieldFrame is a framework for rapid development of fieldtype extensions in ExpressionEngine.” If FieldFrame is installed, you can add new custom weblog fieldtypes to use with your EE weblogs, including WYSIWYG editors, region select menus, Google maps, file upload fields, and finally, data matrixes.

What’s a data matrix, you ask? Think of a spreadsheet: each row in the spreadsheet represents a specific entry and each row is divided into columns that represent the different pieces of data for the entries. If you have a “staff” matrix, each row in the matrix represents a staff member, and each of the row’s columns represents a piece of information about the staff members (e.g., name, title, e-mail address, photo).

FieldFrame’s FF Matrix fieldtype allows you to add data matrixes to your weblog entries, giving you a whole new level of flexibility when it comes to managing your site’s content. You can use it to manage many different types of content — staff bios, product catalogs, event listings — but for the purposes of this entry, I’ll be discussing it within the context of entry galleries (i.e., image galleries that are specific to individual weblog entries).

Getting Started

There are already several tutorials that explain how to use FF Matrix and set up entry galleries, so I won’t spend a lot of time explaining how you do this.

I’m going to assume that you’re already using FF Matrix to set up a entry galleries, and that when a user clicks on an image in the gallery, you want the full-size image to appear on a new page (as opposed to having the image appear in a pop-up window or JavaScript “lightbox”). In this situation, you’ll need to “fake” EE’s single-entry view (as opposed to an “archive” view, which displays multiple entries on the same page).

Here’s our basic set-up:

  • We are, of course, running the latest versions of ExpressionEngine and FieldFrame. I have installed the nGen File Field fieldtype for FieldFrame. And finally, I’ve also installed Lumis’ very handy Image Sizer plugin, which lets me resize images “on the fly” (which is very handy for generating thumbnails.
  • We’ve got a weblog (“blog”) that contains the following custom weblog fields: “Summary,” “Body,” “Extended Text,” and “Entry Gallery.” The first three are textareas and “Entry Gallery” is an FF Matrix field.
  • The “Entry Gallery” field contains the following columns: “Image” (nGen File Field), “Title” (text input), “Description” (textarea).
  • We have a template group (“blog”) that contains two templates: “index” (which is used for multi-entry/archive pages) and “entry” (which is used for single-entry pages). For this tutorial’s purposes, we are only concerned with the “entry” template.

The Initial Template

On the “entry” template, we have the following EE code, which is used to render the content of a single entry:

{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}

	<h1>{title}</h1>

	<p>Posted on {entry_date format="%m/%d/%Y"}</p>
	
	{body}
	
	{extended_text}
	
	{entry_gallery}
	
		{if "{row_count}" == "1"}
			<ul>
		{/if}
		
		<li>
			<a href="/blog/entry/{url_title}/image/{row_count}/">{exp:imgsizer:size src="{entry_gallery_image}" width="50" height="50" alt="{entry_gallery_title}" quality="90"}</a>
		</li>
		
		{if "{row_count}" == "{total_rows}"}
			</ul>
		{/if}
	
	{/entry_gallery}
		
{/exp:weblog:entries}

I’ve got my weblog entries tag and I’m displaying the contents of the “Body” and “Extended Text” fields, followed by my “Entry Gallery” field. I’m using the FF Matrix tag pair for {entry_gallery} to create an unordered list that contains the images in this entry’s gallery. I’ve given each image in the gallery a link that is based on the entry’s URL title and the ID of each image, which is based on their row in the matrix. And finally, I’m using the Image Sizer plugin to create thumbnails of each image, based on the {entry_gallery_image} column in my matrix.

If I were to view the HTML source of this entry, my image URLs would look something like this:

<ul>
	<li>
		<a href="http://domain.com/blog/entry/my-weblog-entry/image/1/"><img src="/images/uploads/1.jpg" alt="" width="50" height="50" />
	</li>
	<li>
		<a href="http://domain.com/blog/entry/my-weblog-entry/image/2/"><img src="/images/uploads/2.jpg" alt="" width="50" height="50" />
	</li>
	<li>
		<a href="http://domain.com/blog/entry/my-weblog-entry/image/3/"><img src="/images/uploads/3.jpg" alt="" width="50" height="50" />
	</li>
</ul>

In the above URLs, “my-weblog-entry” is the entry’s URL title and the number at the end of each URL corresponds to the row ID for each image in the matrix. Now that I have my URLs, I can take advantage of EE’s URL segment parsing to create my “fake” single-entry pages. But first, I’m going to modify this template’s preferences to allow PHP parsing and set the “Parsing Stage” to “Input” (more info here and here).

Enter the Conditional

Once that’s done, I modify the code in my “entry” template to use a conditional:

{if segment_4 == "image"}
	
	{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}
	
	{/exp:weblog:entries}

{if:else}

	{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}

		<h1>{title}</h1>

		<p>Posted on {entry_date format="%m/%d/%Y"}</p>
	
		{body}
	
		{extended_text}
	
		{entry_gallery}
	
			{if "{row_count}" == "1"}
				<ul>
			{/if}
		
			<li>
				<a href="/blog/entry/{url_title}/image/{row_count}/">{exp:imgsizer:size src="{entry_gallery_image}" width="50" height="50" alt="{entry_gallery_title}" quality="90"}</a>
			</li>
		
			{if "{row_count}" == "{total_rows}"}
				</ul>
			{/if}
	
		{/entry_gallery}
		
	{/exp:weblog:entries} 

{/if}

The conditional is based on the fourth URL segment ({segment_4} in EE’s parlance). Essentially, the conditional checks to see if the fourth URL segment is “image.” If it is — which it will be if someone clicks on one of the entry gallery links — then the contents of the first part of the conditional will be rendered by EE. Otherwise, EE will just assume the user is trying to see the actual blog entry and it will render the second part of the conditional.

Now we’re going to focus on the first part of the conditional, the part that handles the single-entry page for our FF Matrix. Remember that earlier, we set up PHP parsing for our template: this is where that comes into play.

{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}

	{entry_gallery offset="<?php echo("{segment_5}"-1); ?>" limit="1"}
	
		<p>
			{exp:imgsizer:size src="{entry_gallery_image}" width="640" height="480" alt="{entry_gallery_title}" quality="100"}
		</p>
		
		<p>
			{entry_gallery_title}
		</p>
		
		<p>
			{entry_gallery_description}
		</p>
		
	{/entry_gallery}
	
{/exp:weblog:entries}

My {entry_gallery} tag pair makes another appearance, but this time, it has two parameters: “offset,” which tells FieldFrame to skip a certain number of rows in the matrix, and “limit,” which tells FieldFrame how many rows in the matrix to return.

I’m using PHP to set the “offset” parameter: it’s whatever value is in the fifth URL segment (which, if you’ll remember, contains the row ID of the image) minus one; and I’ve set the “limit” parameter to “1,” since I only want to display one row, or one image.

The Final Template

Here’s the complete template:

{if segment_4 == "image"}
	
	{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}

		{entry_gallery offset="<?php echo("{segment_5}"-1); ?>" limit="1"}
	
			<p>
				{exp:imgsizer:size src="{entry_gallery_image}" width="640" height="480" alt="{entry_gallery_title}" quality="100"}
			</p>
		
			<p>
				{entry_gallery_title}
			</p>
		
			<p>
				{entry_gallery_description}
			</p>
		
		{/entry_gallery}
	
	{/exp:weblog:entries}

{if:else}

	{exp:weblog:entries weblog="blog" dynamic="off" url_title="{segment_3}"}

		<h1>{title}</h1>

		<p>Posted on {entry_date format="%m/%d/%Y"}</p>
	
		{body}
	
		{extended_text}
	
		{entry_gallery}
	
			{if "{row_count}" == "1"}
				<ul>
			{/if}
		
			<li>
				<a href="/blog/entry/{url_title}/image/{row_count}/">{exp:imgsizer:size src="{entry_gallery_image}" width="50" height="50" alt="{entry_gallery_title}" quality="90"}</a>
			</li>
		
			{if "{row_count}" == "{total_rows}"}
				</ul>
			{/if}
	
		{/entry_gallery}
		
	{/exp:weblog:entries} 

{/if}

Here’s how it all fits together. The user comes to a blog entry that contains an entry gallery (e.g., “my-weblog-entry”). The user clicks on the third image in the entry gallery, whose URL looks like this:

http://domain.com/blog/entry/my-weblog-entry/image/3/

EE detects that the fourth URL segment is now “image,” so it renders the first part of the above conditional. (EE knows which blog entry to render because we’re using the {exp:weblog:entries} tag’s “url_title” parameter and we’ve set it to the third URL segment.)

The {entry_gallery} tag pair’s “offset” parameter is set to “2” — which it gets via the PHP code that subtracts one from the fifth URL segment — thus skipping the first two rows (or images) in the gallery, and its “limit” parameter is set to “1,” which keeps it at the third row, thus returning the information for the third image.

The third image’s information is displayed via the column names (“{entry_gallery_title},” “{entry_gallery_description}”). Also, note that I’m once again using the Image Sizer plugin to resize the image to 640x480, to ensure that it fits comfortably within my design.

Conclusion

I’ve used this technique on several sites, and it works quite nicely, due to the flexibility of FieldFrame and the FF Matrix fieldtype. If the site administrator wants to reorder the images in an entry gallery, they can do so by simply reordering the matrix’s rows in their control panel. The URLs will then automatically resort as well, since they are being dynamically generated by the matrix.

The only major downside that I’ve encountered so far — aside from the potential security risk posed by enabling PHP in the “entry” template — is that this can throw a bit of a monkeywrench into the works with regards to strict URLs.

Say you only have three images in an entry gallery and the user changes the URL in an attempt to see a fourth image, then nothing is returned; they’ll just see a blank space where the “single-entry” content appears for the valid URLs. Technically speaking, though, this should trigger a 404 error, since the URL isn’t associated with any content. However, since a valid URL title exists within the URL, it could be argued that the URL is associated with some content, the initial weblog entry.

If that’s the sort of thing that sticks in your craw, then you may want to avoid this technique. Better yet, if you think of a workaround for this, let me know and I’ll update this article. Otherwise, I’ve found that this adds some very cool and useful flexibility and functionality to EE sites.

Enjoy reading Opus? Want to support my writing? Become a subscriber for just $5/month or $50/year.
Subscribe Today
Return to the Opus homepage