“Faking” single-entry pages with ExpressionEngine, FieldFrame, and FF Matrix
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 strick 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.
What Is This Place?
Opus is a website masquerading as a blog masquerading as a webzine. It’s where I (Jason Morehead) write about music, movies, art, web design, religion and whatever else interests me at the time (Read More).
Related: I can also be found on Twitter, Facebook, and Flickr.
Hand-Picked Opus
Not sure where to start? Then check out this revolving hand-picked list of some of my favorite articles and reviews.
- Seeing through the eyes of the depraved 6/21/2008
- The Friendly Beasts 12/9/2007
- The Revolutionary Army Of The Infant Jesus 8/18/2006
- Ester Drang Interview 11/3/2005
- Samurai Fiction 7/3/2004
Recent Music Reviews
Recent Movie Reviews
Recent Comments
- Owen Moorhead (no relation) on James Cameron, "Avatar", and Pantheism
- Matt on The Return of Captain EO
- Rocky on "Song of Remembering" by The Rentals
- Jason Morehead on "Song of Remembering" by The Rentals
- Jason on "Song of Remembering" by The Rentals
Friends, Allies & Inspiration
- The Grand
- View from the Prairie Box
- Red Bicycle, Inc.
- Looking Closer
- Arts & Faith
- Filmwell
- Twitch
- Elastic Heart
- Raymonn
- Skoolbus 39
- Something Excellent
- Proj
- Long Pauses
- Firespring
- Andy Whitman
- The Search
- The Hurst Review
- Christ and Pop Culture
- This Is Not Entertainment
- TheoFantastique
- Image Journal
- Flickerings
- Disquiet
- PopMatters
- The War Against Silence
- EE Insider
- Godbit Project
- Smashing Magazine








14 Comments
-
Andy Marshall
1 month, 3 weeks ago
-
Cornelius Bergen
1 month, 3 weeks ago
-
Andy Marshall
1 month, 3 weeks ago
-
John Faulds
1 month, 3 weeks ago
-
John Faulds
1 month, 3 weeks ago
-
Jason
1 month, 3 weeks ago
-
Andy Marshall
1 month, 3 weeks ago
-
Jérôme Coupé
1 month, 3 weeks ago
-
Andy Marshall
1 month, 3 weeks ago
-
Jason
1 month, 3 weeks ago
-
Andy Marshall
1 month, 3 weeks ago
-
Jason Morehead
1 month, 3 weeks ago
-
Boyink
1 month, 2 weeks ago
-
Jason
1 month, 2 weeks ago
Commenting is not available in this weblog entry.I’ve been working on something kinda similar today but with a thickbox being teh result of the clicked thumbnail.
That said, I have used the passing of values via the URL segments to be a very clever way of passing info into pages that then directly affect the content - often with weblog:entries search:{segment_4} for eg.
I do have the same problem tho where you forfeit the option for a 404 page, something that does make me a bit uneasy.
If someone does have a way of fixing this little problem, I would love to see it - I have often wondered about a include/exclude htaccess option where you can specify certain segments as safe…?
I’ve done similar things with using the URL segments as parameter values in weblog tags. When I do I use:
{if no_results}
{redirect=“404”}
{/if}
hmm - very interesting - will give that a go!
Alternatively, you could use the {entry_gallery_title} in your gallery URL (with spaces replaced by - ) and then on the single entry page do search:speaker_confirmed=”{modified_segment_5}”.
It would be a bit more fiddly converting the title into a URI-friendly format and then back again for the search parameter, but it would give SEO-friendlier URLs.
Oops, sorry, copied the search parameter code from the Fieldframe docs; should’ve been search:entry_gallery_title=”{modified_segment_5}”.
@Andy: I’ve used the technique that Cornelius mentions a couple of times, and it works really well. More info here.
@John: You’re right, that would work, if the client wants a more SEO-friendly title than just a numeric ID. You’d probably have to add two columns to the matrix, one for “title” and one for “URL title”, though, and do this:
search:entry_gallery_url_title=”{segment_5}”
Cool - thanks for that - will drop that into their site today :)
Did something similar a while ago ...
http://expressionengine.com/forums/viewthread/113020/
... but I never thought of using the offset parameter in that way. Very clever. Thank you
A bit OT, but I’ve tried getting the redirect=“404” into a entry template, and whether strict URLs are on or off, its just displaying the closest page it can figure out based on what is in the URL, so I’m not even getting close to redirecting to a 404 page.
hmm.
@Andy: Are you putting the {if no_results} conditional inside your {exp:weblog:entries} tags?
I am indeed.
But regardless of the redirect=“404”, even with Strict URLs on to point to the 404 page, a URL like domain.com/blog/entry/nonsensical_title_njknknk is still taking me to blog pages, not a 404 page.
simlarly, domain.com/blog/ent is taking me to the blog index template.
@John: Do you have the “require_entry” parameter in your {exp:weblog:entries} tag set to “yes” (more info)?
I must say..it’s odd to be on the receiving end of an EE tut - but thanks for this one as I used on a client site I’m currently building.
@Boyink: No problem. I guess there’s a first time for everything! :)