Una piccola aggiunta al Disqus Helper di ToX

Qualche tempo fa il buon Emanuele Toscano ha pubblicato un comodissimo helper per integrare in cakephp il servizio di commenti Disqus.

Ho avuto finalmente occasione di provarlo – il servizio è fatto bene e offre, anche nella versione gratuita, tutta una serie di cose già pronte che permettono di risparmiare un sacco di tempo (funzione “mi piace”, condividi con facebook o con twitter, moderazione / controllo spam e tante altre piccole opzioni).

L’helper di ToX permette di implementarlo -letteralmente- in cinque minuti.

Lo svantaggio del servizio esterno ovviamente è quello di una minore integrazione rispetto ad un sistema di commenti proprio.
Ad esempio, la mail di notifica di inserimento di un nuovo commento arriva solo al “proprietario”, che va bene per un blog personale ma non per un cms multiutente – L’autore del singolo contenuto non saprà che è stato commentato..
Oppure, per vari motivi, può essere utile sincronizzare i commenti di disqus con quelli nel database della propria applicazione.

Qui Disqus offre dei ganci – nella forma di una API completa o più semplicemente una callback molto utile per l’installazione standard – proprio quella dell’helper in questione.
Ed è proprio qui che arriva la mia aggiunta, per integrare opzionalmente la callback “onNewComment” in caso serva.

 

 

  1. function makeRepliable($onNewCommentCallback = null) {
  2. $projectName = Configure::read('Disqus.projectName');
  3.  
  4. $return = '';
  5.  
  6. if(!is_null($onNewCommentCallback)) {
  7. $return .= "
  8. <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script>
  9. <script type='text/javascript'>
  10. function disqus_config() {this.callbacks.onNewComment = [function(comment) { $.post(\"$onNewCommentCallback\", comment);}];}
  11. </script>";
  12. }
  13.  
  14. $return .= '<div id="disqus_thread"></div>';
  15. $return .= $this->Javascript->link("http://disqus.com/forums/{$projectName}/embed.js");
  16. return $return;
  17. }

Semplicemente, se il metodo viene chiamato con il parametro opzionale “$onNewCommentCallback” (url dell’azione che gestirà la risposta) viene stampato un pezzettino di javascript in più, che serve a dire a disqus quale url chiamare con la sua risposta dopo che è satto inserito con successo un commento.

Qui l’helper aggiornato:

  1. <?php
  2. // ./app/views/helpers/disqus.php
  3. /**
  4.   * Disqus comment system integration Helper
  5.   *
  6.   * @author ToX - http://emanuele.itoscano.com - toss82 - at - gmail.com
  7.   *
  8.   * A little addition by Stefano Manfredini (optional anction for onNewComment callback)
  9.   *
  10.   * @help:
  11.   * In function makeRepliable, I set the projectName somewhere in my configuration files,
  12.   * remember to change this variable to something that suits your needs.
  13.   *
  14.   */
  15.  
  16. class DisqusHelper extends Helper {
  17. var $helpers = array('Html', 'Javascript');
  18.  
  19. function repliesLinkCounter() {
  20. $projectName = Configure::read('Disqus.projectName');
  21. $createJS = "
  22. (function() {
  23. var links = document.getElementsByTagName('a');
  24. var query = '?';
  25. for(var i = 0; i < links.length; i++) {
  26. if(links.href.indexOf('#disqus_thread') >= 0) {
  27. query += 'url' + i + '=' + encodeURIComponent(links.href) + '&amp;';
  28. }
  29. }
  30. document.write('<script charset=\"utf-8\" type=\"text/javascript\" src=\"http://disqus.com/forums/{$projectName}/get_num_replies.js' + query + '\"></' + 'script>');
  31. })();
  32. ";
  33. $return = $this->Javascript->codeBlock($createJS);
  34. return $return;
  35. }
  36.  
  37. /**
  38.   *
  39.   * @param string $onNewCommentCallback, plain url to cake action receiving the "new comment" feedback from Disqus
  40.   * @return the HTML to be rendered, with javascript call to Disqus service
  41.   */
  42. function makeRepliable($onNewCommentCallback = null) {
  43. $projectName = Configure::read('Disqus.projectName');
  44.  
  45. $return = '';
  46.  
  47. // added by SM - optional cakephp action for the onNewComment callback.
  48. // e.g. "http://mysite.ext/comments/send_email_notice_to_author/1234
  49. // In this action, thans to the jquery ajax call using $.post, disqus response will be available in
  50. // $this->params['form'].
  51. // Disqus response is like this: array('id' => 12345, 'text' => 'comment body'),
  52. // - you get $this->params['form']['id'] and $this->params['form']['text'] to work with;
  53. // so you can just send an email to the post author with the comment body, or use Disqus api like this:
  54. // http://docs.disqus.com/help/58/
  55. // to get the info you need about the comment, author, and so on
  56. // (and then process and save to your database as needed).
  57. // Be careful in your cakephp action - make some check (like, at least, $this->RequestHandler->isAjax())
  58. // to ensure it is not triggered bots (search engines or spambots..) who like to follow urls
  59. // written inside javascript bloks)
  60. //
  61. if(!is_null($onNewCommentCallback)) {
  62. $return .= "
  63. <script type='text/javascript'>
  64. if (typeof jQuery == 'undefined') {
  65. var script = document.createElement('script');
  66. script.type = 'text/javascript';
  67. script.src = 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js';
  68. document.getElementsByTagName('head')[0].appendChild(script);
  69. }
  70. </script>
  71.  
  72. <script type='text/javascript'>
  73. jQuery.noConflict();
  74. function disqus_config() {this.callbacks.onNewComment = [function(comment) { jQuery.post(\"$onNewCommentCallback\", comment);}];}
  75. </script>";
  76. }
  77.  
  78. $return .= '<div id="disqus_thread"></div>';
  79. $return .= $this->Javascript->link("http://disqus.com/forums/{$projectName}/embed.js");
  80. return $return;
  81. }
  82.  
  83. function recentComments($num_items = 5, $hide_avatars = 0, $avatar_size = 32, $excerpt_lenght = 200) {
  84. $projectName = Configure::read('Disqus.projectName');
  85. $return = "<div id='recentcomments' class='dsq-widget'>";
  86. $return .= "<h2 class='dsq-widget-title'>". __('Recent Comments', true) ."</h2>";
  87. $return .= $this->Javascript->link("http://disqus.com/forums/{$projectName}/recent_comments_widget.js?num_items={$num_items}&hide_avatars={$hide_avatars}&avatar_size={$avatar_size}&excerpt_length={$excerpt_lenght}");
  88. $return .= "</div>";
  89. return $return;
  90. }
  91. }
  92. ?>

Come scritto nel commento nel codice, disqus (avendo chiamato con la azione ajax di jQuery $.post, fornisce alla nostra azione una risposta che -grazie a cakephp- ci troviamo automaticamente a popolare $this->params[‘form’]. Abbiamo così a disposizione l’id ed il testo del commento. A quel punto, nell’azione in cake, possiamo semplicemente ricavare l’email dell’autore del post e mandargli un avviso via email (con il testo del commento) oppure usare l’id per recuperare tutti gli altri dettagli usando l’API di disqus, e salvare una copia locale nel nostro db o fare quel che ci serve.

Attenzione: l’azione in questione (nel suddetto esempio, /comments/send_email_notice_to_author/$id) deve avere qualche controllo per assicurare che non sia una visita “diretta” -presubimilmente da uno spambot o altro spider che segue anche i link nel javascript) ma venga legittimamente da disqus.
Si può lavorare su $this->referer(), oppure un semplice if($this->RequestHandler->isAjax()) può essere sufficiente (altrimenti c’è il rischio che vangano inviati avvisi o inseriti commenti inesistenti).

Se usate o volete provare Disqus nella vostra applicazione cakephp, e volete quel gancio in più, potete aggiungere questa piccola modifica.
Intanto un doveroso ringraziamento ad Emanuele per aver creato l’helper!