Not a developer? Go to MovableType.com

Documentation

Comment Pagination

Note: The comment pagination feature was added in MT4.3.

Comment pagination is useful when entries have large numbers of comments.

Features

  • AJAX pagination. No page refresh when paging through comments.
  • Comment Permalinks. If comment is on the current page of comments, the page scrolls to that spot; otherwise page comment is on is determined and loaded.

Comment Pagination in a New Blog

Comment pagination has been added to the Classic Blog template set in MT4.3.

To view comment pagination in a new blog:

  1. Create a new blog in MT4.3 install using the Classic Blog template set.
  2. Edit the Entry archve tempate and change the comments_per_page variable to have a value of “1”.
  3. Add an entry.
  4. Add two comments on the entry.
  5. After submitting the second comment (assuming both comments are published), the navigation to the second page of comments is available.

Add Comment Pagination to an Exising Blog

  1. Install MT4.3. Doing so will add a new system template “Comment Listing” to each blog. This is the template code for the Comment Lisitng template:

    {
        "direction": "<$mt:Var name="commentDirection"$>",
        "comments": "<mt:Comments sort_order="$commentDirection"><$mt:Include module="Comment Detail" replace="\","\\" replace='"','\"' strip_linefeeds="1"$></mt:Comments>"
    }
    

    Tip: If implementing a custom version of comment pagination—other than the method described here—it may be useful to access this template to return comments. This template can be viewed by accessing the following URL and replacing the variables:

    <$mt:CGIPath$><$mt:CommentScript$>?__mode=comment_listing&direction=ascend|descend&entry_id=ENTRY_ID&limit=LIMIT_VALUE&offset=OFFSET_VALUE
    
  2. Update the Entry archive template. Place the below code inside the html <head> tag after the current contents.

    <$mt:Var name="comments_per_page" value="50"$>
    <mt:If tag="EntryCommentCount" gt="$comments_per_page">
    <script type="text/javascript">
        MT.entryID = <$mt:EntryID$>;
        MT.commentsPerPage = <$mt:Var name="comments_per_page"$>;
        MT.entryCommentCount = <$mt:EntryCommentCount$>;
        MT.commentIds = [<mt:Comments sort_order="ascend" glue=","><$mt:CommentID$></mt:Comments>];
    </script>
    </mt:If>
    
    • The comments_per_page variable defines the number of comments per page (in this case 50 comments).
    • If the number of comments per page is greater than the number of comments the entry has, then some JavaScript variables are set to be used for calculating how to display comments.
  3. Because the comments are being rendered statically by the Entry archive template and dynamically by the Comment Listing system template, we create a template module and include it in both templates.

    Create a new template module named “Comment Detail” with the following code:

    <div id="comment-<$mt:CommentID$>" class="comment<mt:IfCommentParent> comment-reply</mt:IfCommentParent><mt:IfCommenterIsEntryAuthor> entry-author-comment</mt:IfCommenterIsEntryAuthor>">
        <div class="inner">
            <div class="comment-header">
                <div class="asset-meta">
                    <span class="byline">
                        <$mt:CommentAuthorIdentity$>
    <mt:IfCommentParent>
                        <__trans phrase="[_1] replied to <a href="[_2]">comment from [_3]</a>" params="<span class="vcard author"><$mt:CommentAuthorLink$></span>%%<mt:CommentParent><$mt:CommentLink$></mt:CommentParent>%%<mt:CommentParent><$mt:CommentAuthor$></mt:CommentParent>">
    <mt:Else>
                        <span class="vcard author"><$mt:CommentAuthorLink$></span>
    </mt:IfCommentParent>
                        | <a href="<$mt:CommentLink$>"><abbr class="published" title="<$mt:CommentDate format_name="iso8601"$>"><$mt:CommentDate$></abbr></a>
    <mt:IfCommentsAccepted>
                        | <$mt:CommentReplyToLink$>
    </mt:IfCommentsAccepted>
                    </span>
                </div>
            </div>
            <div class="comment-content">
                <$mt:CommentBody$>
            </div>
        </div>
    </div>
    
  4. In the “Comments” template module, delete the <mt:Comments> block and all its contents. Replace with this code:

    <mt:Comments lastn="$comments_per_page">
        <mt:CommentsHeader>
    <h2 class="comments-header"><$mt:EntryCommentCount singular="1 Comment" plural="# Comments" none="No Comments"$></h2>
            <mt:If tag="EntryCommentCount" gt="$comments_per_page">
    <ul id="top-comment-nav">
        <li id="top-prev-comments">
            <a href="javascript:void(0)" id="top-prev-comments-link" title="Older Comments">&lt;&lt;&nbsp;Older Comments</a>
        </li>
        <li id="top-num-comments">
            <span id="top-current-comments"></span>
        </li>
        <li id="top-next-comments">
            <a href="javascript:void(0)" id="top-next-comments-link" title="Newer Comments">Newer Comments&nbsp;&gt;&gt;</a>
        </li>
    </ul>
            </mt:If>
    <div id="comments-content" class="comments-content" style="clear: left;">
        </mt:CommentsHeader>
        <$mt:Include module="Comment Detail"$>
        <mt:CommentsFooter>
    </div>
            <mt:If tag="EntryCommentCount" gt="$comments_per_page">
                <mt:Ignore><!-- Nav data is modified by the paginate script. --></mt:Ignore>
    <ul id="comment-nav">
        <li id="prev-comments">
            <a href="javascript:void(0)" id="prev-comments-link" title="Older Comments">&lt;&lt;&nbsp;Older Comments</a>
        </li>
        <li id="num-comments">
            <span id="current-comments"></span>
        </li>
        <li id="next-comments">
            <a href="javascript:void(0)" id="next-comments-link" title="Newer Comments">Newer Comments&nbsp;&gt;&gt;</a>
        </li>
    </ul>
            </mt:If>
        </mt:CommentsFooter>
    </mt:Comments>
    
    • The mt:Comments tag is updated to limit the number of comments to the value of the entries_per_page variable.
    • Comment pagination navigation is placed before and after the list of comments. This will be hidden on page load if the entries per page value is less than the total comments.
    • The “Comment Detail” template module is included here and in the “Comment Listing” system template; placing the content in a template module allows the same code to be used in two places.
  5. Add the following JavaScript functions to the bottom of your JavaScript index template:

    if(!this.JSON){JSON={};}(function(){function f(n){return n<10?'0'+n:n;}if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+'-'+f(this.getUTCMonth()+1)+'-'+f(this.getUTCDate())+'T'+f(this.getUTCHours())+':'+f(this.getUTCMinutes())+':'+f(this.getUTCSeconds())+'Z';};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}if(typeof rep==='function'){value=rep.call(holder,key,value);}switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}v=partial.length===0?'[]':gap?'[\n'+gap+partial.join(',\n'+gap)+'\n'+mind+']':'['+partial.join(',')+']';gap=mind;return v;}if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}return str('',{'':value});};}if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}return reviver.call(holder,key,value);}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}throw new SyntaxError('JSON.parse');};}}());
    var MT = window.MT || {};
    MT.cons = function () {
      return {
        LOG : 'log',
        WARN : 'warn',
        DEBUG : 'debug',
        INFO : 'info',
        ERR : 'error',
        JSON : 'json'
      };
    }();
    <mt:Ignore>
    /**
     * Used for base functionality related to MT
     * 
     * @package MT
     * @class core
     * @global
     * @param {Object} o optional configuration object
     * Options:
     */
    </mt:Ignore>
    MT.core = function (o) {
      var _debug = false;
      return {
        <mt:Ignore>
        /**
         * Makes remote call and handles response
         * 
         * @param {String} url The URL endpoint
         * @param {String} respType The type of response expected
         * @param {Function} respHandler The function to handle the response
         * @return void
         */
        </mt:Ignore>
        connect : function (url,respType,respHandler) {
          var xh = mtGetXmlHttp();
          if (!xh) return false;
          xh.onreadystatechange = function() {
            if ( xh.readyState == 4 ) {
              if ( xh.status && ( xh.status != 200 ) ) {
                // error - ignore
              } else {
                switch (respType) {
                  case 'json':
                    respHandler(JSON.parse(xh.responseText));
                    break;
                  case 'xml':
                    break;
                  case 'text':
                    break;
                }
              }
            }
          };
          xh.open('GET',url);
          xh.send(null);
        },
        getEl : function (el) {
          return MT.util.checkNodeType(el)==='element' ? id : (document.getElementById(el) || false);
        },
        addEvent : function (el,type,func,obj) {
          if(!obj && document.addEventListener) {
            el.addEventListener(type,func,false);
          } else if(obj && document.addEventListener) {
            el.addEventListener(type,function () {
              func.call(obj,event);
            },false);
          } else {
            if(obj) {
              el.attachEvent('on' + type,function () {
                func.call(obj,event);
              });
            } else {
              el.attachEvent('on' + type,function () {          
                func.call(el,event);
              });
            }
          }
        },
        <mt:Ignore>
        /**
         * Basic logging function
         * 
         * @param {String} level The log level (WARN|DEBUG|INFO|ERROR|LOG)
         * Specified by one of the MT constants
         * @param {String} msg The log message
         * @return void
         */
        </mt:Ignore>
        log : function (level,msg) {
          if(_debug && window.console) {
            switch(level) {
              case 'warn':
              case 'debug':
              case 'info':
              case 'error':
              case 'log':
                console[level](msg);
                break;
              default:
                return false; 
            }
          } else {
            return false;
          }
        }
      }
    }();
    <mt:Ignore>
    /**
     * Utilities class
     * 
     * @package MT
     * @class util
     * @global
     * Options:
     */
    </mt:Ignore>
    MT.util = function () {
      return {
        toggleVisibility : {
          show : function () {
            var i = arguments.length;
            while(i--) {
              if(MT.util.checkNodeType(arguments[i])==='element') {
                arguments[i].style.visibility = 'visible';
              } else {
                MT.core.getEl(arguments[i]).style.visibility = 'visible';
              }
            }
          },
          hide : function () {
            var i = arguments.length;
            while(i--) {
              if(MT.util.checkNodeType(arguments[i])==='element') {
                arguments[i].style.visibility = 'hidden';
              } else {
                MT.core.getEl(arguments[i]).style.visibility = 'hidden';
              }
            }
          }
        },
        toggleDisplay : {
          show : function () {
            var i = arguments.length;
            while(i--) {
              if(MT.util.checkNodeType(arguments[i])==='element') {
                arguments[i].style.display = '';
              } else {
                MT.core.getEl(arguments[i]).style.display = '';
              }
            }
          },
          hide : function () {
            var i = arguments.length;
            while(i--) {
              if(MT.util.checkNodeType(arguments[i])==='element') {
                arguments[i].style.display = 'none';
              } else {
                MT.core.getEl(arguments[i]).style.display = 'none';
              }
            }
          }
        },
        <mt:Ignore>
        /**
         * Finds the nearest defining (i.e. with an id) parent to the given element
         * 
         * @param {HTMLElement} origin the node from which to start the search
         * @return {HTMLElement|Boolean} The parent node with an id attribute or false
         */
        </mt:Ignore>
        findDefiningParent : function (origin) {
          if(MT.util.checkNodeType(origin)==='element') {
            for(var node=origin.parentNode;node.parentNode;node=node.parentNode) {
              if((node.hasAttribute && node.hasAttribute('id')) || node.getAttribute('id')) {
                return node;
              }
            }
          }
          return false;
        },
        <mt:Ignore>
        /**
         * Tests objects to verify if they are DOM nodes
         * 
         * @param {Object} obj The object to be tested
         * @return {String} the values 'element'|'textnode'|'whitespace'
         */
        </mt:Ignore>
        checkNodeType : function (obj) {
          if (obj && obj.nodeName){
            switch (obj.nodeType) {
              case 1: return 'element';
              case 3: return (/\S/).test(obj.nodeValue) ? 'textnode' : 'whitespace';
            }
          }
        }
      }
    }();
    <mt:Ignore>
    /**
     * mtPaginateComments takes the currently generated static page and either:
     *  - Attempts to find an individual comment link in the query string
     *  - If no link is found, the static page loads
     * In either case, the pagination event is set
     */
    </mt:Ignore>
    (function () {
      var M = MT.core,
          c = MT.cons,
          u = MT.util,
          cache,
          isLoading,
          direction,
          currentComments,
          commentAnchor,
          commentArrId,
          commentsPerPage,
          commentsTotalPages,
          loadingIcon,
          pageNum,
          commentsOffset,
          totalComments,
          entryID,
          commentContentDiv,
          topNav,
          nav,
          currentCommentsSpan,
          topCurrentCommentsSpan;
      M.addEvent(window,'load',_init);
      /**
       * Initializes the class
       * 
       * @return void
       */
      function _init () {
        if(!MT.entryCommentCount) {
          return;
        }
        _initializeVariables();
        _setCommentOffset(false);
        _checkForAnchor();
        _setCurrentComments();
        _toggleNavLinks();
        _initializeEvents();
      }
      <mt:Ignore>
      /**
       * Initializes variables to their initial values
       * 
       * @return void
       */
      </mt:Ignore>
      function _initializeVariables() {
        cache = {};
        isLoading = false;
        commentAnchor = '';
        commentArrId = '';
        commentsPerPage = MT.commentsPerPage || 50;
        currentComments = '';
        direction = 'ascend';
        entryID = MT.entryID;
        totalComments = MT.entryCommentCount;
        commentsTotalPages = Math.ceil(totalComments / commentsPerPage);
        pageNum = 1;
        loadingIcon = "<img title='Loading...' src='<$MTStaticWebPath$>images/indicator.white.gif' alt='Loading' />";
        commentContentDiv = M.getEl("comments-content");
        topNav = M.getEl("top-comment-nav");
        nav = M.getEl("comment-nav");
        currentCommentsSpan = M.getEl("current-comments");
        topCurrentCommentsSpan = M.getEl("top-current-comments");
      }
      function _initializeEvents() {
        if (commentsPerPage < totalComments) {
          M.addEvent(nav,'click',_handleEvents);
          M.addEvent(topNav,'click',_handleEvents);
        }
      }
      <mt:Ignore>
      /**
       * Checks for an existing anchor tag in the query string
       * If found, it looks for it on the current page
       * If that fails, it tries to find it in comment list and loads
       * the desired page
       * 
       * @return void
       */
      </mt:Ignore>
      function _checkForAnchor() {
        var found = String(window.location.hash).match( /comment-(\d{1,6})/ );
            if (found) {
              M.log(c.DEBUG,found);
                if (!M.getEl(found[0]).hasOwnProperty('className')) {
                    if (_findIdMatch(found[1])) {
                    pageNum = Math.floor(commentArrId / commentsPerPage) + 1;
                    M.log(c.DEBUG,'Comment Array Id: ' + commentArrId);
                    M.log(c.DEBUG,'Comments Per Page: ' + commentsPerPage);
                    M.log(c.DEBUG,'Page Number: ' + pageNum);
                    M.log(c.DEBUG,'Comment Offset: ' + _getCommentOffset());
                    _updateComments();
                }
                }
            }
      }
      <mt:Ignore>
      /**
       * Sets commentsOffset (i.e. the offset number to the remote list)
       * 
       * @return void
       */
      </mt:Ignore>
      function _setCommentOffset() {
        commentsOffset = commentsPerPage * (pageNum-1);
      }
      <mt:Ignore>
      /**
       * Gets the commentsOffset (i.e. the offset number to the remote list)
       * 
       * @return void
       */
      </mt:Ignore>
      function _getCommentOffset() {
        return commentsOffset;
      }
      <mt:Ignore>
      /**
       * General event handler
       * 
       * @param {Event} e The event object
       * @return void
       */
      </mt:Ignore>
      function _handleEvents (e) {
        var origin = e.target || e.srcElement,
            parentId;
        // stupid IE
        origin = origin.id && M.getEl(origin.id) || false;
        if(origin) {
          parentId = u.checkNodeType(origin.parentNode)==='element' && origin.parentNode.getAttribute('id') && origin.parentNode.id;
        } else {
          return false;
        }
        switch(origin.nodeName) {
          case 'A':
            switch (parentId) {
              case 'prev-comments':
              case 'top-prev-comments':
                if(e.preventDefault) {
                  e.preventDefault();
                } else {
                  e.returnValue =   false;
                }
                if(!isLoading) {
                  _previousPage();
                }
                break;
              case 'next-comments':
              case 'top-next-comments':
                if(e.preventDefault) {
                  e.preventDefault();
                } else {
                  e.returnValue =   false;
                }
                if(!isLoading) {
                  _nextPage();
                }
                break;
            }
            break;
        }
      }
      <mt:Ignore>
      /**
       * Toggles the visibility of the navigation links
       * 
       * @return void
       */
      </mt:Ignore>
      function _toggleNavLinks () {
        M.log(c.DEBUG,M.getEl('top-prev-comments'));
        if(pageNum <= commentsTotalPages && pageNum !== 1) {
          u.toggleVisibility.show('prev-comments');
          u.toggleVisibility.show('top-prev-comments');
        }
        if(pageNum >= 1 && pageNum !== commentsTotalPages) {
          u.toggleVisibility.show('next-comments');
          u.toggleVisibility.show('top-next-comments');
        }
        if(pageNum===1 || nav.style.visibility==='hidden') {
          u.toggleVisibility.hide('prev-comments');
          u.toggleVisibility.hide('top-prev-comments');
        }
        if(pageNum===commentsTotalPages || nav.style.visibility==='hidden') {
          u.toggleVisibility.hide('next-comments');
          u.toggleVisibility.hide('top-next-comments');
        }
      }
      <mt:Ignore>
      /**
       * Determines appropriate action based on the id of the parent
       * clicked link. Decrements pageNum based on id.
       * 
       * @param {String} id the id of the parent of the clicked link
       * @return void
       */
      </mt:Ignore>
      function _nextPage () {
        if(pageNum < commentsTotalPages) {
          pageNum++;
          _updateComments();
        }
      }
      <mt:Ignore>
      /**
       * Determines appropriate action based on the id of the parent
       * clicked link. Increments/decrements pageNum based on id.
       * 
       * @param {String} id the id of the parent of the clicked link
       * @return void
       */
      </mt:Ignore>
      function _previousPage() {
        if(pageNum > 1) {
          pageNum--;
          _updateComments();
        }
      }
      <mt:Ignore>
      /**
       * Searches for a particular comment in the list of ids
       * 
       * @param {String} id The id for which to search
       * @return {Boolean} true, if found, false otherwise
       */
      </mt:Ignore>
      function _findIdMatch (id) {
        var len = MT.commentIds.length;
        while (len--) {
            if (MT.commentIds[len] == id) {
                commentAnchor = "comment-" + id;
                commentArrId = len;
                return true;
            }
        }
        return false;
      }
      <mt:Ignore>
      /**
       * Sets the current comment counts on the page
       *
       * @return void
       */
      </mt:Ignore>
      function _setCurrentComments() {
        var commentsOnPage = pageNum != commentsTotalPages ? commentsOffset + commentsPerPage : totalComments;
        _setCurrentCommentsContent([commentsOffset+1," - ",commentsOnPage].join(''));
      }
      <mt:Ignore>
      /**
       * Sets the "current-comments" element with the HTML value
       * 
       * @param {String|Element} currentCommentsHTML The content to be set
       * @return void
       */
      </mt:Ignore>
      function _setCurrentCommentsContent(currentCommentsHTML) {
        currentCommentsSpan.innerHTML = currentCommentsHTML;
        topCurrentCommentsSpan.innerHTML = currentCommentsHTML;
      }
      <mt:Ignore>
      /**
       * Sets the content of the comment list
       * 
       * @param {String|Element} commentHTML The content to be set 
       * @return void
       */
      </mt:Ignore>
      function _setCommentContent(commentHTML) {
        commentContentDiv.innerHTML = commentHTML;
      }
      <mt:Ignore>
      /**
       * Builds the appropriate URL to make a remote call to get the
       * next set of comments
       * 
       * @return void
       */
      </mt:Ignore>
      function _updateComments() {
        var comments, jsonUrl;
        isLoading = true;
        _setCurrentCommentsContent(loadingIcon);
        _setCommentOffset();
        jsonUrl = [
            "<$mt:CGIPath$>mt-comments.cgi?__mode=comment_listing&direction=",
            direction,
            "&entry_id=",
            entryID,
            "&limit=",
            commentsPerPage,
            "&offset=",
            _getCommentOffset()
          ].join('');
        if (!commentAnchor) {
          commentAnchor = "comments-content";
        }
        if(cache.hasOwnProperty(jsonUrl)) {
          _refreshComments(cache[jsonUrl]);
          isLoading = false;
        } else {
          M.connect(jsonUrl,c.JSON,function (json) {
            cache[jsonUrl] = json.comments;
              _refreshComments(json.comments);
              isLoading = false;
          });
        }
      }
      <mt:Ignore>
      /**
       * Refreshes the comment data with the current
       * 
       * @param {String} commentData The data used to replace current comments
       * @return void
       */
      </mt:Ignore>
      function _refreshComments(commentData) {
        _setCommentContent(commentData);
        _setCurrentComments();
        window.location.hash = 'reset';
        window.location.hash = commentAnchor;
        _toggleNavLinks();
      }
    })();
    
  6. Republish your blog.

  7. View an entry with more comments than the entries_per_page variable value to view comment pagination.

    Tip: Temporarily decrease the entries_per_page variable value to a number smaller than the total number of comments and republish to view the comment pagination.

