Hey @hardboiled I’m more than happy to share my code.
Most of the discussion above is due to the fact that I try to make things as dynamical as possible but you can get the same result with a lot less code.
Anyway, here’s my current solution.
Folder Structure
Home
Products
Year
Product
The year folder is there just to avoid having a ton of content in the products folder since this is a blog and we post almost daily.
Template : home.php
The content is coming from the controller described below.
<?php snippet('header') ?>
<?php
if ($products) :
foreach ($products as $product) :
snippet('product' , array('product' => $product));
endforeach;
endif;
?>
<?php snippet('footer' , array('pagination' , $pagination)) ?>
Controller : home.php
I’m using one simple controller for both home page (where I show all the products) and for the categories.
This is fairly simple I just fetch all the products then check if there’s a category coming from the route and if that’s the case filter the products by category. Then I filter by date (because i want to exclude posts with date set in the future since those are programmed) and then I sort the posts by date and paginate.
return function($site, $pages, $page, $args) {
# Fetch all the products
$products = page('products')->grandChildren()->visible();
# Filter products by category
if (isset($args['category'])) :
$products = $products->filterBy('category' , '==' , $args['category']);
endif;
# Filter by date to exclude programmed posts
$products = $products->filterBy('date', '<', time());
# Sort and paginate
$products = $products->sortBy('date' , 'desc')->paginate(60);
# create a shortcut for pagination
$pagination = $products->pagination();
# Pass $products, $pagination and $category to the template
return compact('products', 'pagination', 'args');
};
Blueprint : product.yml
The relevant part of the blueprint is this
category :
label : Category
type : select
options : field
help : Product category
field :
page : products
name : categories
separator : ,
As you can see the category is set using a simple select field.
The select is populated using the values coming from a tag field defined on the main product page but that’s just because this way I can add new category easily.
You can get the same result using a set of predefined categories. As I said earlier, this is just to keep things more flexible and easy to update.
Route
At the end I decided to go with the str_replace solution for the route.
$pattern = '(' . str_replace(',', '|', page('products')->categories()->value()) . ')';
c::set('routes', array(
array(
'pattern' => $pattern,
'action' => function($category) {
return array('home' , ["category" => $category]);
}
)
));