Blog Pagination, Categories and Comments with Structure in ExpressionEngine
If we haven’t made it plain before, we love ExpressionEngine and Structure. When betrothed together in holy matrimony they make a beautiful pair. But as with any relationship there are some snags. More specifically – blog pagination, categories and comments. Let’s take a look at the problems they have and then some quick tips I’ve stumbled across on how to fix them.
Basic Structure Setup
Before we jump in I’m assuming you know a bit about Structure. It lets you create pages based on URL’s not templates. But it does use templates. Confused yet!? Ok. If you’re creating a blog you will need to do a few things.
- Create two templates - A “show a list of my entries” template and an “individual article” template.
- In your Structure tree, go to settings and add your blog channel as a listing and set it to the individual article template.
- Create the main blog page with Structure, but choose your list of entries template instead of the default template. Also choose to make the page have listings and choose the Blog channel.
- Now back in your Structure tree you’ve got the blog page in your navigation and the option to edit or add new blog entries as listings.
Here’s basic versions of what the two templates should look like:
Example List Template
<!doctype html> <head> <title>{exp:structure:titletrail separator="|"}</title> </head> <body> <div id="content"> {exp:channel:entries channel="blog" dynamic="no" limit="10"} <article> <h1><a href="{page_url}">{title}</a></h1> {body} </article> {/exp:channel:entries} {paginate}<div class="paginate"> View More: {pagination_links}</div>{/paginate} {/exp:channel:entries} </div><!--End Content--> </body> </html>
Example Article Template
<!doctype html> <head> {exp:channel:entries channel="blog" limit="1"} {if desc}<meta name="description" content="{desc}" />{/if} {if keywords}<meta name="keywords" content="{keywords}" />{/if} <title>{title} | Blog | {site_name}</title> {/exp:channel:entries} </head> <body> <div id="content"> {exp:channel:entries channel="blog" dynamic="no" limit="10"} <article> <h1><a href="{page_url}">{title}</a></h1> {body} </article> {/exp:channel:entries} <div id="comments"> <h2>Comments</h2> {exp:comment:entries channel="blog"} <blockquote> <cite> {url_or_email_as_author}<br /> {comment_date format='%M %d, %Y'} </cite> <article>{comment}</article> </blockquote> {/exp:comment:entries} </div><!--End Comments--> <h2>Form Header Here</h2> {exp:comment:form channel="blog"} <label for="name">Name</label> <input name="name" id="name" type="text" /> <label for="email">Email Address</label> <input name="email" type="text" id="email" /> <label for="comment">Write your message here.</label> <textarea name="comment" id="comment">{comment}</textarea> <input name="submit" type="submit" value="Submit" /> {/exp:comment:form} {/exp:channel:entries} </div><!--End Content--> </body> </html>
The Problems
Pagination
Doesn’t work at all. Why? Because if you have a URL like http://site.com/blog/P1 Structure doesn’t recognize the P1 segment and will either serve up a blank page or go to a 404. You could use Freebie and rebuild pagination yourself, but honestly…why? That’s too much work.
Categories
This doesn’t work either for the exact same reason. Structure doesn’t recognize the category URL’s. Obviously category pagination doesn’t work either. Again, you could use Freebie and rebuild categories with a bunch of if-statements. This would be a bit easier – but then if you needed to paginate categories with Freebie….well that sound you just heard was my head exploding.
Comments & URL Titles
Finally, because Structure uses the {page_url}
variable instead of {url_title}
EE seems to have a lot of trouble doing things like comments on the article page because it can’t find the Entry ID from the URL. My past solution is to make clients enter both the {url_title}
and the {page_url}
making sure they match. That’s a huge opportunity for mistakes, though and your clients have no idea what the heck you’re talking about.
Solutions
Pagination and Categories Solution
To fix our category and pagination problem we are going to need to trick Structure. How do we do that? With a third template. Did you know that if Structure can’t find a {page_url}
, but there is a template at the root of that directory it will try to read that instead? So in our blog example – if we setup our Structure page at http://site.com/blog we can go create a “blog” template group and copy the “list all your entries” template to the index template. Then we make a few modifications.
Modified List Template
<!doctype html> <head> {if segment_2 == "category"} {exp:channel:category_heading channel="blog"} <meta name="description" content=" Blog entries in the {category_name} category." /> <title>{category_name} | Blog | {site_name}</title> {/exp:channel:category_heading} {if:else} {redirect="404"} {/if} </head> <body> <div id="content"> {if segment_2 == "category"} {exp:channel:category_heading channel="blog"} <h2>Viewing entries in the <strong>{category_name}</strong> category.</h2> {/exp:channel:category_heading} {/if} {if segment_2 == "" OR segment_2 == "category"} {exp:channel:entries channel="blog" limit="10"} <article> <h1><a href="{page_url}">{title}</a></h1> {body} </article> {paginate}<div class="paginate"> View More: {pagination_links}</div>{/paginate} {/exp:channel:entries} {if:else} {redirect="404"} {/if} </div><!--End Content--> </body> </html>
We just add some if statements to check the segment for the category trigger in the URL. So now if Structure couldn’t find the http://site.com/blog/P1 or http://site.com/blog/category/category-name URL the fall back template will know what to do with it. Extra awesome bonus points: not only do pagination and categories work, but so does pagination in categories. I don’t know how I found this out, but it works great!
Comments and URL Title Solution
This one’s actually pretty easy and I think I ran across it in the Structure forums. There’s a special Structure tag to grab the ID out of the {page_url}
so you can pass it to the comments and comment form.
Modified Article Template
<!doctype html> <head> {exp:channel:entries channel="blog" limit="1"} {if desc}<meta name="description" content="{desc}" />{/if} {if keywords}<meta name="keywords" content="{keywords}" />{/if} <title>{title} | Blog | {site_name}</title> {/exp:channel:entries} </head> <body> <div id="content"> {exp:channel:entries channel="blog" dynamic="no" limit="10"} <article> <h1><a href="{page_url}">{title}</a></h1> {body} </article> <div id="comments"> <h2>Comments</h2> {exp:comment:entries channel="blog" entry_id="{exp:structure:page_id}" parse="inward"} <blockquote> <cite> {url_or_email_as_author}<br /> {comment_date format='%M %d, %Y'} </cite> <article>{comment}</article> </blockquote> {/exp:comment:entries} </div><!--End Comments--> <h2>Form Header Here</h2> {exp:comment:form channel="blog" entry_id="{exp:structure:page_id}" parse="inward"} <label for="name">Name</label> <input name="name" id="name" type="text" /> <label for="email">Email Address</label> <input name="email" type="text" id="email" /> <label for="comment">Write your message here.</label> <textarea name="comment" id="comment">{comment}</textarea> <input name="submit" type="submit" value="Submit" /> {/exp:comment:form} {/exp:channel:entries} </div><!--End Content--> </body> </html>
Just add entry_id="{exp:structure:page_id}" parse="inward"
to the exp:comment:form
and exp:comment:entries
tags. Like I said, easy. Once I started using this my clients didn’t have to put in two URL Titles anymore! Much better. Did you find this useful? Am I doing it totally wrong and there’s a better way? Let us know in the comments.
Comments
1
Bart Houben - Sep 30, 2011
Jonathan Longnecker - Sep 30, 2011
3
Doug Avery - Sep 30, 2011
Jonathan Longnecker - Sep 30, 2011
5
Travis Schmeisser - Sep 30, 2011
6
Neil - Oct 11, 2011
7
Nol Franklin - Oct 20, 2011
Jonathan Longnecker - Oct 20, 2011
9
Nol Franklin - Oct 21, 2011
10
Nol Franklin - Oct 21, 2011
Jonathan Longnecker - Oct 24, 2011
12
incassobureau - Mar 16, 2012
13
Lamar Pierce - Apr 29, 2012
Jonathan Longnecker - Apr 30, 2012
15
Lamar Pierce - Apr 30, 2012
Jonathan Longnecker - May 01, 2012
17
Lamar Pierce - May 01, 2012
Jonathan Longnecker - May 02, 2012