Back

2 Comments

Gercek Karakus

Gercek Karakus on November 25, 2009, 4:03 p.m. Reply

<mt:If tag="EntryCommentCount" gt="$comments_per_page">
<script type="text/javascript">
    MT.entryID = <$mt:EntryID$>;
    MT.commentsPerPage = <$mt:Var name="comments_per_page"$>;
    MT.entryCommentCount = <$mt:EntryCommentCount$>;
    MT.commentIds = [<mt:Comments sort_order="ascend" glue=","><mt:CommentID></mt:Comments>];
</script>
</mt:If>

The comment ids that are listed with the code above track the comment numbers and is a quick way to figure out where a particular comment resides (i.e. which page). So if someone comes to a page and the comment anchor is #comment-340, it checks that array to decide if it needs to refresh the comment section to another page.

Gercek Karakus

Gercek Karakus on November 25, 2009, 4:10 p.m. Reply

In order to support comment threading, Comment Listing template needs to be edited in order to hide comment responses to get listed two times.

{
    "direction": "<mt:Var name="commentDirection">",
    "comments": "<mt:Comments sort_order="$commentDirection"><mt:Unless tag="CommentParent"><$mt:Include module="Comment Detail" replace="\","\\" replace='"','\"' strip_linefeeds="1"$></mt:Unless></mt:Comments>"     
}

