Automated Smarty Pagination »
As mentioned previously, using Smarty for pagination isn't difficult. Of course, the simple example already given doesn't really do much - your users would still need to know about it, and manually construct the URL. That wouldn't be much fun. Using Smarty, we can do the work for them!
You'll need to start with a "total" count. I use MTCategoryCount, as I'm doing this on category archives. If you wanted to do a complete blog archive, you may want to use MTBlogEntryCount or something similar. You could also perform a similar process for comments with MTEntryCommentCount, trackbacks with MTEntryTrackbackCount, etc.
{{capture assign="count"}}<$MTCategoryCount$>{{/capture}}
This introduces a new function, called capture, that takes the value between the capture tags and assigns that value to a new variable - in this case, called count. Accessing this variable later requires you to put a $ in front of it ($count). So the Movable Type template tag is parsed, a number is created, and that number is assigned to the variable count.
Once you have this total count, it's easy to create a previous link:
{{if $smarty.request.offset > 0}}
<a href="?offset={{math equation="max(x-12,0)" x=$smarty.request.offset}}">Previous</a>
{{/if}}
First, this chunk of code checks to see if the offset is greater than 0. If it is not, then it is 0, meaning you're on the first page - no need for a previous link. If it is, then it uses another Smarty function, math, to create the link. Within the math equation, the PHP max function is used - this function accepts two variables and returns the higher of the two. In this case, it returns the value of offset minus 12 (which indicates a prior page), or if that result is less than zero, it's the beginning and you get 0.
The next tag is more complex in some ways and less so in others:
{{if $count > 12 and $smarty.request.offset < $count-12}}
{{if $smarty.request.offset > 0}}
|
{{/if}}
<a href="?offset={{$smarty.request.offset+12}}">Next</a>
{{/if}}
Again we check some numbers. First, to see if the total count is greater than the page count. On the first page of archives, this is necessary - otherwise it would think there was a next page, even if the total count was less than was displayed on the page. This appears to have something to do with the way a variable is handled if it's never defined (for instance, if you submit a URL without the offset parameter). If you always include offset in the URL, then this piece isn't needed. The second check is to see if the offset is less than the count (remember, our total number of items) minus 12 (our page value).
If both of these conditions are true, it means we have some more records coming. But first, it checks another condition - namely, to see if the offset is greater than 0. Just like before, this means that we're on at least the second page of results. That would mean we have a "previous" link, so we need a separator to help readability. Finally, we build the next link, by taking the offset value and adding 12, our value for each page.
Assuming we have multiple pages of data, we'll see a variety of display options:
Next
Previous
Previous | Next
With each of those being a link to the appropriate place at the appropriate time.
Just to reiterate, the entire code for this would look something like:
{{capture assign="count"}}<$MTBlogEntryCount$>{{/capture}}
{{if $smarty.request.offset > 0}}
<a href="?offset={{math equation="max(x-12,0)" x=$smarty.request.offset}}">Previous</a>
{{/if}}
{{if $smarty.request.offset < $count-12}}
{{if $smarty.request.offset > 0}}
|
{{/if}}
<a href="?offset={{$smarty.request.offset+12}}">Next</a>
{{/if}}
<MTEntries lastn="12" offset="`$smarty.request.offset`">
Once you get the basics working, it's easy to just style the links differently, change the number of items per page or include other information in your template.
The best thing about Smarty is that it goes right into your template files and you can check the results quickly and easily (assuming you are using dynamic publishing, of course). Enjoy.





















