mirror of
https://github.com/processwire/processwire.git
synced 2025-08-16 03:34:33 +02:00
Upgrade FieldtypeComments to support custom fields via new meta functions. Also upgrade ProcessCommentsManager and InputfieldCommentsAdmin for support. InputfieldCommentsAdmin was also upgraded with an option to link to the comments manager rather than making comments editable in the page editor (see "Input" tab for that config option).
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Class that contains an individual comment.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
* @property int $id
|
||||
@@ -195,12 +195,23 @@ class Comment extends WireData {
|
||||
$this->set('website', '');
|
||||
$this->set('ip', '');
|
||||
$this->set('user_agent', '');
|
||||
$this->set('created_users_id', $this->config->guestUserPageID);
|
||||
$this->set('created_users_id', 40);
|
||||
$this->set('code', ''); // approval code
|
||||
$this->set('subcode', ''); // subscriber code (for later user modifications to comment)
|
||||
$this->set('upvotes', 0);
|
||||
$this->set('downvotes', 0);
|
||||
$this->set('stars', 0);
|
||||
$this->set('meta', array());
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wired to API
|
||||
*
|
||||
*/
|
||||
public function wired() {
|
||||
$this->set('created_users_id', $this->wire()->config->guestUserPageID);
|
||||
parent::wired();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,8 +224,7 @@ class Comment extends WireData {
|
||||
public function get($key) {
|
||||
|
||||
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);
|
||||
return $this->wire()->users->get($this->created_users_id);
|
||||
|
||||
} else if($key === 'gravatar') {
|
||||
return $this->gravatar();
|
||||
@@ -243,7 +253,7 @@ class Comment extends WireData {
|
||||
} else if($key === 'editUrl' || $key == 'editURL') {
|
||||
return $this->editUrl();
|
||||
|
||||
} else if($key === 'prevStatus') {
|
||||
} else if($key === 'prevStatus' || $key === 'statusPrevious') {
|
||||
return $this->prevStatus;
|
||||
|
||||
} else if($key === 'textFormatted') {
|
||||
@@ -329,9 +339,11 @@ class Comment extends WireData {
|
||||
if(is_array($textformatters) && count($textformatters)) {
|
||||
// output formatting with specified textformatters (@todo)
|
||||
// NOT CURRENTLY ACTIVE
|
||||
$modules = $this->wire()->modules;
|
||||
$value = strip_tags($value);
|
||||
foreach($textformatters as $name) {
|
||||
if(!$textformatter = $this->wire('modules')->get($name)) continue;
|
||||
/** @var Textformatter $textformatter */
|
||||
if(!$textformatter = $modules->get($name)) continue;
|
||||
$textformatter->formatValue($this->page, $this->field, $value);
|
||||
}
|
||||
} else {
|
||||
@@ -389,21 +401,23 @@ class Comment extends WireData {
|
||||
} else if($key === 'numChildren') {
|
||||
$this->numChildren = (int) $value;
|
||||
return $this;
|
||||
} else if($key === 'meta') {
|
||||
if(!is_array($value)) return $this; // array required for meta
|
||||
}
|
||||
|
||||
// save the state so that modules can identify when a comment that was identified as spam
|
||||
// is then set to not-spam, or when a misidentified 'approved' comment is actually spam
|
||||
if($key == 'status' && $this->loaded) {
|
||||
if($key === 'status' && $this->loaded) {
|
||||
$this->prevStatus = $this->status;
|
||||
}
|
||||
|
||||
if($key == 'stars') {
|
||||
if($key === 'stars') {
|
||||
$value = (int) $value;
|
||||
if($value < 1) $value = 0;
|
||||
if($value > 5) $value = 5;
|
||||
}
|
||||
|
||||
if($key == 'parent_id' && parent::get('parent_id') != $value) {
|
||||
if($key === 'parent_id' && parent::get('parent_id') != $value) {
|
||||
// reset a cached parent value, if present
|
||||
$this->_parent = null;
|
||||
}
|
||||
@@ -431,7 +445,7 @@ class Comment extends WireData {
|
||||
*
|
||||
*/
|
||||
public function __toString() {
|
||||
return "{$this->id}";
|
||||
return "$this->id";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,7 +470,7 @@ class Comment extends WireData {
|
||||
if(!in_array($rating, array('g', 'pg', 'r', 'x'), true)) $rating = 'g';
|
||||
if(empty($imageset)) $imageset = 'mm';
|
||||
$size = (int) $size;
|
||||
$http = wire('config')->https ? 'https' : 'http';
|
||||
$http = wire()->config->https ? 'https' : 'http';
|
||||
$url = "$http://www.gravatar.com/avatar/" .
|
||||
md5(strtolower(trim($email))) .
|
||||
"?s=$size" .
|
||||
@@ -763,7 +777,8 @@ class Comment extends WireData {
|
||||
if($this->page && $this->page->id) {
|
||||
$url = $http ? $this->page->httpUrl() : $this->page->url;
|
||||
} else {
|
||||
$url = $http ? $this->wire('config')->urls->httpRoot : $this->wire('config')->urls->root;
|
||||
$config = $this->wire()->config;
|
||||
$url = $http ? $config->urls->httpRoot : $config->urls->root;
|
||||
}
|
||||
return $url . "#Comment$this->id";
|
||||
}
|
||||
@@ -789,6 +804,105 @@ class Comment extends WireData {
|
||||
if(!$this->field) return '';
|
||||
return $this->page->editUrl() . "?field={$this->field->name}#CommentsAdminItem$this->id";
|
||||
}
|
||||
|
||||
/**
|
||||
* Set meta data (custom fields for comments)
|
||||
*
|
||||
* To set multiple properties at once specify an associative array for $key and omit $value.
|
||||
*
|
||||
* @param string|array $key Property name to set or assoc array of them
|
||||
* @param null|string|array|int|float|mixed $value Value to set for $key or omit of you used an array.
|
||||
* @return self
|
||||
* @since 3.0.203
|
||||
*
|
||||
*/
|
||||
public function setMeta($key, $value = null) {
|
||||
$meta = parent::get('meta');
|
||||
$changed = false;
|
||||
|
||||
if(is_array($key)) {
|
||||
// set multiple properties
|
||||
$changed = $meta != $key;
|
||||
if($changed) $meta = count($meta) ? array_merge($meta, $key) : $key;
|
||||
|
||||
} else if($value === null) {
|
||||
if($key === '*') {
|
||||
// remove all
|
||||
$changed = count($meta) > 0;
|
||||
$meta = array();
|
||||
} else if(isset($meta[$key])) {
|
||||
// remove property
|
||||
unset($meta[$key]);
|
||||
$changed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// set property
|
||||
$changed = !isset($meta[$key]) || $meta[$key] !== $value;
|
||||
$meta[$key] = $value;
|
||||
}
|
||||
|
||||
parent::set('meta', $meta);
|
||||
if($changed) $this->trackChange('meta');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get meta data property value (custom fields for comments)
|
||||
*
|
||||
* Note: values returned are exactly as they were set and do not go through any runtime
|
||||
* formatting for HTML entities or anything like that. Be sure to provide your own formatting
|
||||
* where necessary.
|
||||
*
|
||||
* @param null|string $key Name of property to get
|
||||
* @return string|array|int|float|mixed|null Returns value or null if not found
|
||||
* @since 3.0.203
|
||||
*
|
||||
*/
|
||||
public function getMeta($key = null) {
|
||||
$meta = parent::get('meta');
|
||||
if(empty($key)) return $meta;
|
||||
if(isset($meta[$key])) return $meta[$key];
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove given meta data property or '*' to remove all
|
||||
*
|
||||
* @param string $key
|
||||
* @return self
|
||||
* @since 3.0.203
|
||||
*
|
||||
*/
|
||||
public function removeMeta($key) {
|
||||
return $this->setMeta($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set meta data property
|
||||
*
|
||||
* @param string|array $key Property to get/set or omit to get all.
|
||||
* @param mixed|null $value Value to set for given property ($key) or omit if getting.
|
||||
* @return array|string|int|mixed Returns value for $key or null if it does not exist. Returns array when getting all.
|
||||
* @since 3.0.203
|
||||
*
|
||||
*/
|
||||
public function meta($key = null, $value = null) {
|
||||
if($key === null) {
|
||||
// get all
|
||||
$value = $this->getMeta();
|
||||
} else if($value === null) {
|
||||
// get one property
|
||||
if(!is_string($key)) throw new WireException('Expected string for $key to Comment::meta()');
|
||||
$value = $this->getMeta($key);
|
||||
} else {
|
||||
// set one property
|
||||
$this->setMeta($key, $value);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@@ -9,7 +9,7 @@
|
||||
* /wire/core/Fieldtype.php
|
||||
* /wire/core/FieldtypeMulti.php
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2020 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*/
|
||||
@@ -75,16 +75,17 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
public static function getModuleInfo() {
|
||||
return array(
|
||||
'title' => __('Comments', __FILE__),
|
||||
'version' => 109,
|
||||
'version' => 110,
|
||||
'summary' => __('Field that stores user posted comments for a single Page', __FILE__),
|
||||
'installs' => array('InputfieldCommentsAdmin'),
|
||||
);
|
||||
}
|
||||
|
||||
public function wired() {
|
||||
if($this->wire('config')->ajax) {
|
||||
if($this->wire()->config->ajax) {
|
||||
$this->addHookBefore('Page::render', $this, 'checkVoteAction');
|
||||
}
|
||||
parent::wired();
|
||||
}
|
||||
|
||||
public function getBlankValue(Page $page, Field $field) {
|
||||
@@ -97,7 +98,8 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
public function sanitizeValue(Page $page, Field $field, $value) {
|
||||
if($value instanceof CommentArray) return $value;
|
||||
$commentArray = $this->wire('pages')->get($field->name);
|
||||
/** @var CommentArray $commentArray */
|
||||
$commentArray = $this->wire()->pages->get($field->name);
|
||||
if(!$value) return $commentArray;
|
||||
if($value instanceof Comment) return $commentArray->add($value);
|
||||
if(!is_array($value)) $value = array($value);
|
||||
@@ -107,7 +109,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
public function getInputfield(Page $page, Field $field) {
|
||||
/** @var InputfieldCommentsAdmin $inputfield */
|
||||
$inputfield = $this->modules->get('InputfieldCommentsAdmin');
|
||||
$inputfield = $this->wire()->modules->get('InputfieldCommentsAdmin');
|
||||
if(!$inputfield) return null;
|
||||
$inputfield->set('class', $this->className());
|
||||
return $inputfield;
|
||||
@@ -164,15 +166,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
// don't load non-approved comments if the user can't edit them
|
||||
if(!$editable && $item['status'] < Comment::statusApproved) continue;
|
||||
|
||||
$comment = $this->wire(new Comment());
|
||||
$comment->setPage($page);
|
||||
$comment->setField($field);
|
||||
foreach($item as $key => $val) {
|
||||
if($key == 'data') $key = 'text';
|
||||
$comment->set($key, $val);
|
||||
}
|
||||
$comment->resetTrackChanges(true);
|
||||
|
||||
/** @var Comment $comment */
|
||||
$comment = $this->makeComment($page, $field, $item);
|
||||
$commentArray->add($comment);
|
||||
$comment->setIsLoaded(true);
|
||||
}
|
||||
@@ -238,6 +234,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
if($schemaVersion > 5) {
|
||||
$a['stars'] = ($comment->stars >= 1 && $comment->stars <= 5 ? (int) $comment->stars : null);
|
||||
}
|
||||
if($schemaVersion > 7) {
|
||||
$a['meta'] = json_encode($comment->getMeta());
|
||||
}
|
||||
|
||||
$sleepValue[] = $a;
|
||||
|
||||
@@ -280,7 +279,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
if($field->get('useAkismet') && $comment->ip && $comment->user_agent && ($submitHam || $submitSpam)) {
|
||||
/** @var CommentFilterAkismet $akismet */
|
||||
$akismet = $this->modules->get("CommentFilterAkismet");
|
||||
$akismet = $this->wire()->modules->get('CommentFilterAkismet');
|
||||
$akismet->setComment($comment);
|
||||
if($submitHam) $akismet->submitHam();
|
||||
else if($submitSpam) $akismet->submitSpam();
|
||||
@@ -331,7 +330,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
if($field->get('useAkismet')) {
|
||||
/** @var CommentFilterAkismet $akismet */
|
||||
$akismet = $this->modules->get('CommentFilterAkismet');
|
||||
$akismet = $this->wire()->modules->get('CommentFilterAkismet');
|
||||
$akismet->setComment($comment);
|
||||
$akismet->checkSpam(); // automatically sets status if spam
|
||||
} else {
|
||||
@@ -344,7 +343,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$comment->approvalNote = 'New comment approved / moderation is off';
|
||||
|
||||
} else if($field->get('moderate') == self::moderateNew && $comment->email) {
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
$query = $database->prepare("SELECT count(*) FROM `$table` WHERE status=:status AND email=:email");
|
||||
$query->bindValue(":status", Comment::statusApproved, \PDO::PARAM_INT);
|
||||
@@ -353,7 +352,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$numApproved = (int) $query->fetchColumn();
|
||||
|
||||
if($numApproved > 0) {
|
||||
$cite = $this->wire('sanitizer')->text($comment->cite);
|
||||
$cite = $this->wire()->sanitizer->text($comment->cite);
|
||||
$comment->status = Comment::statusApproved;
|
||||
$comment->approvalNote = "New comment auto-approved because user '$cite' has other approved comments";
|
||||
}
|
||||
@@ -369,7 +368,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
protected function commentMaintenance(Field $field) {
|
||||
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
|
||||
// delete old spam
|
||||
@@ -414,51 +413,59 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$downvoteSchema = "int unsigned NOT NULL default 0";
|
||||
$starsSchema = "tinyint unsigned default NULL";
|
||||
$ipSchema = "varchar(45) NOT NULL default ''";
|
||||
$metaSchema = "text DEFAULT NULL";
|
||||
$table = $field->getTable();
|
||||
|
||||
$schemaVersion = (int) $field->get('schemaVersion');
|
||||
$updateSchema = true;
|
||||
|
||||
if(!$schemaVersion) {
|
||||
// add website field for PW 2.3+
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` ADD website $websiteSchema");
|
||||
if(!$database->columnExists($table, 'website')) {
|
||||
$database->query("ALTER TABLE `$table` ADD website $websiteSchema");
|
||||
}
|
||||
$schemaVersion = 1;
|
||||
} catch(\Exception $e) {
|
||||
$updateSchema = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($schemaVersion < 2) {
|
||||
if($schemaVersion < 2 && $updateSchema) {
|
||||
// add parent_id and flags columns
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` ADD parent_id $parentSchema");
|
||||
$database->query("ALTER TABLE `$table` ADD flags $flagSchema");
|
||||
if(!$database->columnExists($table, 'parent_id')) {
|
||||
$database->query("ALTER TABLE `$table` ADD parent_id $parentSchema");
|
||||
}
|
||||
if(!$database->columnExists($table, 'flags')) {
|
||||
$database->query("ALTER TABLE `$table` ADD flags $flagSchema");
|
||||
}
|
||||
$schemaVersion = 2;
|
||||
} catch(\Exception $e) {
|
||||
$updateSchema = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($schemaVersion < 3) {
|
||||
if($schemaVersion < 3 && $updateSchema) {
|
||||
// add code column (admin code)
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` ADD `code` $codeSchema");
|
||||
$database->query("ALTER TABLE `$table` ADD $codeIndexSchema");
|
||||
if(!$database->columnExists($table, 'code')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `code` $codeSchema");
|
||||
$database->query("ALTER TABLE `$table` ADD $codeIndexSchema");
|
||||
}
|
||||
$schemaVersion = 3;
|
||||
} catch(\Exception $e) {
|
||||
$updateSchema = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($schemaVersion < 4) {
|
||||
if($schemaVersion < 4 && $updateSchema) {
|
||||
// add subcode column (subscriber code)
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` ADD `subcode` $subcodeSchema");
|
||||
$database->query("ALTER TABLE `$table` ADD $subcodeIndexSchema");
|
||||
if(!$database->columnExists($table, 'subcode')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `subcode` $subcodeSchema");
|
||||
$database->query("ALTER TABLE `$table` ADD $subcodeIndexSchema");
|
||||
}
|
||||
$schemaVersion = 4;
|
||||
} catch(\Exception $e) {
|
||||
$updateSchema = false;
|
||||
@@ -467,20 +474,21 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
if($schemaVersion < 5 && $updateSchema) {
|
||||
// add upvote/downvote columns
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
$parentSchema = parent::getDatabaseSchema($field);
|
||||
try {
|
||||
$sql = "
|
||||
CREATE TABLE `{$table}_votes` (
|
||||
`comment_id` int unsigned NOT NULL,
|
||||
`vote` tinyint NOT NULL,
|
||||
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`ip` $ipSchema,
|
||||
`user_id` int unsigned NOT NULL default 0,
|
||||
PRIMARY KEY (`comment_id`, `ip`, `vote`),
|
||||
INDEX `created` (`created`)
|
||||
) " . $parentSchema['xtra']['append']; // engine and charset
|
||||
$database->exec($sql);
|
||||
if(!$database->tableExists("{$table}_votes")) {
|
||||
$sql = "
|
||||
CREATE TABLE `{$table}_votes` (
|
||||
`comment_id` int unsigned NOT NULL,
|
||||
`vote` tinyint NOT NULL,
|
||||
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`ip` $ipSchema,
|
||||
`user_id` int unsigned NOT NULL default 0,
|
||||
PRIMARY KEY (`comment_id`, `ip`, `vote`),
|
||||
INDEX `created` (`created`)
|
||||
) " . $parentSchema['xtra']['append']; // engine and charset
|
||||
$database->exec($sql);
|
||||
}
|
||||
$createdVotesTable = true;
|
||||
} catch(\Exception $e) {
|
||||
$createdVotesTable = $e->getCode() == '42S01'; // 42S01=table already exists (which we consider success too)
|
||||
@@ -490,12 +498,12 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
}
|
||||
}
|
||||
if($createdVotesTable) try {
|
||||
$isUpvotes = $database->prepare("SHOW columns FROM `$table` LIKE 'upvotes'");
|
||||
$isUpvotes->execute();
|
||||
if(!$isUpvotes->rowCount()) $database->query("ALTER TABLE `$table` ADD `upvotes` $upvoteSchema");
|
||||
$isDownvotes = $database->prepare("SHOW columns FROM `$table` LIKE 'downvotes'");
|
||||
$isDownvotes->execute();
|
||||
if(!$isDownvotes->rowCount()) $database->query("ALTER TABLE `$table` ADD `downvotes` $downvoteSchema");
|
||||
if(!$database->columnExists($table, 'upvotes')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `upvotes` $upvoteSchema");
|
||||
}
|
||||
if(!$database->columnExists($table, 'downvotes')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `downvotes` $downvoteSchema");
|
||||
}
|
||||
$schemaVersion = 5;
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage(), Notice::log);
|
||||
@@ -504,28 +512,37 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
}
|
||||
|
||||
if($schemaVersion < 6 && $updateSchema) {
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` ADD `stars` $starsSchema");
|
||||
if(!$database->columnExists($table, 'stars')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `stars` $starsSchema");
|
||||
}
|
||||
$schemaVersion = 6;
|
||||
} catch(\Exception $e) {
|
||||
if($e->getCode() == '42S21') {
|
||||
// column already exists
|
||||
$schemaVersion = 6;
|
||||
} else {
|
||||
// $updateSchema = false;
|
||||
}
|
||||
$updateSchema = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($schemaVersion < 7 && $updateSchema) {
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
try {
|
||||
$database->query("ALTER TABLE `$table` MODIFY `ip` $ipSchema");
|
||||
$database->query("ALTER TABLE `{$table}_votes` MODIFY `ip` $ipSchema");
|
||||
if($database->tableExists("{$table}_votes")) {
|
||||
$database->query("ALTER TABLE `{$table}_votes` MODIFY `ip` $ipSchema");
|
||||
}
|
||||
$schemaVersion = 7;
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage(), Notice::debug);
|
||||
$updateSchema = false;
|
||||
}
|
||||
}
|
||||
|
||||
if($schemaVersion < 8 && $updateSchema) {
|
||||
try {
|
||||
if(!$database->columnExists($table, 'meta')) {
|
||||
$database->query("ALTER TABLE `$table` ADD `meta` $metaSchema");
|
||||
}
|
||||
$schemaVersion = 8;
|
||||
} catch(\Exception $e) {
|
||||
$this->error($e->getMessage(), Notice::debug);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -570,6 +587,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
if($schemaVersion > 5) {
|
||||
$schema['stars'] = $starsSchema;
|
||||
}
|
||||
if($schemaVersion > 7) {
|
||||
$schema['meta'] = $metaSchema;
|
||||
}
|
||||
|
||||
$schema['keys']['primary'] = "PRIMARY KEY (`id`)";
|
||||
$schema['keys']['pages_id_sort'] = "KEY `pages_id_sort` (`pages_id`, `sort`)";
|
||||
@@ -596,7 +616,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
/** @var CommentArray $allItems */
|
||||
$allItems = $page->get($field->name);
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
|
||||
if(!$allItems) return false;
|
||||
@@ -692,20 +712,25 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
* @param Field $field
|
||||
* @return InputfieldWrapper
|
||||
* @todo move to separate config file
|
||||
*
|
||||
*/
|
||||
public function ___getConfigInputfields(Field $field) {
|
||||
|
||||
$modules = $this->wire()->modules;
|
||||
|
||||
$inputfields = parent::___getConfigInputfields($field);
|
||||
$disabledLabel = $this->_('Disabled');
|
||||
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $modules->get('InputfieldFieldset');
|
||||
$fieldset->label = $this->_('Behavior');
|
||||
$fieldset->icon = 'comment-o';
|
||||
$inputfields->add($fieldset);
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $modules->get('InputfieldRadios');
|
||||
$name = 'moderate';
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', $name);
|
||||
$f->addOption(self::moderateNone, $this->_('None - Comments posted immediately'));
|
||||
$f->addOption(self::moderateAll, $this->_('All - All comments must be approved by user with page edit access'));
|
||||
@@ -714,9 +739,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->label = $this->_('Comment moderation');
|
||||
$f->description = $this->_('This determines when a newly posted comment will appear on your site.');
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'redirectAfterPost';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
$f->attr('checked', $field->$name ? 'checked' : '');
|
||||
@@ -725,8 +751,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'quietSave';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
$f->attr('checked', $field->$name ? 'checked' : '');
|
||||
@@ -749,14 +776,16 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
|
||||
// ----------------------------
|
||||
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $modules->get('InputfieldFieldset');
|
||||
$fieldset->label = $this->_('Notifications');
|
||||
$fieldset->icon = 'bell-o';
|
||||
$inputfields->add($fieldset);
|
||||
|
||||
/** @var InputfieldText $f */
|
||||
$f = $modules->get('InputfieldText');
|
||||
$name = 'notificationEmail';
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', $field->$name);
|
||||
$f->label = $this->_('Admin notification email');
|
||||
@@ -769,18 +798,20 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$this->_('3. Enter **123:email** to pull the email from an given page ID and field name, replacing "123" with the page ID and "email" with name of field containing email address.') . "\n" .
|
||||
$this->_('4. Enter **/path/to/page:email** to pull the email from an given page path and field name, replacing "/path/to/page" with the page path and "email" with name of field containing email address.');
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldEmail $f */
|
||||
$f = $modules->get('InputfieldEmail');
|
||||
$name = 'fromEmail';
|
||||
$f = $this->wire('modules')->get('InputfieldEmail');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', $field->$name);
|
||||
$f->label = $this->_('Notifications from email');
|
||||
$f->description = $this->_('Optional e-mail address that notifications will appear from. Leave blank to use the default server email.');
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'notifySpam';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
if($field->$name) $f->attr('checked', 'checked');
|
||||
@@ -789,8 +820,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $modules->get('InputfieldRadios');
|
||||
$name = 'useNotify';
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', $name);
|
||||
$f->label = $this->_('Allow commenter e-mail notifications?');
|
||||
$f->description = $this->_('This option enables anyone that posts a comment to receive email notifications of new comments.');
|
||||
@@ -800,9 +832,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->attr('value', (int) $field->get('useNotify'));
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'useNotifyText';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
if($field->$name) $f->attr('checked', 'checked');
|
||||
@@ -813,14 +846,16 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$fieldset->append($f);
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $modules->get('InputfieldFieldset');
|
||||
$fieldset->label = $this->_('Spam');
|
||||
$fieldset->icon = 'fire-extinguisher';
|
||||
$inputfields->add($fieldset);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'useAkismet';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
$f->attr('checked', $field->$name ? 'checked' : '');
|
||||
@@ -829,8 +864,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
/** @var InputfieldInteger $f */
|
||||
$f = $modules->get('InputfieldInteger');
|
||||
$name = 'deleteSpamDays';
|
||||
$f = $this->wire('modules')->get('InputfieldInteger');
|
||||
$f->attr('name', $name);
|
||||
$value = $field->$name;
|
||||
if(is_null($value)) $value = 3; // default
|
||||
@@ -842,13 +878,15 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $modules->get('InputfieldFieldset');
|
||||
$fieldset->label = $this->_('Output');
|
||||
$fieldset->icon = 'comments-o';
|
||||
$inputfields->add($fieldset);
|
||||
|
||||
|
||||
/** @var InputfieldInteger $f */
|
||||
$f = $modules->get('InputfieldInteger');
|
||||
$name = 'depth';
|
||||
$f = $this->wire('modules')->get('InputfieldInteger');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', (int) $field->$name);
|
||||
$f->label = $this->_('Reply depth');
|
||||
@@ -856,9 +894,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'sortNewest';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
$f->attr('checked', $field->$name ? 'checked' : '');
|
||||
@@ -866,9 +904,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->description = $this->_('By default, comments will sort chronologically (oldest to newest). To reverse that behavior check this box.');
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldCheckbox $f */
|
||||
$f = $modules->get('InputfieldCheckbox');
|
||||
$name = 'useWebsite';
|
||||
$f = $this->wire('modules')->get('InputfieldCheckbox');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', 1);
|
||||
$f->attr('checked', $field->$name ? 'checked' : '');
|
||||
@@ -876,18 +915,20 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->description = $this->_('When checked, the comment submission form will also include a website field.');
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldText $f */
|
||||
$f = $modules->get('InputfieldText');
|
||||
$name = 'dateFormat';
|
||||
$f = $this->wire('modules')->get('InputfieldText');
|
||||
$f->attr('name', $name);
|
||||
$f->attr('value', $field->get('dateFormat') ? $field->get('dateFormat') : 'relative');
|
||||
$f->label = $this->_('Date/time format (for comment list)');
|
||||
$f->description = $this->_('Enter the date/time format you want the default comment list output to use. May be a PHP [date](http://php.net/manual/en/function.date.php) or [strftime](http://php.net/manual/en/function.strftime.php) format. May also be "relative" for relative date format.'); // dateFormat description
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $modules->get('InputfieldRadios');
|
||||
$name = 'useVotes';
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', $name);
|
||||
$f->label = $this->_('Allow comment voting?');
|
||||
$f->description = $this->_('Comment voting enables visitors to upvote and/or downvote comments. Vote counts are displayed alongside each comment. Only one upvote and/or downvote is allowed per comment, per IP address, per hour.');
|
||||
@@ -898,8 +939,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $modules->get('InputfieldRadios');
|
||||
$name = 'useStars';
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', $name);
|
||||
$f->label = $this->_('Use stars rating?');
|
||||
$f->description = $this->_('Star ratings enable the commenter to rate the subject they are commenting on, using a scale of 1 to 5 stars.');
|
||||
@@ -911,8 +953,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$f->columnWidth = 50;
|
||||
$fieldset->append($f);
|
||||
|
||||
/** @var InputfieldRadios $f */
|
||||
$f = $modules->get('InputfieldRadios');
|
||||
$name = 'useGravatar';
|
||||
$f = $this->wire('modules')->get('InputfieldRadios');
|
||||
$f->attr('name', $name);
|
||||
$f->addOption('', $disabledLabel);
|
||||
$f->addOption('g', $this->_('G: Suitable for display on all websites with any audience type.'));
|
||||
@@ -944,23 +987,26 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
|
||||
// -----------------------------
|
||||
|
||||
$fieldset = $this->wire('modules')->get('InputfieldFieldset');
|
||||
|
||||
/** @var InputfieldFieldset $fieldset */
|
||||
$fieldset = $modules->get('InputfieldFieldset');
|
||||
$fieldset->label = $this->_('Implementation');
|
||||
$fieldset->icon = 'file-code-o';
|
||||
$fieldset->description = $this->_('This section is here to help you get started with outputting comments on the front-end of your site. Everything here is optional.');
|
||||
$fieldset->notes = $this->_('If using a cache for output, configure it to bypass the cache when the GET variable "comment_success" is present.');
|
||||
$inputfields->add($fieldset);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldMarkup');
|
||||
|
||||
/** @var InputfieldMarkup $f */
|
||||
$f = $modules->get('InputfieldMarkup');
|
||||
$f->label = $this->_('PHP code to output comments');
|
||||
$f->value =
|
||||
"<p>Please copy and paste the following into your template file(s) where you would like the comments to be output:</p>" .
|
||||
"<pre style='border-left: 4px solid #ccc; padding-left: 1em;'><?php echo \$page->{$field->name}->renderAll(); ?></pre>" .
|
||||
"<p>For more options please see the <a href='https://processwire.com/api/fieldtypes/comments/' target='_blank'>comments documentation page</a>.</p>";
|
||||
$fieldset->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldMarkup');
|
||||
$fieldset->add($f);
|
||||
|
||||
/** @var InputfieldMarkup $f */
|
||||
$f = $modules->get('InputfieldMarkup');
|
||||
$f->label = $this->_('CSS for front-end comments output');
|
||||
$ftUrl = $this->wire('config')->urls('FieldtypeComments');
|
||||
$f->value =
|
||||
@@ -969,8 +1015,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
"<p>Or if you prefer, copy the <a target='_blank' href='{$ftUrl}comments.css'>comments.css</a> file to your own location, " .
|
||||
"modify it as desired, and link to it in your document head as you do with your other css files.</p>";
|
||||
$fieldset->add($f);
|
||||
|
||||
$f = $this->wire('modules')->get('InputfieldMarkup');
|
||||
|
||||
/** @var InputfieldMarkup $f */
|
||||
$f = $modules->get('InputfieldMarkup');
|
||||
$f->label = $this->_('JS for front-end comments output');
|
||||
$f->value =
|
||||
"<p>If you are using threaded comments (i.e. reply depth > 0), please also copy and paste the following into the document <code><head></code> " .
|
||||
@@ -979,9 +1026,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
"<p>Like with the comments.css file, feel free to copy and link to the <a target='_blank' href='{$ftUrl}comments.js'>comments.js</a> file from your own " .
|
||||
"location if you prefer it.</p>";
|
||||
$fieldset->add($f);
|
||||
|
||||
|
||||
/** @var InputfieldHidden $f */
|
||||
$f = $modules->get('InputfieldHidden');
|
||||
$name = 'schemaVersion';
|
||||
$f = $this->wire('modules')->get('InputfieldHidden');
|
||||
$f->attr('name', $name);
|
||||
$value = (int) $field->$name;
|
||||
$f->attr('value', $value);
|
||||
@@ -1014,9 +1062,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
static public function findComments($field, $selectorString) {
|
||||
if(is_string($field)) $field = wire('fields')->get($field);
|
||||
if(is_string($field)) $field = wire()->fields->get($field);
|
||||
if(!$field instanceof Field) throw new WireException('Arg 1 to findComments() must be a field');
|
||||
return $field->type->find($field, $selectorString);
|
||||
$fieldtype = $field->type; /** @var FieldtypeComments $fieldtype */
|
||||
return $fieldtype->find($field, $selectorString);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1070,7 +1119,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
// arguments are reversed
|
||||
list($selectorString, $field) = array($field, $selectorString);
|
||||
}
|
||||
if(is_string($field)) $field = $this->wire('fields')->get($field);
|
||||
if(is_string($field)) $field = $this->wire()->fields->get($field);
|
||||
}
|
||||
if(!$field instanceof Field) $field = $this->getLastAccessField();
|
||||
if(!$field instanceof Field) $field = $this->getCommentsFields(true);
|
||||
@@ -1106,8 +1155,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$limit = 10;
|
||||
$start = 0;
|
||||
$sorts = array();
|
||||
$database = $this->wire('database');
|
||||
|
||||
$database = $this->wire()->database;
|
||||
$fields = $this->wire()->fields;
|
||||
$pages = $this->wire()->pages;
|
||||
|
||||
$selectQuery = new DatabaseQuerySelect();
|
||||
$countQuery = new DatabaseQuerySelect();
|
||||
|
||||
@@ -1251,7 +1302,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
} else {
|
||||
/** @var Field $f */
|
||||
$f = $this->wire('fields')->get($fieldName);
|
||||
$f = $fields->get($fieldName);
|
||||
if(!$f) continue;
|
||||
$fieldTable = $f->getTable();
|
||||
if(!$database->isOperator($operator)) $operator = '=';
|
||||
@@ -1275,7 +1326,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
}
|
||||
|
||||
// if no status was specified and we’re on the front-end, match only approved comments
|
||||
if($status === null && $this->wire('page')->template != 'admin') {
|
||||
if($status === null && $this->wire()->page->template->name != 'admin') {
|
||||
$wheres[] = "$table.status>=" . Comment::statusApproved;
|
||||
}
|
||||
|
||||
@@ -1334,20 +1385,14 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$commentPages = array();
|
||||
|
||||
while($row = $query->fetch(\PDO::FETCH_ASSOC)) {
|
||||
$comment = $this->wire(new Comment());
|
||||
$comment->setField($field);
|
||||
foreach($row as $key => $value) {
|
||||
if($key == 'data') $key = 'text';
|
||||
$comment->set($key, $value);
|
||||
}
|
||||
$pageID = $row['pages_id'];
|
||||
if(isset($commentPages[$pageID])) {
|
||||
$page = $commentPages[$pageID];
|
||||
} else {
|
||||
$page = $this->wire('pages')->get((int) $pageID);
|
||||
$commentPages[$page->id] = $page;
|
||||
$page = $pages->get((int) $pageID);
|
||||
$commentPages[$page->id] = $page;
|
||||
}
|
||||
$comment->resetTrackChanges(true);
|
||||
$comment = $this->makeComment($page, $field, $row);
|
||||
$comments->add($comment);
|
||||
if($page->id) $comment->setPage($page);
|
||||
$comment->setIsLoaded(true);
|
||||
@@ -1382,7 +1427,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function getCommentsFields($one = false) {
|
||||
$fields = array();
|
||||
foreach($this->wire('fields') as $field) {
|
||||
foreach($this->wire()->fields as $field) {
|
||||
if($field->type instanceof FieldtypeComments) {
|
||||
$fields[] = $field;
|
||||
if($one) break;
|
||||
@@ -1402,10 +1447,10 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
public function getCommentByCode($page, $field, $code) {
|
||||
if(!is_object($page)) $page = $this->wire('pages')->get((int) $page);
|
||||
if(!is_object($page)) $page = $this->wire()->pages->get((int) $page);
|
||||
if(!$page->id) return null;
|
||||
if(!trim($code)) return null;
|
||||
if(!is_object($field)) $field = $this->wire('fields')->get($this->wire('sanitizer')->fieldName($field));
|
||||
if(!is_object($field)) $field = $this->wire()->fields->get($this->wire()->sanitizer->fieldName($field));
|
||||
if(!$field || !$field->type instanceof FieldtypeComments) return null;
|
||||
$table = $field->getTable();
|
||||
$col = strlen($code) > 100 ? 'code' : 'subcode';
|
||||
@@ -1429,26 +1474,27 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
public function getCommentByID($page, $field, $id) {
|
||||
$pages = $this->wire()->pages;
|
||||
if(empty($id)) return null;
|
||||
if($page && !is_object($page)) {
|
||||
$page = $this->wire('pages')->get((int) $page);
|
||||
$page = $pages->get((int) $page);
|
||||
if(!$page->id) return null;
|
||||
}
|
||||
if(!is_object($field) && $field) {
|
||||
$field = $this->wire('fields')->get($this->wire('sanitizer')->fieldName($field));
|
||||
$field = $this->wire()->fields->get($this->wire()->sanitizer->fieldName($field));
|
||||
}
|
||||
if(!$field || !$field->type instanceof FieldtypeComments) return null;
|
||||
$table = $field->getTable();
|
||||
$sql = "SELECT * FROM `$table` WHERE id=:id ";
|
||||
if($page) $sql .= "AND pages_id=:pageID";
|
||||
$query = $this->wire('database')->prepare($sql);
|
||||
$query = $this->wire()->database->prepare($sql);
|
||||
$query->bindValue(':id', (int) $id, \PDO::PARAM_INT);
|
||||
if($page) $query->bindValue(':pageID', $page->id, \PDO::PARAM_INT);
|
||||
if(!$query->execute()) return null;
|
||||
if(!$query->rowCount()) return null;
|
||||
$data = $query->fetch(\PDO::FETCH_ASSOC);
|
||||
if(!$page) {
|
||||
$page = $this->wire('pages')->get((int) $data['pages_id']);
|
||||
$page = $pages->get((int) $data['pages_id']);
|
||||
}
|
||||
return $this->makeComment($page, $field, $data);
|
||||
}
|
||||
@@ -1493,15 +1539,26 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
protected function makeComment($page, $field, array $data) {
|
||||
|
||||
/** @var Comment $comment */
|
||||
$comment = $this->wire(new Comment());
|
||||
$comment->setPage($page);
|
||||
$comment->setField($field);
|
||||
|
||||
foreach($data as $key => $val) {
|
||||
if($key == 'data') $key = 'text';
|
||||
if($key === 'data') {
|
||||
$key = 'text';
|
||||
} else if($key === 'meta') {
|
||||
$val = is_string($val) ? json_decode($val, true) : array();
|
||||
if(is_array($val)) $comment->setMeta($val);
|
||||
continue;
|
||||
}
|
||||
$comment->set($key, $val);
|
||||
}
|
||||
|
||||
$comment->resetTrackChanges(true);
|
||||
$comment->setIsLoaded(true);
|
||||
|
||||
return $comment;
|
||||
}
|
||||
|
||||
@@ -1530,11 +1587,18 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$sql = "UPDATE `$table` SET ";
|
||||
$values = array();
|
||||
foreach($properties as $property => $value) {
|
||||
$comment->set($property, $value);
|
||||
if($property === 'meta') {
|
||||
if(!is_array($value)) continue;
|
||||
$comment->setMeta($value);
|
||||
$value = json_encode($value);
|
||||
if(!is_string($value)) continue;
|
||||
} else {
|
||||
$comment->set($property, $value);
|
||||
}
|
||||
$property = $sanitizer->fieldName($property);
|
||||
$property = $database->escapeCol($property);
|
||||
if($property == 'text') $property = 'data';
|
||||
if(is_null($value) && ($property == 'code' || $property == 'subcode')) {
|
||||
if($property === 'text') $property = 'data';
|
||||
if(is_null($value) && ($property === 'code' || $property === 'subcode')) {
|
||||
$sql .= "`$property`=NULL, ";
|
||||
} else {
|
||||
$sql .= "`$property`=:$property, ";
|
||||
@@ -1598,8 +1662,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
throw new WireException("Comment is already assigned to a different Field");
|
||||
}
|
||||
|
||||
/** @var WireDatabasePDO $database */
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
$sets = array('pages_id=:pages_id');
|
||||
$binds = array('pages_id' => (int) $page->id);
|
||||
@@ -1735,7 +1798,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
protected function getMaxSort(Page $page, Field $field) {
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
$sql = "SELECT MAX(sort) FROM `$table` WHERE pages_id=:pages_id";
|
||||
$query = $database->prepare($sql);
|
||||
@@ -1781,7 +1844,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
);
|
||||
|
||||
$options = array_merge($defaults, $options);
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->getTable());
|
||||
$sql = "SELECT COUNT(*) FROM `$table` WHERE pages_id=:page ";
|
||||
$binds = array(':page' => $page->id);
|
||||
@@ -1871,7 +1934,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function ___commentApproved(Page $page, Field $field, Comment $comment, $notes = '') {
|
||||
|
||||
$this->wire('log')->message("Approved comment $comment->id - $notes");
|
||||
$this->wire()->log->message("Approved comment $comment->id - $notes");
|
||||
|
||||
if(!$field->get('useNotify')) return; // notifications not in use
|
||||
if($comment->flags & Comment::flagNotifyQueue) return; // comment queued for 3rd party notifications
|
||||
@@ -2052,7 +2115,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function voteComment(Page $page, Field $field, Comment $comment, $up = true) {
|
||||
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->getTable()) . '_votes';
|
||||
|
||||
if(!$field->get('useVotes')) return false;
|
||||
@@ -2062,8 +2125,8 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
$query = $database->prepare($sql);
|
||||
$query->bindValue(':comment_id', $comment->id, \PDO::PARAM_INT);
|
||||
$query->bindValue(':vote', $up ? 1 : -1, \PDO::PARAM_INT);
|
||||
$query->bindValue(':ip', $this->wire('session')->getIP(), \PDO::PARAM_STR);
|
||||
$query->bindValue(':user_id', $this->wire('user')->id, \PDO::PARAM_INT);
|
||||
$query->bindValue(':ip', $this->wire()->session->getIP(), \PDO::PARAM_STR);
|
||||
$query->bindValue(':user_id', $this->wire()->user->id, \PDO::PARAM_INT);
|
||||
|
||||
$result = false;
|
||||
|
||||
@@ -2083,7 +2146,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
if(stripos($error, 'duplicate entry')) {
|
||||
$this->error($this->_('You have already voted for this comment'));
|
||||
} else {
|
||||
if($this->wire('config')->debug && !$this->wire('user')->isLoggedin()) {
|
||||
if($this->wire()->config->debug && !$this->wire()->user->isLoggedin()) {
|
||||
$this->error($e->getMessage());
|
||||
} else {
|
||||
$this->error($this->_('Error recording vote'));
|
||||
@@ -2104,6 +2167,8 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function checkVoteAction($page) {
|
||||
|
||||
$input = $this->wire()->input;
|
||||
|
||||
$result = array(
|
||||
'success' => false,
|
||||
'valid' => false,
|
||||
@@ -2115,14 +2180,14 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
'commentID' => 0,
|
||||
);
|
||||
|
||||
$action = $this->wire('input')->get('comment_success');
|
||||
$action = $input->get('comment_success');
|
||||
if($action !== 'upvote' && $action !== 'downvote') return $result;
|
||||
|
||||
$commentID = (int) $this->wire('input')->get('comment_id');
|
||||
$fieldID = (int) $this->wire('input')->get('field_id');
|
||||
$commentID = (int) $input->get('comment_id');
|
||||
$fieldID = (int) $input->get('field_id');
|
||||
if(!$commentID || !$fieldID) return $result;
|
||||
|
||||
$field = $this->wire('fields')->get($fieldID);
|
||||
$field = $this->wire()->fields->get($fieldID);
|
||||
if(!$field || !$field->type instanceof FieldtypeComments) return $result;
|
||||
|
||||
if($page instanceof HookEvent) $page = $page->object;
|
||||
@@ -2145,7 +2210,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
'commentID' => $comment->id
|
||||
);
|
||||
|
||||
if($this->wire('config')->ajax) {
|
||||
if($this->wire()->config->ajax) {
|
||||
header("Content-type: application/json");
|
||||
echo json_encode($result);
|
||||
exit;
|
||||
@@ -2164,7 +2229,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*
|
||||
*/
|
||||
public function ___deleteField(Field $field) {
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable($field->table);
|
||||
try {
|
||||
$result = $database->exec("DROP TABLE `$table`"); // QA
|
||||
@@ -2194,7 +2259,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function ___renamedField(Field $field, $prevName) {
|
||||
|
||||
$database = $this->wire('database');
|
||||
$database = $this->wire()->database;
|
||||
$table = $database->escapeTable(Field::tablePrefix . $field->name . '_votes');
|
||||
$prevTable = $database->escapeTable(Field::tablePrefix . $prevName . '_votes');
|
||||
|
||||
@@ -2272,7 +2337,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
protected function exportComment($comment) {
|
||||
if(is_object($comment)) $comment = $comment->getArray();
|
||||
if(isset($comment['created_users_id'])) {
|
||||
$u = $this->wire('users')->get((int) $comment['created_users_id']);
|
||||
$u = $this->wire()->users->get((int) $comment['created_users_id']);
|
||||
$comment['created_user'] = $u->name;
|
||||
unset($comment['created_users_id']);
|
||||
}
|
||||
@@ -2352,6 +2417,9 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
*/
|
||||
public function ___importValue(Page $page, Field $field, $value, array $options = array()) {
|
||||
|
||||
$users = $this->wire()->users;
|
||||
$sanitizer = $this->wire()->sanitizer;
|
||||
|
||||
$value = $this->exportComments($value);
|
||||
$comments = $page->get($field->name);
|
||||
$commentsArray = array();
|
||||
@@ -2408,7 +2476,7 @@ class FieldtypeComments extends FieldtypeMulti {
|
||||
|
||||
foreach($addComments as $commentArray) {
|
||||
unset($commentArray['id']);
|
||||
$u = $this->wire('users')->get("name=" . $this->wire('sanitizer')->pageName($commentArray['created_user']));
|
||||
$u = $users->get("name=" . $sanitizer->pageName($commentArray['created_user']));
|
||||
$commentArray['created_users_id'] = $u->id;
|
||||
unset($commentArray['created_user']);
|
||||
$comment = $this->makeComment($page, $field, $commentArray);
|
||||
|
@@ -5,9 +5,10 @@
|
||||
*
|
||||
* An Inputfield for handling administration of Comments.
|
||||
*
|
||||
* ProcessWire 3.x, Copyright 2019 by Ryan Cramer
|
||||
* ProcessWire 3.x, Copyright 2022 by Ryan Cramer
|
||||
* https://processwire.com
|
||||
*
|
||||
*
|
||||
* @property bool|int $useManager
|
||||
* @method InputfieldMarkup renderItem(Comment $comment, $n)
|
||||
*
|
||||
*/
|
||||
@@ -25,11 +26,29 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
}
|
||||
|
||||
protected $commentIDsToNumbers = array();
|
||||
|
||||
protected $commentsManagerUrl = '';
|
||||
|
||||
protected $statuses = array();
|
||||
|
||||
public function __construct() {
|
||||
$this->set('useManager', false);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function init() {
|
||||
parent::init();
|
||||
if($this->wire()->modules->isInstalled('ProcessCommentsManager')) {
|
||||
$this->commentsManagerUrl = $this->wire()->config->urls->admin . 'setup/comments/';
|
||||
}
|
||||
$this->statuses = array(
|
||||
Comment::statusFeatured => array($this->_x('Featured', 'comment-status'), 'trophy', 'featured'),
|
||||
Comment::statusApproved => array($this->_x('Approved', 'comment-status'), 'check-circle', 'approved'),
|
||||
Comment::statusPending => array($this->_x('Pending', 'comment-status'), 'commenting-o', 'pending'),
|
||||
Comment::statusSpam => array($this->_x('Spam', 'comment-status'), 'warning', 'spam'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Comment $comment
|
||||
* @param int $n
|
||||
@@ -37,14 +56,7 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
*
|
||||
*/
|
||||
protected function ___renderItem(Comment $comment, $n) {
|
||||
|
||||
$statuses = array(
|
||||
Comment::statusFeatured => array($this->_x('Featured', 'comment-status'), 'trophy'),
|
||||
Comment::statusApproved => array($this->_x('Approved', 'comment-status'), 'check-circle'),
|
||||
Comment::statusPending => array($this->_x('Pending', 'comment-status'), 'question-circle'),
|
||||
Comment::statusSpam => array($this->_x('Spam', 'comment-status'), 'warning'),
|
||||
);
|
||||
|
||||
|
||||
$name = $this->name;
|
||||
$names = array(
|
||||
'status' => "{$this->name}_status_{$comment->id}",
|
||||
@@ -57,13 +69,13 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
);
|
||||
|
||||
|
||||
$sanitizer = $this->wire('sanitizer');
|
||||
$sanitizer = $this->wire()->sanitizer;
|
||||
$statusName = '';
|
||||
$statusIcon = '';
|
||||
$statusOut = "<select id='$names[status]' name='$names[status]'>";
|
||||
|
||||
foreach($statuses as $status => $statusInfo) {
|
||||
list($label, $icon) = $statusInfo;
|
||||
foreach($this->statuses as $status => $statusInfo) {
|
||||
list($label, $icon, /*$name*/) = $statusInfo;
|
||||
if($comment->status == $status) {
|
||||
$selected = " selected='selected'";
|
||||
$statusName = $label;
|
||||
@@ -145,6 +157,21 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
} else {
|
||||
$starsInput = '';
|
||||
}
|
||||
|
||||
$notes = array();
|
||||
if($notifyOut) {
|
||||
$notes[] = $this->_('Email notifications:') . " $notifyOut";
|
||||
}
|
||||
if($this->commentsManagerUrl) {
|
||||
$metaQty = count($comment->getMeta());
|
||||
$page = $comment->getPage();
|
||||
$field = $comment->getField();
|
||||
$metaUrl = $this->commentsManagerUrl . "meta/?comment_id=$comment->id&page_id=$page->id&field_id=$field->id";
|
||||
// $editUrl = $this->commentsManagerUrl . "list/$field->name/all/?id=$comment->id";
|
||||
$notes[] =
|
||||
"<a href='$metaUrl' class='pw-modal' data-buttons='button'>" .
|
||||
sprintf($this->_n('%d meta value', '%d meta values', $metaQty), $metaQty) . "</a>";
|
||||
}
|
||||
|
||||
$f->value =
|
||||
"<div class='ui-helper-clearfix'>" .
|
||||
@@ -175,7 +202,7 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
"<label for='$names[text]'><span class='detail'>" . $this->_('Text') . "</span></label>" .
|
||||
"<textarea id='$names[text]' name='$names[text]' rows='5'>$text</textarea>" .
|
||||
"</p>" .
|
||||
($notifyOut ? "<p class='CommentsAdminItemNotify notes'>" . $this->_('Email notifications:') . " $notifyOut</p>" : "") .
|
||||
(count($notes) ? "<p class='CommentsAdminItemNotify detail'>" . implode(' • ', $notes) . "</p>" : "") .
|
||||
"<input class='CommentsAdminItemSort' type='hidden' name='sort_{$this->name}_{$comment->id}' value='$n' />" .
|
||||
"";
|
||||
|
||||
@@ -184,30 +211,79 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
|
||||
public function ___render() {
|
||||
|
||||
if(!count($this->value)) return "<p>" . $this->_('There are currently no items to display.') . "</p>";
|
||||
$value = $this->value;
|
||||
|
||||
if($this->useManager || !count($value)) {
|
||||
$out = $this->renderValue();
|
||||
|
||||
} else {
|
||||
$n = 0;
|
||||
foreach($value as $comment) {
|
||||
$this->commentIDsToNumbers[$comment->id] = ++$n;
|
||||
}
|
||||
|
||||
$n = 0;
|
||||
foreach($this->value as $comment) {
|
||||
$this->commentIDsToNumbers[$comment->id] = ++$n;
|
||||
$fieldset = new InputfieldWrapper(); // wired
|
||||
$this->wire($fieldset);
|
||||
|
||||
$n = 0;
|
||||
foreach($value as $comment) {
|
||||
$f = $this->renderItem($comment, $n++);
|
||||
$f->addClass($this->wrapClass);
|
||||
$fieldset->add($f);
|
||||
}
|
||||
|
||||
$out = $fieldset->render();
|
||||
}
|
||||
|
||||
$fieldset = new InputfieldWrapper(); // wired
|
||||
$this->wire($fieldset);
|
||||
|
||||
$n = 0;
|
||||
foreach($this->value as $comment) {
|
||||
$f = $this->renderItem($comment, $n++);
|
||||
$f->addClass($this->wrapClass);
|
||||
$fieldset->add($f);
|
||||
}
|
||||
|
||||
$out = $fieldset->render();
|
||||
//$this->addClass('InputfieldFieldset', 'wrapClass');
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function ___renderValue() {
|
||||
|
||||
$value = $this->attr('value');
|
||||
|
||||
if(!count($value)) {
|
||||
return "<p>" . $this->_('There are currently no items to display.') . "</p>";
|
||||
}
|
||||
|
||||
$items = array();
|
||||
$qtys = array();
|
||||
$total = 0;
|
||||
$field = null;
|
||||
$page = null;
|
||||
|
||||
foreach($value as $comment) {
|
||||
/** @var Comment $comment */
|
||||
$total++;
|
||||
if(!$field) $field = $comment->getField();
|
||||
if(!$page) $page = $comment->getPage();
|
||||
$status = $comment->status;
|
||||
if(!isset($this->statuses[$status])) continue;
|
||||
if(!isset($qtys[$status])) $qtys[$status] = 0;
|
||||
$qtys[$status]++;
|
||||
}
|
||||
|
||||
$url = $this->commentsManagerUrl . "list/$field->name/all/?pages_id=$page->id";
|
||||
$icon = wireIconMarkup('comments');
|
||||
$item = $icon . ' ' . sprintf($this->_n('%d comment', '%d comments', $total), $total);
|
||||
|
||||
if($page->editable($field)) $item = "<a href='$url' target='_blank'>$item</a>";
|
||||
$items[] = $item;
|
||||
|
||||
foreach($this->statuses as $status => $statusInfo) {
|
||||
if(empty($qtys[$status])) continue;
|
||||
$qty = $qtys[$status];
|
||||
list($label, $icon, /*$name*/) = $statusInfo;
|
||||
$icon = wireIconMarkup($icon);
|
||||
$items[] = "<span class='ui-priority-secondary'>$icon $qty $label</span>";
|
||||
}
|
||||
|
||||
return "<p>" . implode(' ', $items) . "</p>";
|
||||
}
|
||||
|
||||
public function ___processInput(WireInputData $input) {
|
||||
|
||||
if($this->useManager) return $this;
|
||||
|
||||
$n = 1;
|
||||
$names = array(
|
||||
@@ -253,5 +329,27 @@ class InputfieldCommentsAdmin extends Inputfield implements InputfieldItemList {
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function ___getConfigInputfields() {
|
||||
$modules = $this->wire()->modules;
|
||||
$inputfields = parent::___getConfigInputfields();
|
||||
|
||||
/** @var InputfieldToggle $f */
|
||||
$f = $modules->get('InputfieldToggle');
|
||||
$f->attr('name', 'useManager');
|
||||
$f->label = $this->_('Use comments manager rather than in-page editor?');
|
||||
$f->description =
|
||||
$this->_('When enabled user will be directed to the dedicated comments manager for editing comments.') . ' ' .
|
||||
$this->_('This may be preferable because the comments manager has more features and uses pagination.');
|
||||
$value = (int) $this->get('useManager');
|
||||
$f->val($value);
|
||||
$f->themeOffset = 1;
|
||||
$inputfields->prepend($f);
|
||||
if($value && !$this->commentsManagerUrl) {
|
||||
$modules->getInstall('ProcessCommentsManager');
|
||||
}
|
||||
|
||||
return $inputfields;
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -7,8 +7,10 @@ $(document).ready(function() {
|
||||
return false;
|
||||
});
|
||||
|
||||
$('.WireTabs').css('opacity', 1.0);
|
||||
$('.WireTabs a.on').parent('li').click();
|
||||
var $tabs = $('.WireTabs');
|
||||
$tabs.css('opacity', 1.0);
|
||||
$tabs.find('.uk-active').removeClass('uk-active');
|
||||
$tabs.find('a.on').parent('li').click().addClass('uk-active');
|
||||
|
||||
$("a.CommentTextEdit").click(function() {
|
||||
var $textarea = $("<textarea></textarea>");
|
||||
|
@@ -1 +1 @@
|
||||
$(document).ready(function(){var ready=false;$(document).on("click",".WireTabs a",function($event){if(ready)window.location.href=$(this).attr("href");return false});$(".WireTabs").css("opacity",1);$(".WireTabs a.on").parent("li").click();$("a.CommentTextEdit").click(function(){var $textarea=$("<textarea></textarea>");var $parent=$(this).closest(".CommentTextEditable");$parent.parent(".CommentText").removeClass("CommentTextOverflow");$textarea.attr("name",$parent.attr("id"));$textarea.addClass($parent.attr("data-textarea-class"));$(this).remove();$textarea.val($parent.text());$parent.after($textarea);$parent.remove();return false});$(".CommentText").click(function(){$(this).find("a.CommentTextEdit").click();return false});$(".CommentItem").each(function(){var $item=$(this);var $table=$item.find(".CommentItemInfo");var height=$table.height()+30;var $text=$item.find(".CommentText");if($text.height()>height){$text.addClass("CommentTextOverflow")}});$("#CommentLimitSelect").change(function(){window.location="./?limit="+parseInt($(this).val())});$("#CommentListSort").change(function(){window.location="./?sort="+$(this).val()});function commentCheckboxClicked($checkbox){var $item=$checkbox.closest(".CommentItem");if($checkbox.is(":checked")){$item.addClass("CommentChecked")}else{$item.removeClass("CommentChecked")}}$(".CommentCheckbox").click(function(){commentCheckboxClicked($(this))});$("#CommentCheckAll").click(function(){var $items=$(".CommentCheckbox");if($(this).is(":checked")){$items.prop("checked",true)}else{$items.prop("checked",false)}$items.each(function(){commentCheckboxClicked($(this))})});$("#CommentActions").change(function(){var val=$(this).val();if(!val.length)return;var $checkedItems=$(".CommentChecked");if($checkedItems.length){$checkedItems.each(function(){if(val=="reset-upvotes"){$(this).find(".CommentUpvotes > input").val(0).change()}else if(val=="reset-downvotes"){$(this).find(".CommentDownvotes > input").val(0).change()}else{$(this).find(".CommentStatus > input[value='"+val+"']").click()}});$checkedItems.effect("highlight",500)}else{ProcessWire.alert($(this).attr("data-nochecked"))}$(this).val("")});$(document).on("change",".CommentItem :input",function(){var $this=$(this);if($this.is("[type='checkbox']"))return;$(this).closest(".CommentItem").addClass("CommentItemChanged")});$("#CommentListForm").submit(function(){$(this).addClass("CommentListFormSubmitted")});window.addEventListener("beforeunload",function(e){if($(".CommentListFormSubmitted").length)return;var $changes=$(".CommentItemChanged");if($changes.length==0)return;var msg=$("#CommentListForm").attr("data-unsaved");(e||window.event).returnValue=msg;return msg});var color=$(".WireTabs a.on").css("border-top-color");$("#CommentListHeader").css("border-top-color",color);ready=true});
|
||||
$(document).ready(function(){var ready=false;$(document).on("click",".WireTabs a",function($event){if(ready)window.location.href=$(this).attr("href");return false});var $tabs=$(".WireTabs");$tabs.css("opacity",1);$tabs.find(".uk-active").removeClass("uk-active");$tabs.find("a.on").parent("li").click().addClass("uk-active");$("a.CommentTextEdit").click(function(){var $textarea=$("<textarea></textarea>");var $parent=$(this).closest(".CommentTextEditable");$parent.parent(".CommentText").removeClass("CommentTextOverflow");$textarea.attr("name",$parent.attr("id"));$textarea.addClass($parent.attr("data-textarea-class"));$(this).remove();$textarea.val($parent.text());$parent.after($textarea);$parent.remove();return false});$(".CommentText").click(function(){$(this).find("a.CommentTextEdit").click();return false});$(".CommentItem").each(function(){var $item=$(this);var $table=$item.find(".CommentItemInfo");var height=$table.height()+30;var $text=$item.find(".CommentText");if($text.height()>height){$text.addClass("CommentTextOverflow")}});$("#CommentLimitSelect").change(function(){window.location="./?limit="+parseInt($(this).val())});$("#CommentListSort").change(function(){window.location="./?sort="+$(this).val()});function commentCheckboxClicked($checkbox){var $item=$checkbox.closest(".CommentItem");if($checkbox.is(":checked")){$item.addClass("CommentChecked")}else{$item.removeClass("CommentChecked")}}$(".CommentCheckbox").click(function(){commentCheckboxClicked($(this))});$("#CommentCheckAll").click(function(){var $items=$(".CommentCheckbox");if($(this).is(":checked")){$items.prop("checked",true)}else{$items.prop("checked",false)}$items.each(function(){commentCheckboxClicked($(this))})});$("#CommentActions").change(function(){var val=$(this).val();if(!val.length)return;var $checkedItems=$(".CommentChecked");if($checkedItems.length){$checkedItems.each(function(){if(val=="reset-upvotes"){$(this).find(".CommentUpvotes > input").val(0).change()}else if(val=="reset-downvotes"){$(this).find(".CommentDownvotes > input").val(0).change()}else{$(this).find(".CommentStatus > input[value='"+val+"']").click()}});$checkedItems.effect("highlight",500)}else{ProcessWire.alert($(this).attr("data-nochecked"))}$(this).val("")});$(document).on("change",".CommentItem :input",function(){var $this=$(this);if($this.is("[type='checkbox']"))return;$(this).closest(".CommentItem").addClass("CommentItemChanged")});$("#CommentListForm").submit(function(){$(this).addClass("CommentListFormSubmitted")});window.addEventListener("beforeunload",function(e){if($(".CommentListFormSubmitted").length)return;var $changes=$(".CommentItemChanged");if($changes.length==0)return;var msg=$("#CommentListForm").attr("data-unsaved");(e||window.event).returnValue=msg;return msg});var color=$(".WireTabs a.on").css("border-top-color");$("#CommentListHeader").css("border-top-color",color);ready=true});
|
@@ -6,7 +6,7 @@
|
||||
* Manage all comments field data in chronological order.
|
||||
*
|
||||
* ProcessWire 3.x
|
||||
* Copyright (C) 2019 by Ryan Cramer
|
||||
* Copyright (C) 2022 by Ryan Cramer
|
||||
* This file licensed under Mozilla Public License v2.0 http://mozilla.org/MPL/2.0/
|
||||
*
|
||||
* https://processwire.com
|
||||
@@ -23,7 +23,7 @@ class ProcessCommentsManager extends Process {
|
||||
return array(
|
||||
'title' => __('Comments', __FILE__),
|
||||
'summary' => __('Manage comments in your site outside of the page editor.', __FILE__),
|
||||
'version' => 10,
|
||||
'version' => 11,
|
||||
'author' => 'Ryan Cramer',
|
||||
'icon' => 'comments',
|
||||
'requires' => 'FieldtypeComments',
|
||||
@@ -104,7 +104,7 @@ class ProcessCommentsManager extends Process {
|
||||
*
|
||||
*/
|
||||
public function init() {
|
||||
$this->wire('modules')->get('FieldtypeComments');
|
||||
$this->wire()->modules->get('FieldtypeComments');
|
||||
parent::init();
|
||||
$this->statuses = array(
|
||||
Comment::statusFeatured => 'featured',
|
||||
@@ -152,19 +152,19 @@ class ProcessCommentsManager extends Process {
|
||||
return "<p>$error</p>";
|
||||
}
|
||||
|
||||
$go = $this->wire('sanitizer')->pageName($this->wire('input')->get('go'));
|
||||
$go = $this->wire()->sanitizer->pageName($this->wire('input')->get('go'));
|
||||
|
||||
if($count == 1 || $go) {
|
||||
$field = reset($fields);
|
||||
$to = 'all';
|
||||
if($go && in_array($go, $this->statuses)) $to = $go;
|
||||
$this->wire('session')->redirect("./list/$field->name/$to/");
|
||||
$this->wire()->session->redirect("./list/$field->name/$to/");
|
||||
return '';
|
||||
}
|
||||
|
||||
$out = "<h2>" . $this->_('Please select a comments field') . "</h2><ul>";
|
||||
foreach($fields as $field) {
|
||||
$out .= "<li><a href='./list/{$field->name}/pending/'>{$field->name}</a></li>";
|
||||
$out .= "<li><a href='./list/$field->name/pending/'>$field->name</a></li>";
|
||||
}
|
||||
$out .= "</ul>";
|
||||
|
||||
@@ -301,6 +301,107 @@ class ProcessCommentsManager extends Process {
|
||||
return $this->renderComments($comments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the comment meta viewer/editor
|
||||
*
|
||||
* @return string
|
||||
* @since 3.0.203
|
||||
*
|
||||
*/
|
||||
public function ___executeMeta() {
|
||||
$input = $this->wire()->input;
|
||||
$commentId = (int) $input->get('comment_id');
|
||||
$fieldId = (int) $input->get('field_id');
|
||||
$pageId = (int) $input->get('page_id');
|
||||
$modal = (int) $input->get('modal');
|
||||
|
||||
if($commentId < 1 || $fieldId < 1 || $pageId < 1) {
|
||||
throw new WireException("Missing one of: comment_id, field_id, page_id");
|
||||
}
|
||||
|
||||
$field = $this->wire()->fields->get($fieldId);
|
||||
$fieldtype = $field->type; /** @var FieldtypeComments $fieldtype */
|
||||
if(!$field || (!$fieldtype instanceof FieldtypeComments)) {
|
||||
throw new WireException("Invalid field specified");
|
||||
}
|
||||
|
||||
$page = $this->wire()->pages->get($pageId);
|
||||
if(!$page->id || !$page->hasField($field) || !$page->editable($field)) {
|
||||
throw new WireException("Invalid or non-editable page specified");
|
||||
}
|
||||
|
||||
$comment = $fieldtype->getCommentByID($page, $field, $commentId);
|
||||
if(!$comment) throw new WireException("Cannot find comment $commentId");
|
||||
|
||||
$meta = $comment->getMeta();
|
||||
$flags = JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
|
||||
if(defined('JSON_UNESCAPED_LINE_TERMINATORS')) $flags = $flags | JSON_UNESCAPED_LINE_TERMINATORS;
|
||||
$metaJSON = empty($meta) ? '{ }' : json_encode($meta, $flags);
|
||||
$numRows = substr_count($metaJSON, "\n")+1;
|
||||
if($numRows < 10) $numRows = 10;
|
||||
|
||||
$this->headline(sprintf($this->_('Meta data for comment #%d'), $commentId));
|
||||
if(empty($meta)) $this->message($this->_('Comment currently has no meta data'));
|
||||
// $out = "<pre id='meta-preview'>$metaEncodedJSON</pre>";
|
||||
|
||||
$modules = $this->wire()->modules;
|
||||
|
||||
/** @var InputfieldForm $form */
|
||||
$form = $modules->get('InputfieldForm');
|
||||
$form->attr('method', 'post');
|
||||
$form->attr('action', "./?comment_id=$commentId&page_id=$pageId&field_id=$fieldId&modal=$modal");
|
||||
|
||||
/** @var InputfieldTextarea $f */
|
||||
$f = $modules->get('InputfieldTextarea');
|
||||
$f->attr('name', 'meta');
|
||||
$f->label = $this->_('Meta JSON editor');
|
||||
$f->val($metaJSON);
|
||||
$f->attr('rows', $numRows);
|
||||
$f->attr('style', "font-family:monospace;");
|
||||
$form->add($f);
|
||||
|
||||
/** @var InputfieldSubmit $f */
|
||||
$f = $modules->get('InputfieldSubmit');
|
||||
$f->attr('name', 'submit_save');
|
||||
$f->val($this->_('Save changes'));
|
||||
$form->add($f);
|
||||
|
||||
/** @var InputfieldSubmit $f */
|
||||
$f = $modules->get('InputfieldButton');
|
||||
$f->attr('name', 'submit_cancel');
|
||||
$f->setSecondary(true);
|
||||
$f->val($this->_('Cancel'));
|
||||
$form->add($f);
|
||||
|
||||
if($input->post('submit_save')) {
|
||||
$session = $this->wire()->session;
|
||||
$form->processInput($input->post);
|
||||
$metaInput = $form->getChildByName('meta');
|
||||
$metaSaveJSON = $metaInput->val();
|
||||
if($metaSaveJSON === $metaJSON) {
|
||||
$this->message($this->_('No changes detected'));
|
||||
$session->redirect($form->attr('action'));
|
||||
} else {
|
||||
$meta = json_decode($metaSaveJSON, true);
|
||||
if(is_array($meta)) {
|
||||
$result = $fieldtype->updateComment($page, $field, $comment, array('meta' => $meta));
|
||||
if($result) {
|
||||
$this->message(sprintf($this->_('Updated meta for comment #%d'), $commentId));
|
||||
$session->redirect($form->attr('action'));
|
||||
} else {
|
||||
$this->error(sprintf($this->_('Error updating meata for comment #%d'), $commentId));
|
||||
}
|
||||
} else {
|
||||
$this->error($this->_('Cannot save because invalid JSON'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$out = $form->render();
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process changes to posted comments
|
||||
*
|
||||
@@ -485,7 +586,7 @@ class ProcessCommentsManager extends Process {
|
||||
$page = $comment->getPage();
|
||||
$pageTitle = $sanitizer->entities1($page->get('title|name'));
|
||||
$field = $comment->getField();
|
||||
$adminTheme = $this->wire('adminTheme');
|
||||
$adminTheme = $this->wire()->adminTheme;
|
||||
$isSuperuser = $this->user->isSuperuser();
|
||||
$allowDepth = $field->depth > 0;
|
||||
$allowDepthChange = $isSuperuser && $allowDepth;
|
||||
@@ -494,6 +595,10 @@ class ProcessCommentsManager extends Process {
|
||||
$numChildren = 0;
|
||||
$text = $this->renderCommentText($comment);
|
||||
$id = $comment->id;
|
||||
|
||||
/** @var JqueryUI $jQueryUI */
|
||||
$jQueryUI = $this->wire()->modules->get('JqueryUI');
|
||||
$jQueryUI->use('modal');
|
||||
|
||||
$icons = array(
|
||||
'edit' => 'edit',
|
||||
@@ -528,6 +633,7 @@ class ProcessCommentsManager extends Process {
|
||||
$labels = array(
|
||||
'edit' => $this->_('edit'),
|
||||
'view' => $this->_('view'),
|
||||
'meta' => $this->_('meta'),
|
||||
'page' => $this->_('Page'),
|
||||
'date' => $this->_('When'),
|
||||
'status' => $this->_('Status'),
|
||||
@@ -566,6 +672,7 @@ class ProcessCommentsManager extends Process {
|
||||
'siblings' => "../all/?pages_id=$page->id",
|
||||
'pageView' => "$page->url#Comment$id",
|
||||
'pageEdit' => $page->editUrl(),
|
||||
'metaEdit' => "../../../meta/?comment_id=$comment->id&page_id=$page->id&field_id=$field->id&modal=1",
|
||||
'email' => "./?email=" . urlencode($values['email']),
|
||||
'cite' => "../all/?cite=" . urlencode($values['cite']),
|
||||
'ip' => "../all/?ip=" . urlencode($values['ip']),
|
||||
@@ -707,6 +814,10 @@ class ProcessCommentsManager extends Process {
|
||||
foreach($outs as $out) if(!empty($out)) $numRows++;
|
||||
$contentClass = 'CommentContent';
|
||||
if($numRows >= 7) $contentClass .= ' CommentContentLarge';
|
||||
|
||||
$meta = $comment->getMeta();
|
||||
$metaCnt = count($meta);
|
||||
$metaTip = sprintf($this->_n('%d value', '%d values', $metaCnt), $metaCnt);
|
||||
|
||||
$out =
|
||||
"<div class='CommentItem ui-helper-clearfix CommentItemStatus$comment->status'>" .
|
||||
@@ -722,7 +833,9 @@ class ProcessCommentsManager extends Process {
|
||||
"<a href='$urls[siblings]' class='pw-tooltip' title='$tooltips[pageFilter]'><strong>$pageTitle</strong></a> " .
|
||||
"<span class='detail'> " .
|
||||
"<a class='detail' href='$urls[pageView]'>$labels[view]</a> / " .
|
||||
"<a class='detail' href='$urls[pageEdit]'>$labels[edit]</a>" .
|
||||
"<a class='detail' href='$urls[pageEdit]'>$labels[edit]</a> / " .
|
||||
"<a class='detail pw-tooltip pw-modal' title='$metaTip' href='$urls[metaEdit]' " .
|
||||
"data-buttons='button' data-close='button[name=submit_cancel]'>$labels[meta]</a>" .
|
||||
"</span>" .
|
||||
"<span class='CommentChangedIcon'>$icons[changed]</span>" .
|
||||
"</td>" .
|
||||
@@ -883,18 +996,23 @@ class ProcessCommentsManager extends Process {
|
||||
*
|
||||
*/
|
||||
protected function renderComments(CommentArray $comments) {
|
||||
|
||||
$input = $this->wire()->input;
|
||||
|
||||
$commentsBody = '';
|
||||
$cnt = 0;
|
||||
$status = $this->input->urlSegment3;
|
||||
$status = $input->urlSegment3;
|
||||
$start = $comments->getStart();
|
||||
$limit = $comments->getLimit();
|
||||
$total = $comments->getTotal();
|
||||
$pageNumPrefix = $this->config->pageNumUrlPrefix;
|
||||
$pageNum = $this->wire('input')->pageNum;
|
||||
$pageNum = $input->pageNum();
|
||||
$queryString = $this->getQueryString();
|
||||
$unsavedChangesLabel = $this->_('You have unsaved changes!');
|
||||
$field = $comments->getField();
|
||||
$pagesId = (int) $input->get('pages_id');
|
||||
|
||||
if($pagesId) $this->breadcrumb("./$queryString", "Page $pagesId");
|
||||
|
||||
foreach($comments as $comment) {
|
||||
/** @var Comment $comment */
|
||||
@@ -905,7 +1023,7 @@ class ProcessCommentsManager extends Process {
|
||||
}
|
||||
|
||||
/** @var MarkupPagerNav $pager */
|
||||
$pager = $this->wire('modules')->get('MarkupPagerNav');
|
||||
$pager = $this->wire()->modules->get('MarkupPagerNav');
|
||||
$pagerOut = $pager->render($comments, array(
|
||||
'queryString' => $queryString,
|
||||
'baseUrl' => "./"
|
||||
@@ -913,15 +1031,15 @@ class ProcessCommentsManager extends Process {
|
||||
/** @var JqueryWireTabs $wireTabs */
|
||||
$wireTabs = $this->modules->get('JqueryWireTabs');
|
||||
$tabs = array();
|
||||
$class = $this->input->urlSegment3 === 'all' ? 'on' : '';
|
||||
$tabs["tabStatusAll"] = "<a class='$class' href='../all/'>" . $this->labelAll . "</a>";
|
||||
$class = $input->urlSegment3 === 'all' ? 'on' : '';
|
||||
$tabs["tabStatusAll"] = "<a class='$class' href='../all/$queryString'>" . $this->labelAll . "</a>";
|
||||
|
||||
foreach($this->statuses as $status => $name) {
|
||||
if($status == Comment::statusDelete) continue;
|
||||
$class = $this->input->urlSegment3 === $name ? 'on' : '';
|
||||
$class = $input->urlSegment3 === $name ? 'on' : '';
|
||||
$label = $this->statusTranslations[$status];
|
||||
if($label === $name) $label = ucfirst($label);
|
||||
$tabs["tabStatus$status"] = "<a class='$class' href='../$name/'>$label</a>";
|
||||
$tabs["tabStatus$status"] = "<a class='$class' href='../$name/$queryString'>$label</a>";
|
||||
}
|
||||
|
||||
$tabsOut = $wireTabs->renderTabList($tabs);
|
||||
@@ -936,7 +1054,7 @@ class ProcessCommentsManager extends Process {
|
||||
$button = $button->render();
|
||||
} else $button = '';
|
||||
|
||||
if($this->input->pageNum > 1) {
|
||||
if($input->pageNum > 1) {
|
||||
$queryString = "./$pageNumPrefix$pageNum$queryString";
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user