From 5f50c089708f2f7dd0168078b4ceb885e89964af Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Tue, 13 Oct 2015 23:39:13 +0200 Subject: [PATCH 1/4] Works with the Form plugin --- README.md | 6 +- admin/templates/comments.html.twig | 27 ++++ blueprints.yaml | 31 ++++ comments.php | 170 ++++++++++------------ comments.yaml | 72 +++++++++- languages.yaml | 2 + templates/email/base.html.twig | 194 -------------------------- templates/partials/comments.html.twig | 123 +++------------- 8 files changed, 221 insertions(+), 404 deletions(-) create mode 100644 blueprints.yaml delete mode 100644 templates/email/base.html.twig diff --git a/README.md b/README.md index bcf7587..5f0ae36 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,9 @@ For example, in Antimatter, in `templates/item.html.twig`: The comment form will appear to the blog post items. -# Enable the Captcha anti-spam filter +# Enabling Recaptcha -To reduce spam in your comments, enable the Google Recaptcha integration we added. Copy the plugin's `comments.yaml` to `user/config/plugins/comments.yaml` and enable `use_captcha`. Also add the Google Recaptcha API keys to allow it to work correctly. +The plugin comes with Recaptcha integration. To make it work, add your own Recaptcha `site` and `secret` keys the the plugin yaml config file. # Where are the comments stored? @@ -61,7 +61,7 @@ Further improvements to the comments visualization will be added in the next rel # Email notifications -Upon receiving a comment, if `enable_email_notifications` is enabled, the Comments plugin will send an email to the `notifications_email_to` address set in the plugin options. +The plugin interacts with the Email plugin to send emails upon receiving a comment. # Things still missing diff --git a/admin/templates/comments.html.twig b/admin/templates/comments.html.twig index 3ea7829..f5fcc04 100644 --- a/admin/templates/comments.html.twig +++ b/admin/templates/comments.html.twig @@ -105,6 +105,33 @@

Showing {{grav.twig.comments.totalRetrieved}} comments of {{grav.twig.comments.totalAvailable}}

+

Recently commented pages

