1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-12 01:34:31 +02:00

Improvements to FieldtypeComments notifications to improve hookability and allow greater runtime/hook customization for how notification emails are sent.

This commit is contained in:
Ryan Cramer
2021-03-30 08:12:08 -04:00
parent 7f450dedc7
commit 31ecc54abf
4 changed files with 174 additions and 49 deletions

View File

@@ -88,7 +88,13 @@ class Comment extends WireData {
* Flag to indicate author of this comment wants notifications and request confirmed by double opt in
*
*/
const flagNotifyConfirmed = 8;
const flagNotifyConfirmed = 8;
/**
* Flag to indicate comment is queued for notifications to be sent later by 3rd party implementation
*
*/
const flagNotifyQueue = 16;
/**
* Max bytes that a Comment may use

View File

@@ -861,7 +861,7 @@ class CommentForm extends Wire implements CommentFormInterface {
/** @var Comment $comment */
$comment = $this->wire(new Comment());
$comment->user_agent = $_SERVER['HTTP_USER_AGENT'];
$comment->user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '';
$comment->ip = $this->wire('session')->getIP();
$comment->created_users_id = $this->user->id;
//$comment->sort = count($this->comments)+1;
@@ -872,7 +872,13 @@ class CommentForm extends Wire implements CommentFormInterface {
if($parent) {
// validate that depth is in allowed limit
$parents = $this->commentsField->getCommentParents($this->page, $comment);
if($parents->count() >= $maxDepth) $comment->parent_id = 0;
if($parents->count() >= $maxDepth) {
if($parent->parent_id) {
$comment->parent_id = $parent->parent_id;
} else {
$comment->parent_id = 0;
}
}
} else {
// parent does not exist on this page
$comment->parent_id = 0;

View File

@@ -1,5 +1,11 @@
<?php namespace ProcessWire;
/**
*
* @method int sendAdminNotificationEmail(Comment $comment)
* @method int sendNotificationEmail(Comment $comment, $email, $subcode, array $options = array())
*
*/
class CommentNotifications extends Wire {
/**
@@ -14,6 +20,14 @@ class CommentNotifications extends Wire {
*/
protected $field;
/**
* WireMail mailer module name to use
*
* @var string
*
*/
protected $mailer = '';
/*
* FYI
*
@@ -34,6 +48,25 @@ class CommentNotifications extends Wire {
$this->field = $field;
}
/**
* Set name of WireMail module to use for sending notifications
*
* @param string $mailer
*
*/
public function setMailer($mailer) {
$this->mailer = $mailer;
}
/**
* @return WireMail
*
*/
public function newMail() {
$options = array();
if($this->mailer) $options['module'] = $this->mailer;
return $this->wire()->mail->new($options);
}
/**
* Send notification email to specified admin to review the comment
@@ -144,7 +177,7 @@ class CommentNotifications extends Wire {
$emails = $this->parseEmails($field->get('notificationEmail'));
if(count($emails)) {
$mail = $this->wire('mail')->new();
$mail = $this->newMail();
foreach($emails as $email) $mail->to($email);
$mail->subject($subject)->body($body)->bodyHTML($bodyHTML);
$fromEmail = $this->getFromEmail();
@@ -422,63 +455,100 @@ class CommentNotifications extends Wire {
* Send a user (not admin) notification email
*
* @param Comment $comment
* @param string $email
* @param string $subcode
* @param string|array $email
* @param string $subcode Subscribe/unsubscribe code or blank string if not in use
* @param array $options
* @return int
*
*/
public function ___sendNotificationEmail(Comment $comment, $email, $subcode) {
$showText = (bool) $this->field->useNotifyText;
$sanitizer = $this->wire()->sanitizer;
public function ___sendNotificationEmail(Comment $comment, $email, $subcode, array $options = array()) {
$page = $comment->getPage();
$title = $sanitizer->text($page->getUnformatted('title|path'));
$cite = $sanitizer->text($comment->cite);
$url = $page->httpUrl . "#Comment$comment->id";
$unsubUrl = $page->httpUrl . "?comment_success=unsub&subcode=$subcode";
$text = $showText ? $sanitizer->textarea($comment->text) : '';
$textHTML = $showText ? $comment->getFormattedCommentText() : '';
$subject = $this->_('New comment posted:') . " $title"; // Email subject
$postedAtLabel = $this->_('Posted at: %s');
$postedByLabel = $this->_('Posted by: %s');
$unsubLabel = $this->_('Unsubscribe from these notifications');
$viewLabel = $this->_('View or reply');
$sanitizer = $this->wire()->sanitizer;
$title = $sanitizer->text($page->getUnformatted('title|path'));
$cite = $sanitizer->text($comment->cite);
$showText = isset($options['showText']) ? (bool) $options['showText'] : (bool) $this->field->useNotifyText;
$emails = is_array($email) ? $email : array($email);
$defaults = array(
'postedAtLabel' => sprintf($this->_('Posted at: %s'), $title),
'postedByLabel' => sprintf($this->_('Posted by: %s'), $cite),
'postedAtByLabel' => $this->_('Posted at %s by %s'),
'viewLabel' => $this->_('View or reply'),
'showText' => $showText,
'url' => $page->httpUrl . "#Comment$comment->id",
'unsubLabel' => $this->_('Unsubscribe from these notifications'),
'unsubUrl' => (strlen($subcode) ? $page->httpUrl . "?comment_success=unsub&subcode=$subcode" : ''),
'subject' => $this->_('New comment posted:') . " $title", // Email subject
'text' => $showText ? $sanitizer->textarea($comment->text) : '',
'textHTML' => $showText ? $comment->getFormattedCommentText() : '',
'divStyle' => "padding:10px 20px;border:1px solid #eee",
'ccEmails' => array(),
'bccEmails' => array(),
'fromEmail' => $this->getFromEmail(),
'replyToEmail' => '',
);
$options = array_merge($defaults, $options);
$unsubUrl = $options['unsubUrl'];
$body =
sprintf($postedAtLabel, $title) . "\n" .
sprintf($postedByLabel, $cite) . "\n\n" .
($showText ? "$text\n\n" : "") .
"$viewLabel: $url\n\n" .
"$unsubLabel: $unsubUrl\n\n";
$options['postedAtLabel'] . "\n" .
$options['postedByLabel'] . "\n" .
($showText ? "$options[text]\n\n" : "") .
"$options[viewLabel]: $options[url]\n\n" .
"---\n" .
(strlen($unsubUrl) ? "$options[unsubLabel]: $options[unsubUrl]\n\n" : "$options[unsubLabel]\n\n");
$url = $sanitizer->entities($url);
$url = $sanitizer->entities($options['url']);
$cite = $sanitizer->entities($cite);
$title = $sanitizer->entities($title);
$unsubUrl = $sanitizer->entities($unsubUrl);
$titleLink = "<a href='$url'>$title</a>";
$div = "<div style='padding:10px 20px;border:1px solid #eee'>";
$bodyHTML =
"<html><head><title>$title</title><head><body>" .
"<p><em>" . sprintf($this->_('Posted at %s by %s'), $titleLink, $cite) . "</em></p>" .
($showText ? "\n$div<p>$textHTML</p></div>" : '') .
"\n<p><a href='$url'>$viewLabel</a></p>" .
($showText ? "\n<div style='$options[divStyle]'><p>$options[textHTML]</p></div>" : '') .
"\n<p><a href='$url'>$options[viewLabel]</a></p>" .
"\n<p>&nbsp;</p>" .
"\n<hr />" .
"\n<p><small><a href='$unsubUrl'>$unsubLabel</a></small></p>" .
"\n<p><small>" .
(strlen($unsubUrl) ? "<a href='$unsubUrl'>$options[unsubLabel]</a>" : "$options[unsubLabel]") .
"</small></p>" .
"</body></html>";
$mail = $this->wire('mail')->new();
$mail->to($email)->subject($subject)->body($body)->bodyHTML($bodyHTML);
$fromEmail = $this->getFromEmail();
if($fromEmail) $mail->from($fromEmail);
/** @var WireMail $mail */
$mail = $this->newMail();
$mail->to($emails)
->subject($options['subject'])
->body($body)
->bodyHTML($bodyHTML);
if($options['fromEmail']) {
$mail->from($options['fromEmail']);
}
if($options['replyToEmail']) {
$mail->replyTo($options['replyToEmail']);
}
if($options['ccEmails'] && is_array($options['ccEmails'])) {
$mail->header('cc', implode(',', $options['ccEmails']));
$emails = array_merge($emails, $options['ccEmails']);
}
if($options['bccEmails'] && is_array($options['bccEmails'])) {
$mail->header('bcc', implode(',', $options['bccEmails']));
$emails = array_merge($emails, $options['ccEmails']);
}
$result = $mail->send();
if($result) {
$this->wire('log')->message("Sent comment notification email to $email");
$this->wire()->log->message("Sent comment notification email to " . implode(', ', $emails));
} else {
$this->wire('log')->error("Failed sending comment notification to $email");
$this->wire()->log->error("Failed sending comment notification to " . implode(', ', $emails));
}
return $result;
@@ -508,7 +578,7 @@ class CommentNotifications extends Wire {
$body .= "\n\n$footer: $confirmURL";
$bodyHTML .= "<p><strong><a href='$confirmURL'>$footer</a></strong></p>";
$mail = $this->wire('mail')->new();
$mail = $this->newMail();
$mail->to($email)->subject($subject)->body($body)->bodyHTML($bodyHTML);
$fromEmail = $this->getFromEmail();
if($fromEmail) $mail->from($fromEmail);

View File

@@ -34,6 +34,7 @@ require_once($dirname . "/CommentField.php");
* @method void commentUnapproved(Page $page, Field $field, Comment $comment, $notes = '') #pw-hooker
* @method void commentAddReady(Page $page, Field $field, Comment $comment) #pw-hooker
* @method void commentAdded(Page $page, Field $field, Comment $comment) #pw-hooker
* @method int sendNotifyEmails(Page $page, Field $field, Comment $comment, array $emailsData)
*
*
*/
@@ -1864,16 +1865,16 @@ class FieldtypeComments extends FieldtypeMulti {
$this->wire('log')->message("Approved comment $comment->id - $notes");
if(!$field->get('useNotify')) return;
$emails = $this->getNotifyEmails($page, $field, $comment);
if(!$field->get('useNotify')) return; // notifications not in use
if($comment->flags & Comment::flagNotifyQueue) return; // comment queued for 3rd party notifications
$emailsData = $this->getNotifyEmails($page, $field, $comment);
// emails array contains email address => subcode to send notifications to
if(count($emails)) {
require_once(dirname(__FILE__) . '/CommentNotifications.php');
$no = $this->wire(new CommentNotifications($page, $field));
foreach($emails as $email => $data) {
$subcode = $data['subcode'];
$no->sendNotificationEmail($comment, $email, $subcode);
if(count($emailsData)) {
$qty = $this->sendNotifyEmails($page, $field, $comment, $emailsData);
if($qty > 0) {
// emails sent
}
}
}
@@ -1922,8 +1923,7 @@ class FieldtypeComments extends FieldtypeMulti {
*
*/
public function ___commentAdded(Page $page, Field $field, Comment $comment) {
require_once(dirname(__FILE__) . '/CommentNotifications.php');
$no = $this->wire(new CommentNotifications($page, $field));
$no = $this->commentNotifications($page, $field);
$no->sendAdminNotificationEmail($comment);
$this->commentMaintenance($field);
@@ -2006,6 +2006,31 @@ class FieldtypeComments extends FieldtypeMulti {
return $emails;
}
/**
* Get emails (and other data) of people that should be notified for a given Pages comments
*
* @param Page $page
* @param Field $field
* @param Comment|null $comment
* @param array $emailsData
* @return int
* @since 3.0.175
*
*/
public function ___sendNotifyEmails(Page $page, Field $field, Comment $comment, array $emailsData) {
$no = $this->commentNotifications($page, $field);
$cnt = 0;
foreach($emailsData as $data) {
$subcode = $data['subcode'];
$email = $data['email'];
$cnt += $no->sendNotificationEmail($comment, $email, $subcode);
}
return $cnt;
}
/**
* Add a vote to the current comment from the current user/IP
@@ -2371,6 +2396,24 @@ class FieldtypeComments extends FieldtypeMulti {
$options['test'] = true;
return $options;
}
/**
* Get instance of CommentNotifications class
*
* #pw-internal
*
* @param Page $page
* @param Field $field
* @return CommentNotifications
* @since 3.0.175
*
*/
public function commentNotifications(Page $page, Field $field) {
require_once(dirname(__FILE__) . '/CommentNotifications.php');
$no = new CommentNotifications($page, $field);
$this->wire($no);
return $no;
}
}