Creating list and detail portfolio pages in Perch

I recently re-designed my portfolio website as it was in need of a polish and a new lick of paint. Early on I decided to use a brilliant little CMS called Perch to power the backend. I’m a big fan of Perch as it doesn’t dictate the design of your site, it keeps things simple and is easy to use.

I really wanted to have a portfolio page on my site with all my latest projects listed, and have a separate page for each project with notes and screenshots.

In this tutorial I will show you how to set this up with Perch using a multiple-item content region.

You’ll need two templates, one for the detail view of the project and one for the image and title on your portfolio listing page.

Detail template

The detail template is the one that’s used for editing. It needs to include fields for all the information you want to appear in the edit form. It is used for the detail page when we clicks through from a listing. Here we have a single project. Save this as portfolio_detail.html in /perch/templates/content

<h1><perch:content id="title" type="text" label="Portfolio title" required="true" title="true" /></h1>
<perch:content id="desc" type="textarea" label="Description" markdown="true" editor="markitup" />
<perch:content id="slug" for="title" type="slug" suppress="true" />
<perch:content id="image" type="image" label="Image" width="100" height="100" crop="true" suppress="true" />

The slug field makes a URL friendly version of the title when linking to the detail page.

List template

List template

The following code is what you need in your list template. Save this file as portfolio_listing.html in /perch/templates/content

     <a href="?s=<perch:content id="slug" type="slug" />">
            <perch:content id="image" type="image" width="400" height="300" crop="true" output="tag" />
     <h3><a href="?s=<perch:content id="slug" type="slug" />"><perch:content id="title" type="text" /></a></h3>

You’ll notice my images are 400x300px but you can set whatever values you’d like for these.

What I also wanted to do was have a link to the next project on each detail page so the user could quickly navigate to my next portfolio piece without going back to the listings page. This can be done with some simple filtering and ordering using perch_content_custom().

Navigate to next project

Create a new page called portfolio_prevnext.html also saving it in /perch/templates/content and add the following code.

<perch:if exists="is_prev">Previous project<perch:else /><strong>Next project</strong></perch:if>
        <perch:content id="image" type="image" width="150" height="100" crop="true" output="tag" />
        <a href="?s=<perch:content id="slug" type="slug" />">
            <strong><perch:content id="title" type="text" /></strong>

Creating the page

Now you need to create the page. Call it portfolio.php and use the following code as a starting point.

<?php include('perch/runtime.php'); ?>
<!doctype html>
<html lang="en">
    <meta charset="utf-8" />

We next need to add some logic to the page to decide whether to show list mode or detail mode. what we are saying here is if s=something is set on the query string, we want to show the detail mode, otherwise, we will show our list mode. You’ll also see a reference to our portfolio_nextprev.html and that we order it in ascending order with a count of 1.

if (perch_get('s')) {
     // Detail mode
    $result = perch_content_custom('Portfolio', array(
          'template' => 'portfolio_detail.html',
          'filter' => 'slug',
          'match' => 'eq',
          'value' => perch_get('s'),
          'count' => 1,
          'skip-template' => true,
          'return-html'   => true,      
echo $result['html'];
    perch_content_custom('Portfolio', array(
            'template'   => 'portfolio_prevnext.html',
            'filter'     => '_order',
            'match'      => 'gt',
            'value'      => $result[0]['_sortvalue'],
            'sort'       => '_order',
            'sort-order' => 'ASC',
            'count'      => 1,
else {
 // List mode
    perch_content_custom('Portfolio', array(
        'template' => 'portfolio_listing.html',

Save it and reload your previously empty detail page in your browser. Job done!