+ +
+ + + + + + + + {% for page in grav.twig.pages %} + + + + + + {% endfor %} + +
PageNumber of commentsLast commented on
{{page.title}}{{page.commentsCount}}Page: {{page.lastCommentDate}}
+ + {% if grav.twig.comments.totalRetrieved < grav.twig.comments.totalAvailable %} + + {% endif %} +
+ {% endblock %} diff --git a/blueprints.yaml b/blueprints.yaml new file mode 100644 index 0000000..11220ad --- /dev/null +++ b/blueprints.yaml @@ -0,0 +1,31 @@ +name: Comments +version: 0.1.0 +description: Adds a commenting functionality to your site +icon: comment +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-comments +keywords: guestbook, plugin +bugs: https://github.com/getgrav/grav-plugin-comments/issues +readme: https://github.com/getgrav/grav-plugin-comments/blob/develop/README.md +license: MIT + +dependencies: + - form + - email + +form: + validation: loose + fields: + enabled: + type: toggle + label: Plugin status + highlight: 1 + default: 0 + options: + 1: Enabled + 0: Disabled + validate: + type: bool diff --git a/comments.php b/comments.php index 3d1eee3..3396bd9 100644 --- a/comments.php +++ b/comments.php @@ -23,9 +23,27 @@ class CommentsPlugin extends Plugin { return [ 'onPluginsInitialized' => ['onPluginsInitialized', 0], + 'onFormProcessed' => ['onFormProcessed', 0], + 'onPageInitialized' => ['onPageInitialized', 0], ]; } + /** + * Initialize form if the page has one. Also catches form processing if user posts the form. + */ + public function onPageInitialized() + { + /** @var Page $page */ + $page = $this->grav['page']; + if (!$page) { + return; + } + + $header = $page->header(); + $header->form = $this->grav['config']->get('plugins.comments.form'); + $page->header($header); + } + /** */ public function onPluginsInitialized() @@ -36,15 +54,7 @@ class CommentsPlugin extends Plugin 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], ]); - $this->addCommentURL = $this->config->get('plugins.comments.addCommentURL', '/add-comment'); - - if ($this->addCommentURL && $this->addCommentURL == $this->grav['uri']->path()) { - $this->enable([ - 'onPagesInitialized' => ['addComment', 0] - ]); - } else { - $this->grav['twig']->comments = $this->fetchComments(); - } + $this->grav['twig']->comments = $this->fetchComments(); } else { @@ -74,94 +84,65 @@ class CommentsPlugin extends Plugin } } - public function addComment() + /** + * Handle form processing instructions. + * + * @param Event $event + */ + public function onFormProcessed(Event $event) { - $post = !empty($_POST) ? $_POST : []; + $form = $event['form']; + $action = $event['action']; + $params = $event['params']; - $lang = filter_var(urldecode($post['lang']), FILTER_SANITIZE_STRING); - $path = filter_var(urldecode($post['path']), FILTER_SANITIZE_STRING); - $text = filter_var(urldecode($post['text']), FILTER_SANITIZE_STRING); - $name = filter_var(urldecode($post['name']), FILTER_SANITIZE_STRING); - $email = filter_var(urldecode($post['email']), FILTER_SANITIZE_STRING); - $title = filter_var(urldecode($post['title']), FILTER_SANITIZE_STRING); - - if ($this->config->get('plugins.comments.use_captcha')) { - //Validate the captcha - $recaptchaResponse = filter_var(urldecode($post['recaptchaResponse']), FILTER_SANITIZE_STRING); - - $url = 'https://www.google.com/recaptcha/api/siteverify?secret='; - $url .= $this->config->get('plugins.comments.recatpcha_secret'); - $url .= '&response=' . $recaptchaResponse; - $response = json_decode(file_get_contents($url), true); - - if ($response['success'] == false) { - throw new \RuntimeException('Error validating the Captcha'); - } + if (!$this->active) { + return; } - $filename = DATA_DIR . 'comments'; - $filename .= ($lang ? '/' . $lang : ''); - $filename .= $path . '.yaml'; - $file = File::instance($filename); + switch ($action) { + case 'addComment': + $post = !empty($_POST) ? $_POST : []; - if (file_exists($filename)) { - $data = Yaml::parse($file->content()); + $lang = filter_var(urldecode($post['lang']), FILTER_SANITIZE_STRING); + $path = filter_var(urldecode($post['path']), FILTER_SANITIZE_STRING); + $text = filter_var(urldecode($post['text']), FILTER_SANITIZE_STRING); + $name = filter_var(urldecode($post['name']), FILTER_SANITIZE_STRING); + $email = filter_var(urldecode($post['email']), FILTER_SANITIZE_STRING); + $title = filter_var(urldecode($post['title']), FILTER_SANITIZE_STRING); + /** @var Language $language */ + $language = $this->grav['language']; + $lang = $language->getLanguage(); - $data['comments'][] = [ - 'text' => $text, - 'date' => gmdate('D, d M Y H:i:s', time()), - 'author' => $name, - 'email' => $email - ]; - } else { - $data = array( - 'title' => $title, - 'lang' => $lang, - 'comments' => array([ - 'text' => $text, - 'date' => gmdate('D, d M Y H:i:s', time()), - 'author' => $name, - 'email' => $email - ]) - ); + $filename = DATA_DIR . 'comments'; + $filename .= ($lang ? '/' . $lang : ''); + $filename .= $path . '.yaml'; + $file = File::instance($filename); + + if (file_exists($filename)) { + $data = Yaml::parse($file->content()); + + $data['comments'][] = [ + 'text' => $text, + 'date' => gmdate('D, d M Y H:i:s', time()), + 'author' => $name, + 'email' => $email + ]; + } else { + $data = array( + 'title' => $title, + 'lang' => $lang, + 'comments' => array([ + 'text' => $text, + 'date' => gmdate('D, d M Y H:i:s', time()), + 'author' => $name, + 'email' => $email + ]) + ); + } + + $file->save(Yaml::dump($data)); + break; } - - $file->save(Yaml::dump($data)); - - if (isset($this->grav['Email']) && $this->grav['config']->get('plugins.comments.enable_email_notifications')) { - $this->sendEmailNotification(array( - 'title' => $title, - 'comment' => array( - 'text' => $text, - 'date' => gmdate('D, d M Y H:i:s', time()), - 'author' => $name, - 'email' => $email - ) - )); - } - - exit(); - } - - private function sendEmailNotification($comment) { - /** @var Language $l */ - $l = $this->grav['language']; - - $sitename = $this->grav['config']->get('site.title', 'Website'); - $from = $this->grav['config']->get('plugins.email.from', 'noreply@getgrav.org'); - $to = $this->grav['config']->get('plugins.email.email'); - - $subject = $l->translate(['PLUGIN_COMMENTS.NEW_COMMENT_EMAIL_SUBJECT', $sitename]); - $content = $l->translate(['PLUGIN_COMMENTS.NEW_COMMENT_EMAIL_BODY', $sitename, $comment['title'], $comment['comment']['text'], $comment['comment']['author'], $comment['comment']['email']]); - - $twig = $this->grav['twig']; - $body = $twig->processTemplate('email/base.html.twig', ['content' => $content]); - - $message = $this->grav['Email']->message($subject, $body, 'text/html') - ->setFrom($from) - ->setTo($to); - - $sent = $this->grav['Email']->send($message); } private function getFilesOrderedByModifiedDate($path = '') { @@ -242,15 +223,8 @@ class CommentsPlugin extends Plugin }); $totalAvailable = count($comments); - $comments = array_slice($comments, $page * $number, $number); - $totalRetrieved = count($comments); - $hasMore = false; - - if ($totalAvailable > $totalRetrieved) { - $hasMore = true; - } return (object)array( "comments" => $comments, @@ -264,7 +238,7 @@ class CommentsPlugin extends Plugin * Return the comments associated to the current route */ private function fetchComments() { - $lang = $this->grav['language']->getActive(); + $lang = $this->grav['language']->getLanguage(); $filename = $lang ? '/' . $lang : ''; $filename .= $this->grav['uri']->path() . '.yaml'; diff --git a/comments.yaml b/comments.yaml index 89ec74b..d443c0f 100644 --- a/comments.yaml +++ b/comments.yaml @@ -1,6 +1,68 @@ enabled: true -use_captcha: false -recatpcha_site_key: '' -recatpcha_secret: '' -enable_email_notifications: false -notifications_email_to: 'noreply@getgrav.org' \ No newline at end of file +form: + name: comments + fields: + - name: name + label: Name + placeholder: Enter your name + autofocus: on + autocomplete: on + type: text + validate: + required: true + + - name: email + label: Email + placeholder: Enter your email address + type: email + validate: + required: true + + - name: text + label: Message + placeholder: Enter your message + type: textarea + validate: + required: true + + - name: date + type: hidden + process: + fillWithCurrentDateTime: true + + - name: title + type: hidden + evaluateDefault: grav.page.header.title + + - name: lang + type: hidden + evaluateDefault: grav.language.getLanguage + + - name: path + type: hidden + evaluateDefault: grav.uri.path + + # - name: g-recaptcha-response + # label: Captcha + # type: captcha + # recatpcha_site_key: 6Lde4gwTAAAAAAZuv4z2AgVU6Xamn5twDYzQr8hv + # recaptcha_not_validated: 'Captcha not valid!' + # validate: + # required: true + # process: + # ignore: true + + buttons: + - type: submit + value: Submit + + process: + # - email: + # subject: "[Site Guestbook] {{ form.value.name|e }}" + # body: "{% include 'forms/data.html.twig' %}" + # - captcha: + # recatpcha_secret: 6Lde4gwTAAAAAPpwVKuaYm53n2bWfFfxcDxSlI54 + - addComment: + - message: Thank you for writing your comment! + + diff --git a/languages.yaml b/languages.yaml index 917ef58..e4a65da 100644 --- a/languages.yaml +++ b/languages.yaml @@ -1,5 +1,6 @@ en: PLUGIN_COMMENTS: + ADD_COMMENT: Add a comment COMMENTS: Comments EMAIL_NOT_CONFIGURED: Email not configured NEW_COMMENT_EMAIL_SUBJECT: 'New comment on %1$s' @@ -11,6 +12,7 @@ en: BY: by it: PLUGIN_COMMENTS: + ADD_COMMENT: Aggiungi un commento COMMENTS: Commenti EMAIL_NOT_CONFIGURED: Email non configurata NEW_COMMENT_EMAIL_SUBJECT: 'Nuovo commento su %1$s' diff --git a/templates/email/base.html.twig b/templates/email/base.html.twig deleted file mode 100644 index 5405424..0000000 --- a/templates/email/base.html.twig +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - Comments Email Template - - - - - - - - - - - - -
-
- - - - -
- {{ content }} -
-
-
- - - - - - - - - - - - - - diff --git a/templates/partials/comments.html.twig b/templates/partials/comments.html.twig index acc651c..7dec8e4 100644 --- a/templates/partials/comments.html.twig +++ b/templates/partials/comments.html.twig @@ -1,113 +1,28 @@ -{% set use_captcha = grav.config.plugins.comments.use_captcha %} +