Also Comment Detail template needs to be replaced with the following one.

<div class="comments-content">

<mt:Include module="Comments Middle Module">

<!-- Display comment (top level parent) -->
<mt:CommentReplies> <!-- Loop through the reply comments -->
    <mt:CommentsHeader><div class="reply-container" ></mt:CommentsHeader>

        <mt:Include module="Comments Middle Module">

        <!-- Display comment (reply comment, which may be a parent of more replies) -->
        <div class="inner-reply-container" >
            <$mt:CommentRepliesRecurse$> <!-- For each reply comment, recursively display any reply comments -->    
        </div>  
    <mt:CommentsFooter></div></mt:CommentsFooter>
</mt:CommentReplies>
</div>

Comments Middle Module is just another global module, created in order to make Comment Detail template simpler:

<div class="comment<mt:If name="__last__"> last</mt:If>"<mt:IfArchiveTypeEnabled archive_type="Individual"> id="comment-<$mt:CommentID$>"</mt:IfArchiveTypeEnabled>>
<div class="inner">
 <$mt:Include module="Userpic" userpic_size="60" userpic_type="commenter"$>
    <div class="comment-header">
        <div class="asset-meta">

?__mode=view&blog_id=&id="> ">">

        </div>
    </div><!-- end comment header -->
    <div class="comment-content">
        <$mt:CommentBody$>
    </div>

<div class="reply">
 <mt:IfCommentsAccepted><div class="reply-button"><$mt:CommentReplyToLink$></div>

    <mt:IfCommentParent> <mt:Else><!-- if it's a top level category ' -->
<mt:IfCommentReplies>
    <$mt:Var name="count" value="0">
<mt:CommentReplies><$mt:setvar name="count" op="++"$>   <mt:CommentReplies><$mt:setvar name="count" op="++"$>   </mt:CommentReplies></mt:CommentReplies>
    <div class="num-replies"><mt:var name="count"> replies</div></mt:IfCommentReplies></mt:IfCommentParent>
    </mt:IfCommentsAccepted></div><!-- end reply- button -->

</div> 
</div>