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.


Posted

in

Comments

35 responses to “Automated Smarty Pagination”

  1. Jesse Sanford Avatar
    Jesse Sanford

    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();
      }
    ?>
    
  2. swag Avatar
    swag

    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().

  3. Chad Everett Avatar

    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!

  4. Dhiram Avatar

    Really nice, however I am using MT 4.1 and it does not work with caching turned on.

  5. Chad Everett Avatar

    Hi Dilaroga –

    Thanks for the detailed explanation. I’ll have to take a more in-depth look at it when I get a chance!