{{'PLUGIN_COMMENTS.ADD_COMMENT'|t}}

-

Add a Comment

+
+{% for field in grav.config.plugins.comments.form.fields %} - - -{% if use_captcha %} - - - -{% endif %} - - - - - - {{'PLUGIN_COMMENTS.NAME'|t}} - {{'PLUGIN_COMMENTS.EMAIL'|t}} - {% if use_captcha %} -
+ {% set value = form.value(field.name) %} + {% if field.evaluateDefault %} + {% set value = evaluate(field.evaluateDefault) %} {% endif %} +
+ {% include "forms/fields/#{field.type}/#{field.type}.html.twig" %} +
+{% endfor %} - +
+ {% for button in grav.config.plugins.comments.form.buttons %} + + {% endfor %} +
+
{{ form.message }}
+ {% if grav.twig.comments|length %}

{{'PLUGIN_COMMENTS.COMMENTS'|t}}

From f064eb3bbbf1c3212168742407179638b5fe815e Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 15 Oct 2015 15:43:29 +0200 Subject: [PATCH 2/4] Drop unneeded param --- templates/partials/comments.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/partials/comments.html.twig b/templates/partials/comments.html.twig index 7dec8e4..f572482 100644 --- a/templates/partials/comments.html.twig +++ b/templates/partials/comments.html.twig @@ -1,7 +1,7 @@

