Categories, Pagination and 404s with Structure
I searched long and hard for an elegant solution to this common problem with the Structure add-on for ExpressionEngine, and nothing quite resolved all the issues I was having. So, I thought I would offer the solution I came up with for the following scenario and requirements, as it seems pretty common amongst Structure users. This would apply to your typical "News," "Blog," "Articles," or similar type of section that features a list of web site entries, sortable by category. I assume you could get Yearly Archives working in a similar manner, but my project doesn't require them, so I didn't bother. Hopefully this helps some people out.
Requirements
- Use MD Detect Page Type to use single template to serve content
- Retain valid 404 errors
- Retain pagination for single entries, categories or other listings of entries
I avoided using Freebie or Zoo Triggers because of issues introduced in regards to pagination or other complexities. If these add-ons work for you, great! The suggestions below intentionally disregard them. Also, while it isn't recommended to use the same template group as a Structure Entry URL, I found that when using categories, the following solution is actually most elegant when approached in this manner. While this solution might not work for everyone, I have found it to work well on pretty much every site I build with this type of web site content.
Setting up for success
- Create a Structure page and assign a listing channel. In my example, I have created the page "News" with a Structure Page URL of "news" and selected my "News" channel as the listing channel.
- Assign the Structure Template for this page to the template you are going to use for all content in this section. In my example, I am using the "news/index" template.
- In the Structure "Channel Settings," ensure that your listing channel has been assigned the same template (news/index in my example).
The Templates
Index template (news/index) - uses MD Detect Page Type
{exp:md_detect_page_type url_segment="{segment_2}"}
{if pagination_page || category_page || segment_2 == ""}
{embed="embeds/.top_structure" title="News{if (pagination_page && category_page) || category_page}{exp:channel:category_heading channel="channel_news"} - {category_name}{/exp:channel:category_heading}{/if}"} {!-- hard-coding news overview title and category title when applicable for SEO reasons --}
{if:else}
{exp:channel:entries limit="1" disable="categories|member_data|pagination" status="not closed"}
{embed="embeds/.top_structure" entry_id="{entry_id}"} {!-- use single entry data when applicable --}
{/exp:channel:entries}
{/if}
<div id="content">
{if pagination_page || segment_2 == ""}
{embed="news/.home_listing"}
{/if}
{if (pagination_page && category_page) || category_page}
{embed="news/.cat_listing"}
{/if}
{if segment_2 != "" && pagination_page != TRUE && category_page != TRUE}
{embed="news/.single_entry"}
{/if}
<nav id="categories">
<h4>News Categories:</h4>
{exp:channel:category_archive channel="channel_news" display_empty="no"}
{categories}
<a href="/news/category/{category_url_title}/">{category_name}</a>
{/categories}
{/exp:channel:category_archive}
</nav>
</div>{!-- end content --}
{/exp:md_detect_page_type}
{embed="embeds/.bottom_structure"}
Note: You can now use Low Variables to emulate the function of embeds without the performance hit: https://getsatisfaction.com/low/topics/cant_edit_or_delete_variables#reply_9079311 - I just haven't implemented it on this project yet. ![]()
Because we have already used MD Detect Page Type to detect what type of content we are loading, there are just two instances where a 404 will fail because of the conflict between the template group name and the Structure URL of the news entry - when a single entry is served or when a category list is served. Let's look at those two templates first:
Single Entry Template with prev/next entry pagination
{exp:channel:entries channel="channel_news" limit="1" disable="member_data|trackbacks"}
{if "/{segment_1}/{segment_2}/" != "{page_uri}"}{redirect="404"}{/if}
<h1>{title}</h1>
{body}
<div class="pagination">
{exp:channel:prev_entry channel="channel_news"}
<p class="prev"><strong>&laquo; PREV:</strong> <a href="{path=news}" title="{prev_entry->title}">{prev_entry->title}</a></p>
{/exp:channel:prev_entry}
{exp:channel:next_entry channel="channel_news"}
<p class="next column2"><a href="{path=news}" title="{next_entry->title}">{next_entry->title}</a> <strong>NEXT: &raquo;</strong></p>
{/exp:channel:next_entry}
</div>
{/exp:channel:entries}
The key in retaining a valid 404 function on this template is the second line of code - simply use segment detection to ensure that the segment build actually matches the page_uri of the entry. Note: I am using page_uri instead of url_title for consistency with the rest of the site. Since we are using Structure to manage the site pages, I avoid calling any entries using url_title in the templates. The pagination uses the default ExpressionEngine Next/Previous Entry Linking and it works great.
Category List Template with pagination
{if "{segment_3}" != "{exp:channel:category_heading channel="channel_news"}{category_url_title}{/exp:channel:category_heading}"}{redirect="404"}{/if}
{exp:channel:category_heading channel="channel_news"}<h1>{category_name}</h1>{/exp:channel:category_heading}
<ul class="entryList">
{exp:channel:entries channel="channel_news" limit="5" sort="desc" orderby="date" disable="member_data|trackbacks" paginate="bottom"}
<li>
<h3 class="heading"><a href="{page_uri}">{title}</a></h3>
<p class="postInfo column1"><strong>Posted in</strong> {categories backspace="2"}<strong><a href="{path=news}">{category_name}</a></strong>, {/categories} on {entry_date format="%F %j, %Y"}</p>
<p>{summary}</p>
</li>
{paginate}
<li class="pagination clearfix"><p>Page {current_page} of {total_pages} pages: <span class="pagLinks">{pagination_links}</span> </p></li>
{/paginate}
{/exp:channel:entries}
</ul>
Again, we are using segment detection to ensure the category_url_title matches the category being displayed. If not, we redirect to 404. I don't have any child categories, but I'm sure you could check multiple segments for a valid category_url_title if needed. Again, pagination uses the default ExpressionEngine Channel Entry Pagination, so no Structure pagination woes!
Hopefully this is helpful to those looking for a solution to this comment EE Structure scenario.
Posted by Michael
in Website Development - ExpressionEngine on June 5, 2012
Comments: 0 | View/Add Comments
Let's Talk
E-mail Us • 206-331-3859
Comments:
No comments have been submitted.