disqus-comments-number/

В старом 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://remontka.com/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%2Fremontka.com%2F%3Fp%3D18014 , и выдирать оттуда число комментариев. Только работать это будет несколько медленнее.

EnglishRussianUkrainian