1
0
mirror of https://github.com/processwire/processwire.git synced 2025-08-13 18:24:57 +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

@@ -90,6 +90,12 @@ class Comment extends WireData {
*/ */
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 * Max bytes that a Comment may use
* *

View File

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

View File

@@ -1,5 +1,11 @@
<?php namespace ProcessWire; <?php namespace ProcessWire;
/**
*
* @method int sendAdminNotificationEmail(Comment $comment)
* @method int sendNotificationEmail(Comment $comment, $email, $subcode, array $options = array())
*
*/
class CommentNotifications extends Wire { class CommentNotifications extends Wire {
/** /**
@@ -14,6 +20,14 @@ class CommentNotifications extends Wire {
*/ */
protected $field; protected $field;
/**
* WireMail mailer module name to use
*
* @var string
*
*/
protected $mailer = '';
/* /*
* FYI * FYI
* *
@@ -34,6 +48,25 @@ class CommentNotifications extends Wire {
$this->field = $field; $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 * Send notification email to specified admin to review the comment
@@ -144,7 +177,7 @@ class CommentNotifications extends Wire {
$emails = $this->parseEmails($field->get('notificationEmail')); $emails = $this->parseEmails($field->get('notificationEmail'));
if(count($emails)) { if(count($emails)) {
$mail = $this->wire('mail')->new(); $mail = $this->newMail();
foreach($emails as $email) $mail->to($email); foreach($emails as $email) $mail->to($email);
$mail->subject($subject)->body($body)->bodyHTML($bodyHTML); $mail->subject($subject)->body($body)->bodyHTML($bodyHTML);
$fromEmail = $this->getFromEmail(); $fromEmail = $this->getFromEmail();
@@ -422,63 +455,100 @@ class CommentNotifications extends Wire {
* Send a user (not admin) notification email * Send a user (not admin) notification email
* *
* @param Comment $comment * @param Comment $comment
* @param string $email * @param string|array $email
* @param string $subcode * @param string $subcode Subscribe/unsubscribe code or blank string if not in use
* @param array $options
* @return int * @return int
* *
*/ */
public function ___sendNotificationEmail(Comment $comment, $email, $subcode) { public function ___sendNotificationEmail(Comment $comment, $email, $subcode, array $options = array()) {
$showText = (bool) $this->field->useNotifyText;
$sanitizer = $this->wire()->sanitizer;
$page = $comment->getPage(); $page = $comment->getPage();
$sanitizer = $this->wire()->sanitizer;
$title = $sanitizer->text($page->getUnformatted('title|path')); $title = $sanitizer->text($page->getUnformatted('title|path'));
$cite = $sanitizer->text($comment->cite); $cite = $sanitizer->text($comment->cite);
$url = $page->httpUrl . "#Comment$comment->id"; $showText = isset($options['showText']) ? (bool) $options['showText'] : (bool) $this->field->useNotifyText;
$unsubUrl = $page->httpUrl . "?comment_success=unsub&subcode=$subcode"; $emails = is_array($email) ? $email : array($email);
$text = $showText ? $sanitizer->textarea($comment->text) : '';
$textHTML = $showText ? $comment->getFormattedCommentText() : ''; $defaults = array(
$subject = $this->_('New comment posted:') . " $title"; // Email subject 'postedAtLabel' => sprintf($this->_('Posted at: %s'), $title),
$postedAtLabel = $this->_('Posted at: %s'); 'postedByLabel' => sprintf($this->_('Posted by: %s'), $cite),
$postedByLabel = $this->_('Posted by: %s'); 'postedAtByLabel' => $this->_('Posted at %s by %s'),
$unsubLabel = $this->_('Unsubscribe from these notifications'); 'viewLabel' => $this->_('View or reply'),
$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 = $body =
sprintf($postedAtLabel, $title) . "\n" . $options['postedAtLabel'] . "\n" .
sprintf($postedByLabel, $cite) . "\n\n" . $options['postedByLabel'] . "\n" .
($showText ? "$text\n\n" : "") . ($showText ? "$options[text]\n\n" : "") .
"$viewLabel: $url\n\n" . "$options[viewLabel]: $options[url]\n\n" .
"$unsubLabel: $unsubUrl\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); $cite = $sanitizer->entities($cite);
$title = $sanitizer->entities($title); $title = $sanitizer->entities($title);
$unsubUrl = $sanitizer->entities($unsubUrl); $unsubUrl = $sanitizer->entities($unsubUrl);
$titleLink = "<a href='$url'>$title</a>"; $titleLink = "<a href='$url'>$title</a>";
$div = "<div style='padding:10px 20px;border:1px solid #eee'>";
$bodyHTML = $bodyHTML =
"<html><head><title>$title</title><head><body>" . "<html><head><title>$title</title><head><body>" .
"<p><em>" . sprintf($this->_('Posted at %s by %s'), $titleLink, $cite) . "</em></p>" . "<p><em>" . sprintf($this->_('Posted at %s by %s'), $titleLink, $cite) . "</em></p>" .
($showText ? "\n$div<p>$textHTML</p></div>" : '') . ($showText ? "\n<div style='$options[divStyle]'><p>$options[textHTML]</p></div>" : '') .
"\n<p><a href='$url'>$viewLabel</a></p>" . "\n<p><a href='$url'>$options[viewLabel]</a></p>" .
"\n<p>&nbsp;</p>" . "\n<p>&nbsp;</p>" .
"\n<hr />" . "\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>"; "</body></html>";
$mail = $this->wire('mail')->new(); /** @var WireMail $mail */
$mail->to($email)->subject($subject)->body($body)->bodyHTML($bodyHTML); $mail = $this->newMail();
$fromEmail = $this->getFromEmail(); $mail->to($emails)
if($fromEmail) $mail->from($fromEmail); ->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(); $result = $mail->send();
if($result) { if($result) {
$this->wire('log')->message("Sent comment notification email to $email"); $this->wire()->log->message("Sent comment notification email to " . implode(', ', $emails));
} else { } else {
$this->wire('log')->error("Failed sending comment notification to $email"); $this->wire()->log->error("Failed sending comment notification to " . implode(', ', $emails));
} }
return $result; return $result;
@@ -508,7 +578,7 @@ class CommentNotifications extends Wire {
$body .= "\n\n$footer: $confirmURL"; $body .= "\n\n$footer: $confirmURL";
$bodyHTML .= "<p><strong><a href='$confirmURL'>$footer</a></strong></p>"; $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); $mail->to($email)->subject($subject)->body($body)->bodyHTML($bodyHTML);
$fromEmail = $this->getFromEmail(); $fromEmail = $this->getFromEmail();
if($fromEmail) $mail->from($fromEmail); 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 commentUnapproved(Page $page, Field $field, Comment $comment, $notes = '') #pw-hooker
* @method void commentAddReady(Page $page, Field $field, Comment $comment) #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 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"); $this->wire('log')->message("Approved comment $comment->id - $notes");
if(!$field->get('useNotify')) return; if(!$field->get('useNotify')) return; // notifications not in use
$emails = $this->getNotifyEmails($page, $field, $comment); 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 // emails array contains email address => subcode to send notifications to
if(count($emails)) { if(count($emailsData)) {
require_once(dirname(__FILE__) . '/CommentNotifications.php'); $qty = $this->sendNotifyEmails($page, $field, $comment, $emailsData);
$no = $this->wire(new CommentNotifications($page, $field)); if($qty > 0) {
foreach($emails as $email => $data) { // emails sent
$subcode = $data['subcode'];
$no->sendNotificationEmail($comment, $email, $subcode);
} }
} }
} }
@@ -1922,8 +1923,7 @@ class FieldtypeComments extends FieldtypeMulti {
* *
*/ */
public function ___commentAdded(Page $page, Field $field, Comment $comment) { public function ___commentAdded(Page $page, Field $field, Comment $comment) {
require_once(dirname(__FILE__) . '/CommentNotifications.php'); $no = $this->commentNotifications($page, $field);
$no = $this->wire(new CommentNotifications($page, $field));
$no->sendAdminNotificationEmail($comment); $no->sendAdminNotificationEmail($comment);
$this->commentMaintenance($field); $this->commentMaintenance($field);
@@ -2007,6 +2007,31 @@ class FieldtypeComments extends FieldtypeMulti {
return $emails; 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 * Add a vote to the current comment from the current user/IP
* *
@@ -2372,5 +2397,23 @@ class FieldtypeComments extends FieldtypeMulti {
return $options; 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;
}
} }