← На главную

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

В старом 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. И решение даже получилось почти не костыльным. В общем, я доволен.

Дополнение: К сожалению, описанный здесь 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, и выдирать оттуда число комментариев. Только работать это будет несколько медленнее.