mirror of
https://github.com/processwire/processwire.git
synced 2025-08-13 02:04:35 +02:00
Various comments field updates: Add support for searching flags property in FieldtypeComments::find() method. Add new field configuration option to include comment text in notification emails (useNotifyText). Fix issue where comment notification emails linked to just Page URL rather than page Page URL with comment ID #fragment. Add FieldtypeComments::getNotifyEmails() new API method for getting notification emails. Add Comment::getFormattedCommentText() method to expand options and clarify how comment text is returned. Improve HTML version of notification emails sent by CommentNotifications::sendNotificationEmail(). Add ‘notifyDefault’ option to CommentForm class so you can specify a different default notification option other than ‘off’.
This commit is contained in:
@@ -28,6 +28,8 @@
|
||||
* @property int $upvotes
|
||||
* @property int $downvotes
|
||||
* @property int $stars
|
||||
* @property null|bool $isNew Was this comment added in this request? (since 3.0.169)
|
||||
* @property null|string $approvalNote Runtime approval note for newly added comment, internal use (since 3.0.169)
|
||||
* @property-read Comment|null $parent Parent comment when depth is enabled or null if no parent (since 3.0.149)
|
||||
* @property-read CommentArray $parents All parent comments (since 3.0.149)
|
||||
* @property-read CommentArray $children Immediate child comments (since 3.0.149)
|
||||
@@ -149,10 +151,20 @@ class Comment extends WireData {
|
||||
protected $pageComments = null;
|
||||
|
||||
/**
|
||||
* Cache of comment text for getformattedCommentText method
|
||||
*
|
||||
* @var string|null
|
||||
*
|
||||
*/
|
||||
protected $textFormatted = null;
|
||||
protected $formattedCommentText = null;
|
||||
|
||||
/**
|
||||
* Cache of options for getformattedCommentText method
|
||||
*
|
||||
* @var array|null
|
||||
*
|
||||
*/
|
||||
protected $formattedCommentOptions = null;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
@@ -194,44 +206,44 @@ class Comment extends WireData {
|
||||
*/
|
||||
public function get($key) {
|
||||
|
||||
if($key == 'user' || $key == 'createdUser') {
|
||||
if($key === 'user' || $key === 'createdUser') {
|
||||
if(!$this->created_users_id) return $this->users->get($this->config->guestUserPageID);
|
||||
return $this->users->get($this->created_users_id);
|
||||
|
||||
} else if($key == 'gravatar') {
|
||||
} else if($key === 'gravatar') {
|
||||
return $this->gravatar();
|
||||
|
||||
} else if($key == 'page') {
|
||||
} else if($key === 'page') {
|
||||
return $this->getPage();
|
||||
|
||||
} else if($key == 'field') {
|
||||
} else if($key === 'field') {
|
||||
return $this->getField();
|
||||
|
||||
} else if($key == 'parent') {
|
||||
} else if($key === 'parent') {
|
||||
return $this->parent();
|
||||
|
||||
} else if($key == 'parents') {
|
||||
} else if($key === 'parents') {
|
||||
return $this->parents();
|
||||
|
||||
} else if($key == 'children') {
|
||||
} else if($key === 'children') {
|
||||
return $this->children();
|
||||
|
||||
} else if($key == 'url') {
|
||||
} else if($key === 'url') {
|
||||
return $this->url();
|
||||
|
||||
} else if($key == 'httpUrl' || $key == 'httpURL') {
|
||||
} else if($key === 'httpUrl' || $key == 'httpURL') {
|
||||
return $this->httpUrl();
|
||||
|
||||
} else if($key == 'editUrl' || $key == 'editURL') {
|
||||
} else if($key === 'editUrl' || $key == 'editURL') {
|
||||
return $this->editUrl();
|
||||
|
||||
} else if($key == 'prevStatus') {
|
||||
} else if($key === 'prevStatus') {
|
||||
return $this->prevStatus;
|
||||
|
||||
} else if($key == 'textFormatted') {
|
||||
return $this->textFormatted;
|
||||
} else if($key === 'textFormatted') {
|
||||
return $this->getFormattedCommentText();
|
||||
|
||||
} else if($key == 'depth') {
|
||||
} else if($key === 'depth') {
|
||||
return $this->depth();
|
||||
|
||||
} else if($key === 'loaded') {
|
||||
@@ -250,34 +262,88 @@ class Comment extends WireData {
|
||||
* Note that we won't apply this to get() when $page->outputFormatting is active
|
||||
* in order for backwards compatibility with older installations.
|
||||
*
|
||||
* @param $key
|
||||
* @param string $key One of: text, cite, email, user_agent, website
|
||||
* @param array $options
|
||||
* @return mixed|null|Page|string
|
||||
*
|
||||
*/
|
||||
public function getFormatted($key) {
|
||||
$value = $this->get($key);
|
||||
public function getFormatted($key, array $options = array()) {
|
||||
$value = trim($this->get($key));
|
||||
$sanitizer = $this->wire()->sanitizer;
|
||||
|
||||
if($key == 'text') {
|
||||
if($this->textFormatted !== null) return $this->textFormatted;
|
||||
if($key === 'text') {
|
||||
$value = $this->getFormattedCommentText($options);
|
||||
} else if(in_array($key, array('cite', 'email', 'user_agent', 'website'))) {
|
||||
$value = $sanitizer->entities($value);
|
||||
} else if(is_string($value)) {
|
||||
$value = $sanitizer->entities1($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comment text as formatted string
|
||||
*
|
||||
* Note that the default options behavior is to return comment text with paragraphs split by `</p><p>`
|
||||
* but without the first `<p>` and last `</p>` since it is assumed these will be the markup you wrap
|
||||
* the comment in. If you want it to include the wrapping `<p>…</p>` tags then specify true for the
|
||||
* `wrapParagraph` option in the `$options` argument.
|
||||
*
|
||||
* @param array $options
|
||||
* - `useParagraphs` (bool): Convert newlines to paragraphs? (default=true)
|
||||
* - `wrapParagraph` (bool): Use wrapping <p>…</p> tags around return value? (default=false)
|
||||
* - `useLinebreaks` (bool): Convert single newlines to <br> tags? (default=true)
|
||||
* @return string
|
||||
* @since 3.0.169
|
||||
*
|
||||
*/
|
||||
public function getFormattedCommentText(array $options = array()) {
|
||||
|
||||
$defaults = array(
|
||||
'useParagraphs' => true,
|
||||
'wrapParagraph' => false,
|
||||
'useLinebreaks' => true,
|
||||
);
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
|
||||
if($this->formattedCommentText !== null) {
|
||||
if($this->formattedCommentOptions === null || $options == $this->formattedCommentOptions) {
|
||||
return $this->formattedCommentText;
|
||||
}
|
||||
}
|
||||
|
||||
$sanitizer = $this->wire()->sanitizer;
|
||||
$value = trim($this->get('text'));
|
||||
$textformatters = null;
|
||||
|
||||
// $textformatters = $this->field ? $this->field->textformatters : null; // @todo
|
||||
|
||||
if(is_array($textformatters) && count($textformatters)) {
|
||||
// output formatting with specified textformatters
|
||||
// output formatting with specified textformatters (@todo)
|
||||
// NOT CURRENTLY ACTIVE
|
||||
$value = strip_tags($value);
|
||||
foreach($textformatters as $name) {
|
||||
if(!$textformatter = $this->wire('modules')->get($name)) continue;
|
||||
$textformatter->formatValue($this->page, $this->field, $value);
|
||||
}
|
||||
} else {
|
||||
// default output formatting
|
||||
$value = $this->wire('sanitizer')->entities(trim($value));
|
||||
$value = $sanitizer->entities($value);
|
||||
while(strpos($value, "\n\n\n") !== false) $value = str_replace("\n\n\n", "\n\n", $value);
|
||||
if($options['useParagraphs']) {
|
||||
$value = str_replace("\n\n", "</p><p>", $value);
|
||||
$value = str_replace("\n", "<br />", $value);
|
||||
}
|
||||
if($options['wrapParagraph']) {
|
||||
$value = "<p>$value</p>";
|
||||
}
|
||||
$linebreak = $options['useLinebreaks'] ? "<br />" : " ";
|
||||
$value = str_replace("\n", $linebreak, $value);
|
||||
}
|
||||
|
||||
} else if(in_array($key, array('cite', 'email', 'user_agent', 'website'))) {
|
||||
$value = $this->wire('sanitizer')->entities(trim($value));
|
||||
}
|
||||
$this->formattedCommentText = $value;
|
||||
$this->formattedCommentOptions = $options;
|
||||
|
||||
return $value;
|
||||
}
|
||||
@@ -296,7 +362,12 @@ class Comment extends WireData {
|
||||
$value = (int) $value;
|
||||
} else if($key === 'text') {
|
||||
$value = $this->cleanCommentString($value);
|
||||
$this->textFormatted = null;
|
||||
$this->formattedCommentText = null;
|
||||
$this->formattedCommentOptions = null;
|
||||
} else if($key === 'textFormatted') {
|
||||
$this->formattedCommentText = $value;
|
||||
$this->formattedCommentOptions = null;
|
||||
return $this;
|
||||
} else if($key === 'cite') {
|
||||
$value = str_replace(array("\r", "\n", "\t"), ' ', substr(strip_tags($value), 0, 128));
|
||||
} else if($key === 'email') {
|
||||
@@ -309,9 +380,6 @@ class Comment extends WireData {
|
||||
$value = $this->wire('sanitizer')->url($value, array('allowRelative' => false, 'allowQuerystring' => false));
|
||||
} else if($key === 'upvotes' || $key === 'downvotes') {
|
||||
$value = (int) $value;
|
||||
} else if($key === 'textFormatted') {
|
||||
$this->textFormatted = $value;
|
||||
return $this;
|
||||
} else if($key === 'numChildren') {
|
||||
$this->numChildren = (int) $value;
|
||||
return $this;
|
||||
|
@@ -15,6 +15,7 @@
|
||||
* @property string $fromEmail
|
||||
* @property int $notifySpam
|
||||
* @property int $useNotify See Comment::flagNotify* constants
|
||||
* @property bool|int $useNotifyText Include comment text in notification emails?
|
||||
* @property int|bool $useAkismet
|
||||
* @property int $deleteSpamDays
|
||||
* @property int $depth
|
||||
|
@@ -169,6 +169,9 @@ class CommentForm extends Wire implements CommentFormInterface {
|
||||
// When a comment is saved to a page, avoid updating the modified time/user
|
||||
'quietSave' => false,
|
||||
|
||||
// default value for the notify option (when used)
|
||||
'notifyDefault' => 0,
|
||||
|
||||
// interial use: have options been initialized and are ready to use?
|
||||
'_ready' => false,
|
||||
|
||||
@@ -786,6 +789,7 @@ class CommentForm extends Wire implements CommentFormInterface {
|
||||
if(!$this->commentsField->useNotify) return '';
|
||||
$out = '';
|
||||
$tag = $this->options['inputWrapTag'];
|
||||
$notifyDefault = (int) $this->options['notifyDefault'];
|
||||
|
||||
$options = array();
|
||||
|
||||
@@ -809,15 +813,24 @@ class CommentForm extends Wire implements CommentFormInterface {
|
||||
$classes[$key] = $value ? " class='" . trim($value) . "'" : "";
|
||||
}
|
||||
|
||||
$checked = "checked='checked' ";
|
||||
$checkedNotify = array(
|
||||
0 => ($notifyDefault === 0 ? $checked : ''),
|
||||
Comment::flagNotifyAll => ($notifyDefault === Comment::flagNotifyAll ? $checked : ''),
|
||||
Comment::flagNotifyReply => ($notifyDefault === Comment::flagNotifyReply ? $checked : ''),
|
||||
);
|
||||
|
||||
if(count($options)) {
|
||||
$checked = $checkedNotify[0];
|
||||
$out =
|
||||
"\n\t<$tag$classes[notify]>" .
|
||||
"\n\t\t<label$classes[label]><span$classes[labelSpan]>" . $this->labels('notify') . "</span></label> " .
|
||||
"\n\t\t<label$classes[radioLabel]><input$classes[radioInput] type='radio' name='notify' checked='checked' value='0' /> " . $this->labels('notifyOff') . "</label> ";
|
||||
"\n\t\t<label$classes[radioLabel]><input$classes[radioInput] type='radio' name='notify' value='0' $checked/> " . $this->labels('notifyOff') . "</label> ";
|
||||
|
||||
foreach($options as $value => $label) {
|
||||
$checked = $checkedNotify[(int)$value];
|
||||
$label = str_replace(' ', ' ', $label);
|
||||
$out .= "\n\t\t<label$classes[radioLabel]><input$classes[radioInput] type='radio' name='notify' value='$value' /> $label</label> ";
|
||||
$out .= "\n\t\t<label$classes[radioLabel]><input$classes[radioInput] type='radio' name='notify' value='$value' $checked/> $label</label> ";
|
||||
}
|
||||
$out .= "\n\t</$tag>";
|
||||
}
|
||||
|
@@ -109,20 +109,20 @@ class CommentFormCustom extends CommentForm {
|
||||
<span class='{notify.label.span.class}'>{notify.label}</span>
|
||||
</label>
|
||||
<label class='{notify.input.label.class}'>
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' checked='checked' value='{notify.input.off.value}' />
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' checked='checked' value='{notify.input.off.value}' {notify.input.off.checked}/>
|
||||
{notify.input.off.label}
|
||||
</label>
|
||||
|
||||
{if.notify.replies}
|
||||
<label class='{notify.input.label.class}'>
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.replies.value}' />
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.replies.value}' {notify.input.replies.checked}/>
|
||||
{notify.input.replies.label}
|
||||
</label>
|
||||
{endif.notify.replies}
|
||||
|
||||
{if.notify.all}
|
||||
<label class='{notify.input.label.class}'>
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.all.value}' />
|
||||
<input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.all.value}' {notify.input.all.checked}/>
|
||||
{notify.input.all.label}
|
||||
</label>
|
||||
{endif.notify.all}
|
||||
@@ -272,10 +272,13 @@ class CommentFormCustom extends CommentForm {
|
||||
'{notify.input.name}' => 'notify',
|
||||
'{notify.input.off.value}' => '0',
|
||||
'{notify.input.off.label}' => $labels['notifyOff'],
|
||||
'{notify.input.off.checked}' => ($this->options['notifyDefault'] == 0 ? 'checked ' : ''),
|
||||
'{notify.input.replies.value}' => '2',
|
||||
'{notify.input.replies.label}' => $labels['notifyReplies'],
|
||||
'{notify.input.replies.checked}' => ($this->options['notifyDefault'] == 2 ? 'checked ' : ''),
|
||||
'{notify.input.all.value}' => '4',
|
||||
'{notify.input.all.label}' => $labels['notifyAll'],
|
||||
'{notify.input.all.checked}' => ($this->options['notifyDefault'] == 4 ? 'checked ' : ''),
|
||||
);
|
||||
|
||||
$ifs = array(
|
||||
|
@@ -9,7 +9,7 @@ class CommentNotifications extends Wire {
|
||||
protected $page;
|
||||
|
||||
/**
|
||||
* @var Field
|
||||
* @var CommentField
|
||||
*
|
||||
*/
|
||||
protected $field;
|
||||
@@ -429,18 +429,44 @@ class CommentNotifications extends Wire {
|
||||
*/
|
||||
public function ___sendNotificationEmail(Comment $comment, $email, $subcode) {
|
||||
|
||||
$showText = (bool) $this->field->useNotifyText;
|
||||
$sanitizer = $this->wire()->sanitizer;
|
||||
$page = $comment->getPage();
|
||||
$title = $page->get('title|name');
|
||||
$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";
|
||||
$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
|
||||
$body = $this->_('Posted at: %s') . "\n";
|
||||
$body .= sprintf($this->_('Posted by: %s'), $this->wire('sanitizer')->name($comment->cite)) . "\n";
|
||||
$bodyHTML = "<p>" . nl2br(sprintf($body, "<a href='$url'>$page->title</a>")) . "</p>";
|
||||
$body = sprintf($body, $page->title) . "\n" . sprintf($this->_('URL: %s'), $url);
|
||||
$footer = $this->_('Disable Notifications');
|
||||
$body .= "\n\n$footer: $unsubURL";
|
||||
$bodyHTML .= "<p><a href='$unsubURL'>$footer</a></p>";
|
||||
$postedAtLabel = $this->_('Posted at: %s');
|
||||
$postedByLabel = $this->_('Posted by: %s');
|
||||
$unsubLabel = $this->_('Unsubscribe from these notifications');
|
||||
$viewLabel = $this->_('View or reply');
|
||||
|
||||
$body =
|
||||
sprintf($postedAtLabel, $title) . "\n" .
|
||||
sprintf($postedByLabel, $cite) . "\n\n" .
|
||||
($showText ? "$text\n\n" : "") .
|
||||
"$viewLabel: $url\n\n" .
|
||||
"$unsubLabel: $unsubUrl\n\n";
|
||||
|
||||
$url = $sanitizer->entities($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>" .
|
||||
"\n<p> </p>" .
|
||||
"\n<hr />" .
|
||||
"\n<p><small><a href='$unsubUrl'>$unsubLabel</a></small></p>" .
|
||||
"</body></html>";
|
||||
|
||||
$mail = $this->wire('mail')->new();
|
||||
$mail->to($email)->subject($subject)->body($body)->bodyHTML($bodyHTML);
|
||||
@@ -448,6 +474,7 @@ class CommentNotifications extends Wire {
|
||||
if($fromEmail) $mail->from($fromEmail);
|
||||
|
||||
$result = $mail->send();
|
||||
|
||||
if($result) {
|
||||
$this->wire('log')->message("Sent comment notification email to $email");
|
||||
} else {
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* /wire/core/Fieldtype.php
|
||||
* /wire/core/FieldtypeMulti.php
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2016 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -74,7 +74,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
public static function getModuleInfo() {
|
||||
return array(
|
||||
'title' => __('Comments', __FILE__),
|
||||
'version' => 108,
|
||||
'version' => 109,
|
||||
'summary' => __('Field that stores user posted comments for a single Page', __FILE__),
|
||||
'installs' => array('InputfieldCommentsAdmin'),
|
||||
);
|
||||
@@ -119,7 +119,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
/**
|
||||
* Update a query to match the text with a fulltext index
|
||||
*
|
||||
* @param DatabaseQuerySelect $query
|
||||
* @param PageFinderDatabaseQuerySelect $query
|
||||
* @param string $table
|
||||
* @param string $subfield
|
||||
* @param string $operator
|
||||
@@ -297,17 +297,15 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
protected function checkCommentCodes(Comment $comment) {
|
||||
// assign code and subcode
|
||||
if(!$comment->code || !$comment->subcode) {
|
||||
$pass = $this->wire(new Password());
|
||||
$rand = new WireRandom();
|
||||
if(!strlen($comment->code)) {
|
||||
// code: visible to admin only
|
||||
$code = $pass->randomBase64String(128, true);
|
||||
$code = substr($this->wire('sanitizer')->fieldName($code), 0, 128);
|
||||
$code = $rand->alphanumeric(128);
|
||||
$comment->code = $code;
|
||||
}
|
||||
if(!strlen($comment->subcode)) {
|
||||
// subcode: may be visible to commenter
|
||||
$subcode = $pass->randomBase64String(40, true);
|
||||
$subcode = substr($this->wire('sanitizer')->fieldName($subcode), 0, 40);
|
||||
$subcode = $rand->alphanumeric(40);
|
||||
$comment->subcode = $subcode;
|
||||
}
|
||||
}
|
||||
@@ -324,7 +322,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
protected function checkNewComment(Page $page, Field $field, Comment $comment) {
|
||||
|
||||
if($page) {} // ignore
|
||||
if($comment->id || $comment->quiet()) return;
|
||||
$comment->isNew = true;
|
||||
|
||||
$this->checkCommentCodes($comment);
|
||||
|
||||
@@ -340,7 +340,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
if($comment->status != Comment::statusSpam) {
|
||||
if($field->get('moderate') == self::moderateNone) {
|
||||
$comment->status = Comment::statusApproved;
|
||||
$this->commentApproved($page, $field, $comment, 'New comment approved / moderation is off');
|
||||
$comment->approvalNote = 'New comment approved / moderation is off';
|
||||
|
||||
} else if($field->get('moderate') == self::moderateNew && $comment->email) {
|
||||
$database = $this->wire('database');
|
||||
@@ -352,17 +352,12 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$numApproved = (int) $query->fetchColumn();
|
||||
|
||||
if($numApproved > 0) {
|
||||
$cite = $this->wire('sanitizer')->text($comment->cite);
|
||||
$comment->status = Comment::statusApproved;
|
||||
$cite = $this->wire('sanitizer')->name($comment->cite);
|
||||
$this->commentApproved($page, $field, $comment, "New comment auto-approved because user '$cite' has other approved comments");
|
||||
$comment->approvalNote = "New comment auto-approved because user '$cite' has other approved comments";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
require_once(dirname(__FILE__) . '/CommentNotifications.php');
|
||||
$no = $this->wire(new CommentNotifications($page, $field));
|
||||
$no->sendAdminNotificationEmail($comment);
|
||||
$this->commentMaintenance($field);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -794,6 +789,18 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->addOption(Comment::flagNotifyReply, $this->_('Users can receive email notifications of replies to their comment only'));
|
||||
$f->addOption(Comment::flagNotifyAll, $this->_('Users can receive email notifications for all new comments on the page'));
|
||||
$f->attr('value', (int) $field->get('useNotify'));
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
$name = 'useNotifyText';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
if($field->$name) $f->attr('checked', 'checked');
|
||||
$f->label = $this->_('Allow comment text in notifications?');
|
||||
$f->description = $this->_('When checked, the entire comment text will also appear in the notification emails, rather than just a link to it.');
|
||||
$f->columnWidth = 50;
|
||||
$f->showIf = 'useNotify>0';
|
||||
$fieldset->append($f);
|
||||
|
||||
// ---------------------------------------
|
||||
@@ -1065,6 +1072,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$intColumns = array(
|
||||
'id',
|
||||
'status',
|
||||
'flags',
|
||||
'created',
|
||||
'pages_id',
|
||||
'parent_id',
|
||||
@@ -1149,6 +1157,23 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$wheres[] = "($table.$f!=0 OR $table.$f IS NOT NULL)";
|
||||
}
|
||||
|
||||
} else if($f === 'flags') {
|
||||
if(!is_array($value)) $value = array($value);
|
||||
$whereFlags = array();
|
||||
if(!in_array($operator, array('=', '!=', '&'))) {
|
||||
throw new WireException("Operator $operator not supported for comment flags");
|
||||
}
|
||||
foreach($value as $flag) {
|
||||
$intFlag = (int) $flag;
|
||||
if($operator === '!=') {
|
||||
$whereFlags[] = "(NOT $table.flags & $intFlag)";
|
||||
} else {
|
||||
$whereFlags[] = "($table.flags & $intFlag)";
|
||||
}
|
||||
}
|
||||
$andOr = $operator === '!=' ? ' AND ' : ' OR ';
|
||||
$wheres[] = '(' . implode($andOr, $whereFlags) . ')';
|
||||
|
||||
} else if(in_array($f, $intColumns)) {
|
||||
if(!$database->isOperator($operator)) $operator = '=';
|
||||
if(count($values) > 1 && ($operator == '=' || $operator == '!=')) {
|
||||
@@ -1798,41 +1823,19 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
$this->wire('log')->message("Approved comment $comment->id - $notes");
|
||||
|
||||
if($field->get('useNotify')) {
|
||||
|
||||
$emails = array();
|
||||
foreach($page->get($field->name) as $c) {
|
||||
|
||||
if($c->status < Comment::statusApproved) continue;
|
||||
if($c->id == $comment->id) continue;
|
||||
if(strtolower($c->email) == strtolower($comment->email)) continue;
|
||||
|
||||
/*
|
||||
* @todo this should be ready to use, but needs more testing before enabling it
|
||||
*
|
||||
if($c->flags & Comment::flagNotifyConfirmed) {
|
||||
// notifications have been confirmed by double opt-in
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
if($c->flags & Comment::flagNotifyAll) {
|
||||
if($c->subcode) $emails[strtolower($c->email)] = $c->subcode;
|
||||
} else if(($c->flags & Comment::flagNotifyReply) && $comment->parent_id == $c->id) {
|
||||
if($c->subcode) $emails[strtolower($c->email)] = $c->subcode;
|
||||
}
|
||||
}
|
||||
if(!$field->get('useNotify')) return;
|
||||
$emails = $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 => $subcode) {
|
||||
foreach($emails as $email => $data) {
|
||||
$subcode = $data['subcode'];
|
||||
$no->sendNotificationEmail($comment, $email, $subcode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -1860,6 +1863,11 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
public function ___commentAddReady(Page $page, Field $field, Comment $comment) {
|
||||
if($page && $field) {} // ignore
|
||||
$text = $comment->text;
|
||||
if(strtolower($this->wire()->config->dbEngine) !== 'utf8mb4') {
|
||||
$comment->text = $this->wire()->sanitizer->removeMB4($text, array('replaceWith' => ' '));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1873,6 +1881,89 @@ 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->sendAdminNotificationEmail($comment);
|
||||
$this->commentMaintenance($field);
|
||||
|
||||
if($comment->status == Comment::statusApproved || $comment->status == Comment::statusFeatured) {
|
||||
$this->commentApproved($page, $field, $comment, $comment->approvalNote);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get emails (and other data) of people that should be notified for a given Page’s comments
|
||||
*
|
||||
* @param Page $page
|
||||
* @param Field $field
|
||||
* @param Comment|null $comment
|
||||
* @return array
|
||||
* @throws WireException
|
||||
* @since 3.0.169
|
||||
*
|
||||
*/
|
||||
public function getNotifyEmails(Page $page, Field $field, Comment $comment = null) {
|
||||
|
||||
if(!$field->get('useNotify')) return array();
|
||||
|
||||
$emails = array();
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
|
||||
$sql =
|
||||
"SELECT id, cite, flags, email, subcode " .
|
||||
"FROM `$table` " .
|
||||
"WHERE pages_id=:pages_id " .
|
||||
"AND status>0 " .
|
||||
"AND ((flags & 2) OR (flags & 4) OR (flags & 8)) " . // 2=replies, 4=all, 8=confirmed
|
||||
"AND id!=:id " .
|
||||
"AND email!=:email " .
|
||||
"ORDER BY created DESC";
|
||||
|
||||
$query = $database->prepare($sql);
|
||||
$query->bindValue(':pages_id', $page->id, \PDO::PARAM_INT);
|
||||
$query->bindValue(':id', ($comment ? $comment->id : 0), \PDO::PARAM_INT);
|
||||
$query->bindValue(':email', ($comment ? strtolower($comment->email) : ''), \PDO::PARAM_STR);
|
||||
$query->execute();
|
||||
|
||||
while($row = $query->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$id = (int) $row['id'];
|
||||
$flags = (int) $row['flags'];
|
||||
$subcode = $row['subcode'];
|
||||
$email = strtolower($row['email']);
|
||||
|
||||
if(empty($subcode)) continue;
|
||||
|
||||
/*
|
||||
* @todo this should be ready to use, but needs more testing before enabling it
|
||||
*
|
||||
if($flags & Comment::flagNotifyConfirmed) {
|
||||
// notifications have been confirmed by double opt-in
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
*/
|
||||
|
||||
if($flags & Comment::flagNotifyAll) {
|
||||
// OK
|
||||
} else if(($flags & Comment::flagNotifyReply) && $comment && $comment->parent_id == $id) {
|
||||
// OK
|
||||
} else {
|
||||
continue; // SKIP
|
||||
}
|
||||
|
||||
$emails[$email] = array(
|
||||
'id' => $id,
|
||||
'email' => $email,
|
||||
'cite' => $row['cite'],
|
||||
'subcode' => $subcode,
|
||||
'flags' => $flags,
|
||||
);
|
||||
}
|
||||
|
||||
$query->closeCursor();
|
||||
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -611,10 +611,14 @@ class ProcessCommentsManager extends Process {
|
||||
"</label> ";
|
||||
}
|
||||
|
||||
if($page->editable()) $text =
|
||||
if($page->editable()) {
|
||||
$text =
|
||||
"<div class='CommentTextEditable' id='CommentText$id' data-textarea-class='$classes[textarea]'>" .
|
||||
"<p>$text <a class='CommentTextEdit' href='#'>$icons[edit] $labels[edit]</a></p>" .
|
||||
"</div>";
|
||||
} else {
|
||||
$text = "<p>$text</p>";
|
||||
}
|
||||
|
||||
if($allowPageChange) $outs['page'] =
|
||||
"<span class='detail ui-priority-secondary'>Page #</span> " .
|
||||
|
Reference in New Issue
Block a user