{{'PLUGIN_COMMENTS.ADD_COMMENT'|t}}

{% for field in grav.config.plugins.comments.form.fields %} From fe66c4bfd60c4011d8f80ac0d91402262147ca50 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 15 Oct 2015 15:43:45 +0200 Subject: [PATCH 3/4] Fix order of events preventing new comment from appearing immediately --- comments.php | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/comments.php b/comments.php index 3396bd9..9570777 100644 --- a/comments.php +++ b/comments.php @@ -25,6 +25,7 @@ class CommentsPlugin extends Plugin 'onPluginsInitialized' => ['onPluginsInitialized', 0], 'onFormProcessed' => ['onFormProcessed', 0], 'onPageInitialized' => ['onPageInitialized', 0], + 'onTwigSiteVariables' => ['onTwigSiteVariables', 0] ]; } @@ -33,15 +34,25 @@ class CommentsPlugin extends Plugin */ public function onPageInitialized() { - /** @var Page $page */ - $page = $this->grav['page']; - if (!$page) { - return; - } + if (!$this->isAdmin()) { + /** @var Page $page */ + $page = $this->grav['page']; + if (!$page) { + return; + } - $header = $page->header(); - $header->form = $this->grav['config']->get('plugins.comments.form'); - $page->header($header); + $header = $page->header(); + if (!isset($header->form)) { + $header->form = $this->grav['config']->get('plugins.comments.form'); + $page->header($header); + } + } + } + + public function onTwigSiteVariables() { + if (!$this->isAdmin()) { + $this->grav['twig']->comments = $this->fetchComments(); + } } /** @@ -54,8 +65,6 @@ class CommentsPlugin extends Plugin 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], ]); - $this->grav['twig']->comments = $this->fetchComments(); - } else { /** @var Uri $uri */ From 13252376e43aac8d29c216cc0cfef1ac973f59e5 Mon Sep 17 00:00:00 2001 From: Flavio Copes Date: Thu, 15 Oct 2015 18:04:02 +0200 Subject: [PATCH 4/4] Add enable_on_routes and disable_on_routes config options Example usage: enable_on_routes: - '/blog' disable_on_routes: - /blog/blog-post-to-ignore - /ignore-this-route #- '/blog/daring-fireball-link' --- comments.php | 42 +++++++++++++++- comments.yaml | 13 ++++- templates/partials/comments.html.twig | 71 ++++++++++++++------------- 3 files changed, 89 insertions(+), 37 deletions(-) diff --git a/comments.php b/comments.php index 9570777..c3df1b7 100644 --- a/comments.php +++ b/comments.php @@ -15,6 +15,7 @@ use Symfony\Component\Yaml\Yaml; class CommentsPlugin extends Plugin { protected $route = 'comments'; + protected $enable = false; /** * @return array @@ -51,7 +52,43 @@ class CommentsPlugin extends Plugin public function onTwigSiteVariables() { if (!$this->isAdmin()) { - $this->grav['twig']->comments = $this->fetchComments(); + $this->grav['twig']->enable = $this->enable; + + if ($this->enable) { + $this->grav['twig']->comments = $this->fetchComments(); + } + } + } + + /** + * Determine if $haystack starts with $needle. Credit: http://stackoverflow.com/a/10473026/205039 + */ + private function startsWith($haystack, $needle) { + return $needle === "" || strrpos($haystack, $needle, -strlen($haystack)) !== FALSE; + } + + /** + * Determine if the plugin should be enabled based on the enable_on_routes and disable_on_routes config options + */ + private function calculateEnable() { + $uri = $this->grav['uri']; + + $disable_on_routes = (array) $this->config->get('plugins.comments.disable_on_routes'); + $enable_on_routes = (array) $this->config->get('plugins.comments.enable_on_routes'); + + $path = $uri->path(); + + if (!in_array($path, $disable_on_routes)) { + if (in_array($path, $enable_on_routes)) { + $this->enable = true; + } else { + foreach($enable_on_routes as $route) { + if ($this->startsWith($path, $route)) { + $this->enable = true; + break; + } + } + } } } @@ -61,6 +98,8 @@ class CommentsPlugin extends Plugin { if (!$this->isAdmin()) { + $this->calculateEnable(); + $this->enable([ 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], ]); @@ -118,6 +157,7 @@ class CommentsPlugin extends Plugin $name = filter_var(urldecode($post['name']), FILTER_SANITIZE_STRING); $email = filter_var(urldecode($post['email']), FILTER_SANITIZE_STRING); $title = filter_var(urldecode($post['title']), FILTER_SANITIZE_STRING); + /** @var Language $language */ $language = $this->grav['language']; $lang = $language->getLanguage(); diff --git a/comments.yaml b/comments.yaml index d443c0f..13a3cf7 100644 --- a/comments.yaml +++ b/comments.yaml @@ -1,4 +1,13 @@ enabled: true + +enable_on_routes: + - '/blog' + +disable_on_routes: + - /blog/blog-post-to-ignore + - /ignore-this-route + #- '/blog/daring-fireball-link' + form: name: comments fields: @@ -45,7 +54,7 @@ form: # - name: g-recaptcha-response # label: Captcha # type: captcha - # recatpcha_site_key: 6Lde4gwTAAAAAAZuv4z2AgVU6Xamn5twDYzQr8hv + # recatpcha_site_key: e32iojeoi32jeoi32jeoij32oiej32oiej3 # recaptcha_not_validated: 'Captcha not valid!' # validate: # required: true @@ -61,7 +70,7 @@ form: # subject: "[Site Guestbook] {{ form.value.name|e }}" # body: "{% include 'forms/data.html.twig' %}" # - captcha: - # recatpcha_secret: 6Lde4gwTAAAAAPpwVKuaYm53n2bWfFfxcDxSlI54 + # recatpcha_secret: ej32oiej23oiej32oijeoi32jeio32je - addComment: - message: Thank you for writing your comment! diff --git a/templates/partials/comments.html.twig b/templates/partials/comments.html.twig index f572482..3462a23 100644 --- a/templates/partials/comments.html.twig +++ b/templates/partials/comments.html.twig @@ -1,41 +1,44 @@ -