Comments (35)
Awesome! This is fantastic. Thanks a ton
Posted by Ernie on May 28, 2005 4:51 AM
I implemented this and had a problem with caching turned on, where MT would cache all requests as page one, ignoring the query string. I fixed it by changing line 313 of php/mt.php from:
$cache_id = $blog_id.';'.$path;
to:
$cache_id = $blog_id.';'.$path.';'.$_SERVER['QUERY_STRING'];
Once I did this, it worked perfectly with caching. I'd have prefered a fix I could make in my mtview.php template, rather than customizing the MT code, but couldn't come up with a way.
Posted by ernie on June 3, 2005 1:52 PM
Interesting - you may notice that I recently implemented a different paging method, but it wasn't for this reason. Now, instead of using a query string, I simply append the page, and rewrite inside of the PHP. This doesn't seem to result in any caching issues - but then, the other way didn't cause me any problems either!
Posted by Chad Everett on June 3, 2005 2:24 PM
Worked like a charm. Thanks a million. :-)
Posted by Dhiram on June 4, 2005 4:15 AM
Wow. I switched to dynamic publishing few days ago, and it is getting interesting...
The pagination is great! Thank you for the tutorial!
Posted by Thomas on June 6, 2005 3:39 PM
I recently migrated my weblog from the university's servers to my own domain, and I am now paying for the bandwidth that my blog requires.
Some of my entries have over 500 comments, and therefore wasting an incredible amount of bandwidth on many visitors who don't even look at the comments.
So, I was looking for a solution to paginate the individual archives in hopes of optimizing comment delivery—thus serving them only to those who request them—and your wonderful example allowed me to get a test page up and running using dynamic publishing within about 10 minutes!
I cannot thank you enough, for it will likely save me lots of money. And as I am still a full-time graduate student, that means a lot to me.
Cheers!
Posted by jay on September 4, 2005 10:42 PM
Fantastic!
I tried MTPaginate plugin, but it won't work with dynamic pages.
This is THE solution!
Thanks a lot.
Posted by skoji on November 2, 2005 9:50 AM
Smarty pagination works fine
Can u please add a new attrubute or funtion such that we can give a css class name for the hyperlinks ,to diferenciate for current page and rest of the page links thru custom colors or etc thru css class name
when this feature is implemented please email me
Thanks
john
Posted by john on May 15, 2006 3:18 AM
Uh, no (on both counts).
All you have to do is to give the link (or any html fragment) a class, or id, and then style it. Enjoy.
Posted by Chad Everett on May 15, 2006 8:06 AM
Hey! You did a good job I am thankful.
Posted by Tito on July 21, 2006 9:00 AM
This is great, I've been getting slammed by my new hosting company because of MTPaginate's insane resource hogging, and so I've been looking for a painless pagination alternative.
So will you please update my code and email me when you're done? Thanks. ;)
Posted by greg.org on August 5, 2006 5:43 PM
Thanx tons! Would not have been possible without you.
Posted by Yash on November 15, 2006 5:24 AM
It says that Smarty has been built-in in mt3.33... But why none of my Smarty code being rendered? It just display pure code, not the output...
I think it's about static/dynamic publishing, tried both still the same, tried html/php extension, still no different...
All I want to do is paginate my category page (static publishing), view 10 entries per page, then next/previous...
Posted by Pai on December 20, 2006 9:29 PM
If you are using static publishing, then that is your problem. Smarty will only work with dynamic publishing. The extension doesn't matter.
If you want to continue using static publishing, you may want to try MT-Paginate instead, as you can use it within static archives (you do need to have your pages parsed as PHP).
Posted by Chad Everett on December 21, 2006 6:48 AM
Thanks Chad...
Anyway, I wonder why Six Apart didn't provide this feature... pagination "should" exist by default in any publishing platform.
Posted by Pai on December 26, 2006 12:26 PM
Pagination is one of the most sought after - yet missing - features of MT.
I've created a solution with just three plugins which you can use on index pages (also monthly index, category index) and individual entry pages (e.g. to paginate comments).
You don't have to hack MT, don't need to use dynamic (PHP) publishing either.
Blog Pagination with Movable Type
Posted by BlogBear on June 21, 2007 6:35 PM
That's an interesting method, and I commend you for the style you're using. If nothing else, it may improve the user experience.
But I'd suggest that you're not doing a entirely server-based process, either, since it is based on JavaScript.
By using Smarty (and, in turn, PHP), it's entirely server-based, and also your server only serves up the part of the page that is requested (like MT-Paginate, which you mention), resulting in lower bandwidth usage.
Your method returns the entire page - though admittedly, it won't need to request anything else if the user decides to view another page.
But it's quite possible to use it on comments or anything else as well.
And no hacking is necessary - I simply did so in order to create different URLs. In other words, I didn't want to include "page=2" or something, so I needed to do some hacking to the code to make it work right. You could also use some mod_rewrite magic that should make this work correctly, depending on the host. Still, thanks for the information!
Posted by Chad Everett on June 22, 2007 6:48 AM
How do I install this plugin and where do I find it?
Posted by Shane on August 24, 2007 2:46 PM
Hi Shane -
This isn't a plugin. The Smarty templating language is what is used by Movable Type to render dynamic pages. So it's built in to every distribution of MT. Just start writing by adding the code above to your templates, then save and refresh!
Posted by Chad Everett on August 29, 2007 9:04 AM
Thanks a lot, Chad. I'm now using it in 3.2 templates but upgraded to 4.01. I've created a new 4.0 template blog...Where in the new template system would I put the code?
Thanks!
Posted by Shane on October 23, 2007 9:57 PM
Hi Shane -
You'll put the code wherever you want it to appear. Probably in the Entry template, but it's ultimately up to you (for instance, if you're using it in the category or date listing, it would be in the Entry Listing template).
Posted by Chad Everett on October 25, 2007 7:39 AM
Thanks again for the response! I gathered that it would go in my Page template for parsing the main index entries, but just by placing it in there, I get errors because of the MTEntries tag:
"Your template changes have been saved. One or more errors were found in this template. MTEntries with no /MTEntries on line 35."
Would I perhaps need to wrap your code around the Page Detail module in the Page template with "MTEntries lastn="3" offset="`$smarty.request.offset`"
and then the end tag underneath the module?
Posted by Shane on October 25, 2007 8:42 AM
If you want to update your Main Index, then that's where you should put the code. The Page template is for pages.
The error you are getting sounds like you don't have an </MTEntries> tag. Also, make sure you are using dynamic publishing - it's not on by default.
Posted by Chad Everett on October 25, 2007 9:04 AM
Ok great! It worked. Thanks a lot I really appreciate the help. :-)
Posted by Shane on October 25, 2007 9:41 AM
Somehow it does not work with caching enabled on MT4.1. On clicking the next link I get the first page only.
Posted by SK on November 28, 2007 7:04 AM
Hi SK -
Actually, it won't work if you use caching in MT 3.3x either - it's just that you have to turn that on yourself. :)
You'll want to look for this line in mt.php:
Notice that it's just the $blog_id and $fi_path? There is no page number on it. So you need to add it. Of course, you need to have a page number first.
Once you do, you need to add it to the cache ID, like so:
// Add pagination info to cache if present... if ($page_number) { $cache_id = $blog_id.';'.$fi_path.';'.$page_number; } else { $cache_id = $blog_id.';'.$fi_path; }How do you get a value into $page_number? Well, that's a little tricky. You can try something simple like this:
// Check for page number... if ($_GET['page']) { $page_number = $_GET['page']; }This would be the value that you used for the page number in your templates. Just set $page_number equal to that variable and you're set. Now the cache ID is equal to the blog ID, the fileinfo path and the page number, so now you will have a cached version of each page.
Posted by Chad Everett on November 28, 2007 8:24 AM
I am running MT4 and wish to paginate my search results. How would I go about doing so ? Any ideas , I think you run Movable type on this blog, how did you manage to get the 'navigation' thingy for the search results? Thanks in advance, this means a lot to me ; I am completely stumped since MT uses CGI for this.
Posted by Yash on December 12, 2007 7:44 AM
I dont use MT's search actually , but I need it since the TAG cloud refers to the search page by searching for the tag. If there is anyway to get a result of entries tagged with that particular tag an paginated (the blog has a large number of entries) then it would do as well.
Posted by Yash on December 12, 2007 7:47 AM
Hi Yash -
You can do pagination just like you could previously - either with MT-Paginate or with Smarty (as described here). It's no different from prior versions - at least, I don't think it is. This site is currently on MT 3.35, so I can't say for sure.
As to the search results, I'm using Mark Carey's excellent Fast Search plugin and a few tags to paginate the results. The documentation should describe how to to do it. You can also do the same with MT-Paginate if you don't have Fast Search.
Posted by Chad Everett on December 12, 2007 9:12 AM
First thanks to you for sharing you experience with mt. For me this note was very helpful to implement pagination on an mt 4.01 system. But the fact to disable the caching system was unthinkable cause of performance reasons.
Modify the mt core was not allowed for me. So after many times i found a way hacking the mt bootstrap called mtview.php to implement a pagination system based on the code explain in this note and working with the caching system enabled. And it seems to work as well... I paste the code in this comment, i hope it will help someone in the future.
Here is my mtview.php hack :
$mt = new MT(1, '/path/to/mt-config.cgi'); // Get the context, an MTViewer object that extend Smarty object. $ctx =& $mt->context() ; // enable the mt caching system $mt->caching = true; // Test the query string if (empty($_SERVER['QUERY_STRING']) || $_GET['offset'] == '0') { // This is normal way... we are not in a pagination action $mt->view() ; } else if (isset($_GET['offset'])) { // Here we're into a pagination action, offset is set and more than 0 // so we can begin to work // Direct enable the smarty caching system through the MTViewer subclass $ctx->caching = true; // Define a cache id $cache_id = $_SERVER['QUERY_STRING'] ; // assign the variable to easy retrieve it into the template. $ctx->assign("offset", $_GET['offset']) ; // Display your own template, in my case a custom index template. $mt->display($_SERVER['DOCUMENT_ROOT']."custom_index.tpl", $cache_id) ; } // Do other process if needed... else { $mt->view() ; }Posted by Dilaroga on January 20, 2008 5:35 AM
Hi Dilaroga -
Thanks for the detailed explanation. I'll have to take a more in-depth look at it when I get a chance!
Posted by Chad Everett on January 22, 2008 9:45 AM
Really nice, however I am using MT 4.1 and it does not work with caching turned on.
Posted by Dhiram on March 1, 2008 2:34 AM
Actually, Dhiram, as mentioned above in the comments, it doesn't work with caching even in prior versions of MT. Read through the comments for more details on why!
Posted by Chad Everett on March 3, 2008 12:20 PM
Please tell me how to integrate the pagination codes .Iam sending my php code
search.php
----------------
My tpl file
------------
{include file="home/header.tpl.html"}
{{capture assign="count"}}{{/capture}}
{{if $smarty.request.offset > 0}}
Previous
{{/if}}
{{if $smarty.request.offset
{{if $smarty.request.offset > 0}}
|
{{/if}}
Next
{{/if}}
{include file="home/footer.tpl.html"}
Please help me to do the pagination in the tpl file which fetches data from search.php - search_h().
Posted by swag on May 8, 2008 2:30 AM
Here is the fix for anyone using mt 4.1... it is based on Dilaroga's mtview.php above. I fixed a security hole in his implementation that would allow a malicious user to DOS your server. Read the inline comments for more details.
<?php include('<$MTCGIServerPath$>/php/mt.php'); $mt = new MT(<$MTBlogID$>,'<$MTConfigFile$>'); // Get the context, an MTViewer object that extend Smarty object. $ctx =& $mt->context(); // enable the mt caching system $mt->caching = true; // Test the query string if (empty($_SERVER['QUERY_STRING']) || $_REQUEST['offset'] == '0') { // This is normal way... we are not in a pagination action $mt->view(); } elseif(isset($_REQUEST['offset']) && $_REQUEST['offset'] < 100000) { // Changed statement above to make sure the offset is within reason. // Without doing so and setting the cache_id to whatever is in the // query string leaves the server open to a DOS attack by malicious // users who could send millions of random query strings, creating // new compiled smarty templates on the filesystem, swamping the // server disk I/O and possibly filling the hard disk that the smarty // template_c directory is located on. // the smarty documentation speaks of it here: // http://www.smarty.net/manual/en/caching.multiple.caches.php // TODO: Make the limit above based on a lookup of the total number // of records and use that as the upper limit for the offset variable // Here we're into a pagination action, offset is set and more than // 0 so we can begin to work Direct enable the smarty caching system // through the MTViewer subclass $ctx->caching = true; // Define a cache id $cache_id = $blog_id.';'.$fi_path.';'.$_REQUEST['offset']; // Assign the variable to easily retrieve it into the template. $ctx->assign('offset', $_REQUEST['offset']); // Display your own template, in my case a custom index template. $mt->display('<$MTBlogSitePath$>templates/index.php', $cache_id); } else { $mt->view(); } ?>Posted by Jesse Sanford on May 24, 2008 4:58 PM