Update! September 16, 2011
Since I wrote this blog post, there have been some new developments. First of all, the PyroCMS releases after 1.3.2 will fix the bug mentioned below. Secondly, I’ve released an add-on that makes it easier to manage your custom routes, called PyroRoutes. You can download it for free here.
There has been a lot of questions on the PyroStreams forum about one subject in particular – showing dynamic info on its own page – so what follows is a guide on how to do that. Once the new Addict site is up (which has a blog), I’ll cross-post this over there.
One note – I am using PyroStreams 2 beta syntax here with the {entries} tag inside of the cycle plugin. If you are using PyroStreams 1, please adjust accordingly. If you are using 2 beta, please update to the latest version (uploaded today at 6pm EST), as it contains fixes to the single function.
Alright, let’s get started!
Pages in PyroCMS
First a little note on the relationship between pages and streams. When you create a stream, there is nothing created in the page system that tells PyroCMS to do anything but to create that stream and populate it with data. The display is up to you, which means that it is very flexible, but some things require a little bit of elbow grease.
If you’ve used ExpressionEngine before, you know that you can create a URL and EE will show you anything but a 404 (unless you have strict URLs turned on, and they are turned off by default). That means if you have a template group called products and a template inside of it called product, you could do products/product/sample-product or products/product/sample-product/features all you want. EE doesn’t really care about the URL as long as it can find something to show.
PyroCMS cares about your URL. If you give it the URL products/product/4, It is going to look for a page in your page tree called products/product/4 and try and load that page. The trick is you need to tell PyroCMS to ignore certain segments in your URL, so it will load a base page (in this case products/product-page). On that page, we’ll pay attention to what’s in the URL, and display an entry based on that.
If you are confused, don’t worry! It’s easy – below is an example.
Building a Simple Products Directory
So if you are listing products on a page, you pretty much can tell how that goes. You create a “Products” page:

In the page layout (let’s called it “Product Listing”) associated with that page (under the “Design” tab), you run through code that grabs your products:
{pyro:streams:cycle stream="products"}
<a href="products/product/{id}">{name}</a>
{/pyro:streams:cycle}
Easy enough! We are dynamically creating links to products by id. (Keep in mind, this could be a slug or something else you want to use, but for this example we’ll use IDs since every post has them.)
Now, we need to create a Product page as a child page of Products. This page has a URI of products/product-page. We can create a separate page layout for that as well. In this example we’ll call it “Product”.



Now, if we go to our product listing, and click on a product, we get a 404, because PyroCMS is looking for a page called 2 (if the id is 2) that is a child page of Product. That doesn’t exist in our pages tree, so we need to add a route.
If you are not familiar with routes, they are a CodeIgniter thing, and they are located in system/pyrocms/config/routes.php. It is a simple array that has a standard format:
$route['uri to route'] = 'uri to route to';
You can also use :any and :num to signify anything in a URI segment and a number in the URI segment, respectively.
You might ask “what are we routing to”? The answer is the view function in the pages module. So our route is going to look like this:
$route['products/product/:any'] = 'pages/view/products/product-page';
What we are doing is saying that when PyroCMS encounters a URI with products/product/, and anything in the third segment (our id, slug, whatever), it will load up products/product-page. Notice that we don’t use any routing variables like $1 because we don’t want to pass dynamic info to the root value – we just want PyroCMS to ignore some segments.
Bypassing a Bug
I will add a pull request for this ASAP, but doing this throws an error in PyroCMS 1.2 and above. This is because of a bug (what I think is a bug anyways) in the pages module. Luckily, the fix is really easy. Go to system/pyrocms/modules/pages/controllers/pages.php and change line 43 to:
$url_segments = $this->uri->total_rsegments() > 0 ? array_slice($this->uri->rsegment_array(), 2) : null;
That’s it! You should be set to go now.
Displaying Dynamic Data
No you should be able to click on any one of your product links, and you won’t get a 404. Awesome! Now we just need to display some dynamic data.
You can use the cycle plugin if you want but we have a simplified function called single in PyroStreams 2 that you can use. It basically just eliminates the need to use “entries” and limit 1 and all that stuff. So in our Product page layout, we have this code:
{pyro:streams:single stream="products" id="[segment_3]"}
<h1>{name}</h1>
{/pyro:streams:single}
Simple as that – we can tell it to grab the ID using our (PyroStreams 2 only) segment variables. Using the cycle plugin you can do:
{pyro:streams:cycle stream="products" where="id==seg_3" limit="1"}
{entries}
<h1>{name}</h1>
{/entries}
{/pyro:streams:cycle}
That should cover it! I’ll be posting some more how-to’s here on PyroStreams just as soon as I get the last damn bits of PyroStreams 2 finished!