{{'PLUGIN_COMMENTS.ADD_COMMENT'|t}}

+{% if grav.twig.enable %} - -{% for field in grav.config.plugins.comments.form.fields %} +

{{'PLUGIN_COMMENTS.ADD_COMMENT'|t}}

- {% set value = form.value(field.name) %} - {% if field.evaluateDefault %} - {% set value = evaluate(field.evaluateDefault) %} - {% endif %} -
- {% include "forms/fields/#{field.type}/#{field.type}.html.twig" %} -
-{% endfor %} + + {% for field in grav.config.plugins.comments.form.fields %} -
- {% for button in grav.config.plugins.comments.form.buttons %} - + {% set value = form.value(field.name) %} + {% if field.evaluateDefault %} + {% set value = evaluate(field.evaluateDefault) %} + {% endif %} +
+ {% include "forms/fields/#{field.type}/#{field.type}.html.twig" %} +
{% endfor %} -
- -
{{ form.message }}
- -{% if grav.twig.comments|length %} - -

{{'PLUGIN_COMMENTS.COMMENTS'|t}}

- - - {% for comment in grav.twig.comments|array_reverse %} - - - +
+ {% for button in grav.config.plugins.comments.form.buttons %} + {% endfor %} -
- {{comment.text|e}} -
- {{'PLUGIN_COMMENTS.WRITTEN_ON'|t}} {{comment.date|e}} {{'PLUGIN_COMMENTS.BY'|t}} {{comment.author|e}} -
+ + + +
{{ form.message }}
+ + {% if grav.twig.comments|length %} + +

{{'PLUGIN_COMMENTS.COMMENTS'|t}}

+ + + {% for comment in grav.twig.comments|array_reverse %} + + + + {% endfor %} +
+ {{comment.text|e}} +
+ {{'PLUGIN_COMMENTS.WRITTEN_ON'|t}} {{comment.date|e}} {{'PLUGIN_COMMENTS.BY'|t}} {{comment.author|e}} +
+ {% endif %} {% endif %} \ No newline at end of file