Как настроить отображение числа комментариев в Disqus 2012 по своему вкусу

25 февраля 2013

В старом Disqus, так называемом Disqus Classic, была возможность настраивать то, как будет отображаться количество комментариев к статьям. Например, если комментариев нет, на ваше усмотрение Disqus мог писать «0 комментариев», «Комментарии отсутствуют», «Нет комментариев» и тп. В Disqus 2012 такая возможность пропала. Раньше проблема решалась временным переключением на старый Disqus, но теперь и этой возможности нет.

А я как раз давно подумывал над тем, чтобы перейти с такого отображения числа комментариев:

Старое отображение числа комментариев

… на такое:

Новое отображение числа комментариев

Тогда я мог бы писать заголовки произвольной длины и они смотрелись бы по-человечески. Также, если число комментариев у какого-нибудь поста вдруг перевалит за сотню, оно будет нормально отображено. Да и страницы бложика будут грузиться чуточку быстрее за счет избавления от ненужных украшательств.

В связи с тем, что в свое время я сказал Disqus’у выводить просто число комментариев безо всяких там слов, а возможности как-то это изменить теперь нет, спрашивается, что делать-то? Погуглив немного я не смог найти какой-либо воркэраунд. Пришлось придумывать свой.

Оказалось, что Disqus отдает информацию о числе комментариев к заданному множеству статей в ответ на запрос типа:

http://disqus.com/forums/ID/get_num_replies.js?url1=URL1&url2=URL2&...

Здесь ID — это идентификатор вашего сайта в Disqus, а URL1, URL2 и тд — адреса статей, для которых требуется получить количество комментариев. В ответ приходит JavaScript, который ищет на текущей странице отрывки кода вроде:

<a href="http://example.ru/bebebe#disqus_thread">число комментариев</a>

… и заменяет текст внутри тэга на число комментариев.

Я набросал такой скрипт:

<?php
// error_reporting(E_ALL);
$secret = "SECRET!";
header("Content-type: text/javascript");

if(!isset($_GET['q']) || !isset($_GET['s']) ||
   md5($secret.$_GET['q']) != $_GET['s']) {
  echo "// invalid query checksum\n";
  exit;
}

if(rand(1,512) == 1) {
  // удаляем файлы, созданные более суток назад
  echo "// you are lucky, cleaning cache...\n";
  system("find ./cache -mtime +1 -delete");
}

$cache = "./cache/".md5($secret.$_GET['s'].floor(time() / (30 * 60)));
if(file_exists($cache)) {
  $numbers = file_get_contents($cache);
  echo "// cached\n";
} else {
  $url = "http://disqus.com/forums/eaxme/get_num_replies.js?".
         $_GET['q'];
  $data = file_get_contents($url);
  preg_match("/var num_replies = '([^']*)'/", $data, $matches);
  $numbers = $matches[1];
  file_put_contents($cache, $numbers);
}
?>
(function () {
  var nodes = document.getElementsByTagName('a');
  var disqus_nodes = [];
  var _node_is_disqus = function(node) {
    return (node.href.indexOf('#disqus_thread') >= 0);
  }
  var i;
  for (i = 0; i < nodes.length; i++) {
    try {
      if (_node_is_disqus(nodes[i])) {
        disqus_nodes.push(nodes[i]);
      }
    } catch(e) {
    }
  }
  var num_replies = '<?php echo $numbers ?>'.split(',');
  var replies_count, link_text;
  for (i = 0; i < disqus_nodes.length; i++) {
    link_text = '';
    template = '';
    replies_count = parseInt(num_replies[i], 10);
    if (replies_count !== undefined && !isNaN(replies_count)) {
      rem = replies_count % 10;
      if (replies_count > 10 && replies_count < 15) {
        template = '{num} комментариев';
      } else if (rem > 1 && rem < 5) {
        template = '{num} комментария';
      } else if (rem == 1) {
        template = '{num} комментарий';
      } else {
        template = '{num} комментариев';
      }
      link_text = template.replace('{num}', replies_count);
    }
    if (link_text) {
      try {
        disqus_nodes[i].innerHTML = link_text;
      } catch(e) {
        if (disqus_nodes[i].innerText) {
          disqus_nodes[i].innerText = link_text;
        }
      }
    }
  }
})();

Скрипт представляет собой своего рода прокси для get_num_replies.js. Он принимает два аргумента — q и s. Первый представляет собой запрос, который должен быть послан get_num_replies.js, а второй — что-то вроде цифровой подписи аргумента q, на всякий случай. Если подпись верна, скрипт шлет запрос на сервер Disqus’а, парсит ответ регулярным выражением, и возвращает немного модифицированный ответ. Чтобы не ходить слишком часто по HTTP, ответы от Disqus’а кэшируются.

Также я добавил в functions.php такой кусок кода:

function comments_number_javascript($commentsNumberQuery) {
  echo '<script type="text/javascript" src="'.
           'http://eax.me/disqus-comments/?q='.
               urlencode($commentsNumberQuery).
               '&amp;s='.md5("SECRET!".$commentsNumberQuery).
       '"></script>';
}

… вывод постов в index.php, archive.php и single.php изменил следующим образом:

<?php
  global $commentsNumberQuery;
  $commentsNumberQuery = "";
  $postNumber = 0;
  while(have_posts()):
    the_post();
    $postNumber++;
    $commentsNumberQuery .= "url".$postNumber."=".get_permalink()."&";
?>

… а в footer.php дописал:

<?php
  global $commentsNumberQuery;
  comments_number_javascript($commentsNumberQuery);
?>
</body>
</html>

В результате я убил сразу трех зайцев:

  • Решил основную задачу — выводить число комментариев в формате «N комментариев»;
  • Немного ускорил работу бложика (меньше картинок, меньше редиректов, кэширование ответа от Disqus);
  • Настроил вывод числа комментариев в полном соответствии с правилами русского языка;

Есть подозрение, что последнего вообще никогда не будет в Disqus. И решение даже получилось почти не костыльным. В общем, я доволен. А вы что скажите?

P.S. Кстати, можете меня поздравить. Это мой двухсотый пост в этом блоге.

Дополнение: К сожалению, описанный здесь API жестко привязывается к URL статьи. Если вы решите изменить этот URL, число комментариев станет перманентно равно нулю. Для решения этой проблемы можно дергать http://disqus.com/embed/comments/?f=FORUM&t_i=POSTID, где FORUM — это идентификатор вашего сайта, например eaxme, а POSTID — идентификатор поста в urlencode, например 18014%20http%3A%2F%2Feax.me%2F%3Fp%3D18014, и выдирать оттуда число комментариев. Только работать это будет несколько медленнее.

Метки: , , .


Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.