mirror of
https://github.com/danpros/htmly.git
synced 2026-04-17 11:16:00 +05:30
Initial commit - adding comments functionality to HTMLy.
This commit is contained in:
parent
dde01601bd
commit
eb7eda6da6
11 changed files with 1613 additions and 3 deletions
297
system/admin/views/comments.html.php
Normal file
297
system/admin/views/comments.html.php
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
<?php if (!defined('HTMLY')) die('HTMLy'); ?>
|
||||
<h2><?php echo i18n('Comments_Management');?></h2>
|
||||
<br>
|
||||
|
||||
<?php if (isset($message)): ?>
|
||||
<div class="alert alert-<?php echo $message['type']; ?> alert-dismissible fade show">
|
||||
<?php echo $message['text']; ?>
|
||||
<button type="button" class="close" data-dismiss="alert">×</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<nav>
|
||||
<div class="nav nav-tabs" id="nav-tab">
|
||||
<a class="nav-item nav-link <?php echo (!isset($tab) || $tab === 'all') ? 'active' : ''; ?>"
|
||||
href="<?php echo site_url();?>admin/comments"><?php echo i18n('All_Comments');?></a>
|
||||
<a class="nav-item nav-link <?php echo (isset($tab) && $tab === 'pending') ? 'active' : ''; ?>"
|
||||
href="<?php echo site_url();?>admin/comments/pending"><?php echo i18n('Pending_Moderation');?>
|
||||
<?php if (isset($pendingCount) && $pendingCount > 0): ?>
|
||||
<span class="badge badge-warning"><?php echo $pendingCount; ?></span>
|
||||
<?php endif; ?>
|
||||
</a>
|
||||
<a class="nav-item nav-link <?php echo (isset($tab) && $tab === 'settings') ? 'active' : ''; ?>"
|
||||
href="<?php echo site_url();?>admin/comments/settings"><?php echo i18n('Settings');?></a>
|
||||
</div>
|
||||
</nav>
|
||||
<br><br>
|
||||
|
||||
<?php if (!isset($tab) || $tab === 'all' || $tab === 'pending'): ?>
|
||||
<!-- Comments List -->
|
||||
<?php if (!empty($comments)): ?>
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php echo i18n('Author');?></th>
|
||||
<th><?php echo i18n('Comment');?></th>
|
||||
<th><?php echo i18n('Post_Page');?></th>
|
||||
<th><?php echo i18n('Date');?></th>
|
||||
<th><?php echo i18n('Status');?></th>
|
||||
<th><?php echo i18n('Actions');?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($comments as $comment): ?>
|
||||
<tr id="comment-<?php echo $comment['id']; ?>">
|
||||
<td>
|
||||
<strong><?php echo _h($comment['name']); ?></strong><br>
|
||||
<small><?php echo _h($comment['email']); ?></small><br>
|
||||
<small class="text-muted">IP: <?php echo _h($comment['ip']); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$preview = mb_substr($comment['comment'], 0, 100);
|
||||
echo _h($preview);
|
||||
if (mb_strlen($comment['comment']) > 100) echo '...';
|
||||
?>
|
||||
<?php if (!empty($comment['parent_id'])): ?>
|
||||
<br><small class="text-info"><em><?php echo i18n('Reply_to_comment');?></em></small>
|
||||
<?php endif; ?>
|
||||
<?php if ($comment['notify']): ?>
|
||||
<br><small class="text-success"><em><?php echo i18n('Notifications_enabled');?></em></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<a href="<?php echo site_url() . $comment['post_id']; ?>" target="_blank">
|
||||
<?php echo _h($comment['post_id']); ?>
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<?php echo format_date($comment['timestamp']); ?>
|
||||
<?php if (isset($comment['modified'])): ?>
|
||||
<br><small class="text-muted"><?php echo i18n('Modified');?>: <?php echo $comment['modified']; ?></small>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($comment['published']): ?>
|
||||
<span class="badge badge-success"><?php echo i18n('Published');?></span>
|
||||
<?php else: ?>
|
||||
<span class="badge badge-warning"><?php echo i18n('Pending');?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if (!$comment['published']): ?>
|
||||
<a class="btn btn-success btn-xs"
|
||||
href="<?php echo site_url(); ?>admin/comments/publish/<?php echo $comment['post_id']; ?>/<?php echo $comment['id']; ?>"
|
||||
onclick="return confirm('<?php echo i18n('Confirm_publish_comment'); ?>');">
|
||||
<?php echo i18n('Publish');?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a class="btn btn-primary btn-xs"
|
||||
href="<?php echo site_url(); ?>admin/comments/edit/<?php echo $comment['post_id']; ?>/<?php echo $comment['id']; ?>">
|
||||
<?php echo i18n('Edit');?>
|
||||
</a>
|
||||
<a class="btn btn-danger btn-xs"
|
||||
href="<?php echo site_url(); ?>admin/comments/delete/<?php echo $comment['post_id']; ?>/<?php echo $comment['id']; ?>"
|
||||
onclick="return confirm('<?php echo i18n('Confirm_delete_comment'); ?>');">
|
||||
<?php echo i18n('Delete');?>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else: ?>
|
||||
<p><?php echo i18n('No_comments_found'); ?>.</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php elseif ($tab === 'settings'): ?>
|
||||
<!-- Settings Form -->
|
||||
<form method="POST" action="<?php echo site_url(); ?>admin/comments/settings">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo get_csrf(); ?>">
|
||||
|
||||
<!-- // removed by Emidio 20251105
|
||||
<div class="alert alert-info">
|
||||
<strong><?php echo i18n('Note'); ?>:</strong> <?php echo i18n('Enable_comments_in_main_config'); ?>
|
||||
<br>
|
||||
<code>config/config.ini</code> → <code>comment.system = "local"</code>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<h4><?php echo i18n('General_Settings');?></h4>
|
||||
<hr>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"><?php echo i18n('Comment_Moderation');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" name="comments.moderation" value="true"
|
||||
<?php echo comments_config('comments.moderation') === 'true' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label"><?php echo i18n('Require_admin_approval');?></label>
|
||||
</div>
|
||||
<small class="form-text text-muted"><?php echo i18n('Comments_moderation_desc');?></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"><?php echo i18n('Anti_Spam_Protection');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" name="comments.honeypot" value="true"
|
||||
<?php echo comments_config('comments.honeypot') === 'true' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label"><?php echo i18n('Enable_honeypot');?></label>
|
||||
</div>
|
||||
<small class="form-text text-muted"><?php echo i18n('Honeypot_desc');?></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><?php echo i18n('Email_Notifications');?></h4>
|
||||
<hr>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"><?php echo i18n('Enable_Notifications');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" name="comments.notify" value="true"
|
||||
<?php echo comments_config('comments.notify') === 'true' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label"><?php echo i18n('Send_email_notifications');?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="admin-email" class="col-sm-3 col-form-label"><?php echo i18n('Admin_Email');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="email" class="form-control" id="admin-email" name="comments.admin.email"
|
||||
value="<?php echo _h(comments_config('comments.admin.email')); ?>"
|
||||
placeholder="admin@example.com">
|
||||
<small class="form-text text-muted"><?php echo i18n('Admin_email_desc');?></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4><?php echo i18n('SMTP_Settings');?></h4>
|
||||
<hr>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3 col-form-label"><?php echo i18n('Enable_SMTP');?></label>
|
||||
<div class="col-sm-9">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" name="comments.mail.enabled" value="true"
|
||||
<?php echo comments_config('comments.mail.enabled') === 'true' ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label"><?php echo i18n('Enable_SMTP_for_emails');?></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-host" class="col-sm-3 col-form-label"><?php echo i18n('SMTP_Host');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="mail-host" name="comments.mail.host"
|
||||
value="<?php echo _h(comments_config('comments.mail.host')); ?>"
|
||||
placeholder="smtp.gmail.com">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-port" class="col-sm-3 col-form-label"><?php echo i18n('SMTP_Port');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" class="form-control" id="mail-port" name="comments.mail.port"
|
||||
value="<?php echo _h(comments_config('comments.mail.port')); ?>"
|
||||
placeholder="587">
|
||||
<small class="form-text text-muted">587 (TLS) or 465 (SSL)</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-encryption" class="col-sm-3 col-form-label"><?php echo i18n('Encryption');?></label>
|
||||
<div class="col-sm-9">
|
||||
<select class="form-control" id="mail-encryption" name="comments.mail.encryption">
|
||||
<option value="tls" <?php echo comments_config('comments.mail.encryption') === 'tls' ? 'selected' : ''; ?>>TLS</option>
|
||||
<option value="ssl" <?php echo comments_config('comments.mail.encryption') === 'ssl' ? 'selected' : ''; ?>>SSL</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-username" class="col-sm-3 col-form-label"><?php echo i18n('SMTP_Username');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="mail-username" name="comments.mail.username"
|
||||
value="<?php echo _h(comments_config('comments.mail.username')); ?>"
|
||||
placeholder="your-email@gmail.com">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-password" class="col-sm-3 col-form-label"><?php echo i18n('SMTP_Password');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="password" class="form-control" id="mail-password" name="comments.mail.password"
|
||||
value="<?php echo _h(comments_config('comments.mail.password')); ?>"
|
||||
placeholder="<?php echo i18n('Enter_password');?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-from-email" class="col-sm-3 col-form-label"><?php echo i18n('From_Email');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="email" class="form-control" id="mail-from-email" name="comments.mail.from.email"
|
||||
value="<?php echo _h(comments_config('comments.mail.from.email')); ?>"
|
||||
placeholder="noreply@example.com">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="mail-from-name" class="col-sm-3 col-form-label"><?php echo i18n('From_Name');?></label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="mail-from-name" name="comments.mail.from.name"
|
||||
value="<?php echo _h(comments_config('comments.mail.from.name')); ?>"
|
||||
placeholder="<?php echo config('blog.title'); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-sm-9 offset-sm-3">
|
||||
<button type="submit" class="btn btn-primary"><?php echo i18n('Save_Settings');?></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($editComment)): ?>
|
||||
<!-- Edit Comment Modal/Page -->
|
||||
<h3><?php echo i18n('Edit_Comment');?></h3>
|
||||
<hr>
|
||||
<form method="POST" action="<?php echo site_url(); ?>admin/comments/update/<?php echo $editComment['post_id']; ?>/<?php echo $editComment['id']; ?>">
|
||||
<input type="hidden" name="csrf_token" value="<?php echo get_csrf(); ?>">
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-name"><?php echo i18n('Name');?></label>
|
||||
<input type="text" class="form-control" id="edit-name" name="name"
|
||||
value="<?php echo _h($editComment['name']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-email"><?php echo i18n('Email');?></label>
|
||||
<input type="email" class="form-control" id="edit-email" name="email"
|
||||
value="<?php echo _h($editComment['email']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-comment"><?php echo i18n('Comment');?></label>
|
||||
<textarea class="form-control" id="edit-comment" name="comment" rows="6" required><?php echo _h($editComment['comment']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="edit-published" name="published" value="1"
|
||||
<?php echo $editComment['published'] ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="edit-published"><?php echo i18n('Published');?></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary"><?php echo i18n('Update_Comment');?></button>
|
||||
<a href="<?php echo site_url(); ?>admin/comments" class="btn btn-secondary"><?php echo i18n('Cancel');?></a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
|
@ -158,6 +158,12 @@
|
|||
Facebook
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="-config-comment.system" id="comment.system3" value="local" <?php if (config('comment.system') === 'local'):?>checked<?php endif;?>>
|
||||
<label class="form-check-label" for="comment.system3">
|
||||
Local
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -150,6 +150,50 @@ if (isset($author[0])) {
|
|||
</ul>
|
||||
</li>
|
||||
<?php if ($role === 'editor' || $role === 'admin'):?>
|
||||
<?php if (local()): ?>
|
||||
<li class="nav-item has-treeview menu-open">
|
||||
<a href="#" class="nav-link">
|
||||
<i class="nav-icon fa fa-comments"></i>
|
||||
<p>
|
||||
<?php echo i18n('Comments'); ?>
|
||||
<?php
|
||||
$pendingCount = getPendingCommentsCount();
|
||||
if ($pendingCount > 0): ?>
|
||||
<span class="badge badge-warning right"><?php echo $pendingCount; ?></span>
|
||||
<?php endif; ?>
|
||||
<i class="right fa fa-angle-left"></i>
|
||||
</p>
|
||||
</a>
|
||||
<ul class="nav nav-treeview">
|
||||
<li class="nav-item">
|
||||
<a href="<?php echo site_url();?>admin/comments" class="nav-link">
|
||||
<p>
|
||||
<?php echo i18n('All_Comments'); ?>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a href="<?php echo site_url();?>admin/comments/pending" class="nav-link">
|
||||
<p>
|
||||
<?php echo i18n('Pending_Moderation'); ?>
|
||||
<?php if ($pendingCount > 0): ?>
|
||||
<span class="badge badge-warning right"><?php echo $pendingCount; ?></span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<?php if ($role === 'admin'):?>
|
||||
<li class="nav-item">
|
||||
<a href="<?php echo site_url();?>admin/comments/settings" class="nav-link">
|
||||
<p>
|
||||
<?php echo i18n('Settings'); ?>
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif;?>
|
||||
</ul>
|
||||
</li>
|
||||
<?php endif;?>
|
||||
<li class="nav-item has-treeview menu-open">
|
||||
<a href="#" class="nav-link">
|
||||
<i class="nav-icon fa fa-cogs"></i>
|
||||
|
|
|
|||
290
system/htmly.php
290
system/htmly.php
|
|
@ -3095,7 +3095,255 @@ get('/admin/categories/:category', function ($category) {
|
|||
}
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Show admin/comments - All comments
|
||||
get('/admin/comments', function () {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if (login() && ($role === 'admin' || $role === 'editor')) {
|
||||
config('views.root', 'system/admin/views');
|
||||
|
||||
$comments = getAllComments();
|
||||
$pendingCount = getPendingCommentsCount();
|
||||
|
||||
render('comments', array(
|
||||
'title' => generate_title('is_default', i18n('Comments_Management')),
|
||||
'description' => safe_html(strip_tags(blog_description())),
|
||||
'canonical' => site_url(),
|
||||
'metatags' => generate_meta(null, null),
|
||||
'type' => 'is_admin-comments',
|
||||
'is_admin' => true,
|
||||
'bodyclass' => 'admin-comments',
|
||||
'breadcrumb' => '<a href="' . site_url() . '">' . config('breadcrumb.home') . '</a> » ' . i18n('Comments'),
|
||||
'tab' => 'all',
|
||||
'comments' => $comments,
|
||||
'pendingCount' => $pendingCount
|
||||
));
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Show admin/comments/pending - Pending comments
|
||||
get('/admin/comments/pending', function () {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if (login() && ($role === 'admin' || $role === 'editor')) {
|
||||
config('views.root', 'system/admin/views');
|
||||
|
||||
$allComments = getAllComments();
|
||||
$comments = array_filter($allComments, function($comment) {
|
||||
return !$comment['published'];
|
||||
});
|
||||
$pendingCount = count($comments);
|
||||
|
||||
render('comments', array(
|
||||
'title' => generate_title('is_default', i18n('Pending_Comments')),
|
||||
'description' => safe_html(strip_tags(blog_description())),
|
||||
'canonical' => site_url(),
|
||||
'metatags' => generate_meta(null, null),
|
||||
'type' => 'is_admin-comments',
|
||||
'is_admin' => true,
|
||||
'bodyclass' => 'admin-comments',
|
||||
'breadcrumb' => '<a href="' . site_url() . '">' . config('breadcrumb.home') . '</a> » ' . i18n('Comments') . ' » ' . i18n('Pending'),
|
||||
'tab' => 'pending',
|
||||
'comments' => $comments,
|
||||
'pendingCount' => $pendingCount
|
||||
));
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Show admin/comments/settings - Settings page
|
||||
get('/admin/comments/settings', function () {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if (login() && $role === 'admin') {
|
||||
config('views.root', 'system/admin/views');
|
||||
|
||||
$pendingCount = getPendingCommentsCount();
|
||||
|
||||
render('comments', array(
|
||||
'title' => generate_title('is_default', i18n('Comments_Settings')),
|
||||
'description' => safe_html(strip_tags(blog_description())),
|
||||
'canonical' => site_url(),
|
||||
'metatags' => generate_meta(null, null),
|
||||
'type' => 'is_admin-comments',
|
||||
'is_admin' => true,
|
||||
'bodyclass' => 'admin-comments',
|
||||
'breadcrumb' => '<a href="' . site_url() . '">' . config('breadcrumb.home') . '</a> » ' . i18n('Comments') . ' » ' . i18n('Settings'),
|
||||
'tab' => 'settings',
|
||||
'pendingCount' => $pendingCount
|
||||
));
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Save comments settings
|
||||
post('/admin/comments/settings', function () {
|
||||
$proper = is_csrf_proper(from($_REQUEST, 'csrf_token'));
|
||||
if (login() && $proper) {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if ($role === 'admin') {
|
||||
$config = array();
|
||||
|
||||
// Get checkbox values (they are not sent if unchecked)
|
||||
// Note: HTML forms convert dots to underscores in POST data
|
||||
$config['comments.moderation'] = isset($_POST['comments_moderation']) ? 'true' : 'false';
|
||||
$config['comments.honeypot'] = isset($_POST['comments_honeypot']) ? 'true' : 'false';
|
||||
$config['comments.notify'] = isset($_POST['comments_notify']) ? 'true' : 'false';
|
||||
$config['comments.mail.enabled'] = isset($_POST['comments_mail_enabled']) ? 'true' : 'false';
|
||||
|
||||
// Get text fields (using underscores because HTML forms convert dots)
|
||||
$config['comments.admin.email'] = from($_POST, 'comments_admin_email');
|
||||
$config['comments.mail.host'] = from($_POST, 'comments_mail_host');
|
||||
$config['comments.mail.port'] = from($_POST, 'comments_mail_port');
|
||||
$config['comments.mail.username'] = from($_POST, 'comments_mail_username');
|
||||
$config['comments.mail.encryption'] = from($_POST, 'comments_mail_encryption');
|
||||
$config['comments.mail.from.email'] = from($_POST, 'comments_mail_from_email');
|
||||
$config['comments.mail.from.name'] = from($_POST, 'comments_mail_from_name');
|
||||
|
||||
// Only update password if provided
|
||||
$password = from($_POST, 'comments_mail_password');
|
||||
if (!empty($password)) {
|
||||
$config['comments.mail.password'] = $password;
|
||||
}
|
||||
|
||||
// Debug: log to file (remove after debugging)
|
||||
file_put_contents('content/comments-debug.log',
|
||||
date('Y-m-d H:i:s') . "\n" .
|
||||
"POST data: " . print_r($_POST, true) . "\n" .
|
||||
"Config array: " . print_r($config, true) . "\n\n",
|
||||
FILE_APPEND
|
||||
);
|
||||
|
||||
$result = save_comments_config($config);
|
||||
|
||||
// Log result
|
||||
file_put_contents('content/comments-debug.log',
|
||||
"Save result: " . ($result ? "SUCCESS ($result bytes)" : "FAILED") . "\n" .
|
||||
"File content after save:\n" . file_get_contents('config/comments.ini') . "\n\n",
|
||||
FILE_APPEND
|
||||
);
|
||||
|
||||
$redir = site_url() . 'admin/comments/settings';
|
||||
header("location: $redir");
|
||||
} else {
|
||||
$redir = site_url();
|
||||
header("location: $redir");
|
||||
}
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Show edit comment form
|
||||
get('/admin/comments/edit/:postid/:commentid', function ($postid, $commentid) {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if (login() && ($role === 'admin' || $role === 'editor')) {
|
||||
config('views.root', 'system/admin/views');
|
||||
|
||||
$comments = getComments($postid, true);
|
||||
$editComment = null;
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
if ($comment['id'] === $commentid) {
|
||||
$comment['post_id'] = $postid;
|
||||
$editComment = $comment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($editComment) {
|
||||
$pendingCount = getPendingCommentsCount();
|
||||
|
||||
render('comments', array(
|
||||
'title' => generate_title('is_default', i18n('Edit_Comment')),
|
||||
'description' => safe_html(strip_tags(blog_description())),
|
||||
'canonical' => site_url(),
|
||||
'metatags' => generate_meta(null, null),
|
||||
'type' => 'is_admin-comments',
|
||||
'is_admin' => true,
|
||||
'bodyclass' => 'admin-comments',
|
||||
'breadcrumb' => '<a href="' . site_url() . '">' . config('breadcrumb.home') . '</a> » <a href="' . site_url() . 'admin/comments">' . i18n('Comments') . '</a> » ' . i18n('Edit'),
|
||||
'editComment' => $editComment,
|
||||
'pendingCount' => $pendingCount
|
||||
));
|
||||
} else {
|
||||
$redir = site_url() . 'admin/comments';
|
||||
header("location: $redir");
|
||||
}
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Update comment
|
||||
post('/admin/comments/update/:postid/:commentid', function ($postid, $commentid) {
|
||||
$proper = is_csrf_proper(from($_REQUEST, 'csrf_token'));
|
||||
if (login() && $proper) {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if ($role === 'admin' || $role === 'editor') {
|
||||
$data = array(
|
||||
'name' => from($_POST, 'name'),
|
||||
'email' => from($_POST, 'email'),
|
||||
'comment' => from($_POST, 'comment'),
|
||||
'published' => isset($_POST['published'])
|
||||
);
|
||||
|
||||
if (commentModify($postid, $commentid, $data)) {
|
||||
$redir = site_url() . 'admin/comments';
|
||||
header("location: $redir");
|
||||
} else {
|
||||
$redir = site_url() . 'admin/comments/edit/' . $postid . '/' . $commentid;
|
||||
header("location: $redir");
|
||||
}
|
||||
} else {
|
||||
$redir = site_url();
|
||||
header("location: $redir");
|
||||
}
|
||||
} else {
|
||||
$login = site_url() . 'login';
|
||||
header("location: $login");
|
||||
}
|
||||
});
|
||||
|
||||
// Publish comment
|
||||
get('/admin/comments/publish/:postid/:commentid', function ($postid, $commentid) {
|
||||
if (login()) {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if ($role === 'admin' || $role === 'editor') {
|
||||
commentPublish($postid, $commentid);
|
||||
}
|
||||
}
|
||||
$redir = site_url() . 'admin/comments';
|
||||
header("location: $redir");
|
||||
});
|
||||
|
||||
// Delete comment
|
||||
get('/admin/comments/delete/:postid/:commentid', function ($postid, $commentid) {
|
||||
if (login()) {
|
||||
$user = $_SESSION[site_url()]['user'];
|
||||
$role = user('role', $user);
|
||||
if ($role === 'admin' || $role === 'editor') {
|
||||
commentDelete($postid, $commentid);
|
||||
}
|
||||
}
|
||||
$redir = site_url() . 'admin/comments';
|
||||
header("location: $redir");
|
||||
});
|
||||
|
||||
// Show admin/field
|
||||
|
|
@ -5790,6 +6038,46 @@ post('/:year/:month/:name/delete', function () {
|
|||
}
|
||||
});
|
||||
|
||||
// Submit comment from public form
|
||||
post('/comments/submit', function () {
|
||||
if (!local()) {
|
||||
$redir = site_url();
|
||||
header("location: $redir");
|
||||
return;
|
||||
}
|
||||
|
||||
$postId = from($_POST, 'post_id');
|
||||
$name = from($_POST, 'name');
|
||||
$email = from($_POST, 'email');
|
||||
$comment = from($_POST, 'comment');
|
||||
$parentId = from($_POST, 'parent_id');
|
||||
$notify = from($_POST, 'notify');
|
||||
$website = from($_POST, 'website'); // honeypot field
|
||||
|
||||
$data = array(
|
||||
'name' => $name,
|
||||
'email' => $email,
|
||||
'comment' => $comment,
|
||||
'parent_id' => $parentId,
|
||||
'notify' => $notify,
|
||||
'website' => $website
|
||||
);
|
||||
|
||||
$result = commentInsert($postId, $data);
|
||||
|
||||
if ($result['success']) {
|
||||
// Redirect back to post with success anchor
|
||||
$redir = site_url() . $postId . '#comment-success';
|
||||
// $redir = site_url() . $postId . '#comment-' . $result['comment_id'];
|
||||
} else {
|
||||
// Redirect back to post with error
|
||||
$redir = site_url() . $postId . '#comment-error';
|
||||
// $redir = site_url() . $postId . '#comment-error?' . $result['message'];
|
||||
}
|
||||
|
||||
header("location: $redir");
|
||||
});
|
||||
|
||||
// If we get here, it means that
|
||||
// nothing has been matched above
|
||||
get('.*', function () {
|
||||
|
|
|
|||
263
system/includes/comments-frontend.php
Normal file
263
system/includes/comments-frontend.php
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
<?php
|
||||
if (!defined('HTMLY')) die('HTMLy');
|
||||
|
||||
/**
|
||||
* Display comments form
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param string $parentId Parent comment ID for replies (optional)
|
||||
* @return void
|
||||
*/
|
||||
function displayCommentsForm($postId, $parentId = null)
|
||||
{
|
||||
if (!local()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$formId = $parentId ? 'reply-form-' . $parentId : 'comment-form';
|
||||
$submitUrl = site_url() . 'comments/submit';
|
||||
?>
|
||||
<form id="<?php echo $formId; ?>" method="POST" action="<?php echo $submitUrl; ?>" class="comment-form">
|
||||
<input type="hidden" name="post_id" value="<?php echo _h($postId); ?>">
|
||||
<?php if ($parentId): ?>
|
||||
<input type="hidden" name="parent_id" value="<?php echo _h($parentId); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Honeypot field (hidden from users) -->
|
||||
<div style="position:absolute;left:-5000px;" aria-hidden="true">
|
||||
<input type="text" name="website" tabindex="-1" value="" autocomplete="off">
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" style="width: 100%">
|
||||
<label for="name-<?php echo $formId; ?>"><?php echo i18n('Name'); ?> <span class="required">*</span></label>
|
||||
<input type="text" class="form-control" id="name-<?php echo $formId; ?>" name="name" required>
|
||||
|
||||
<label for="email-<?php echo $formId; ?>"><?php echo i18n('Email'); ?> <span class="required">*</span></label>
|
||||
<input type="email" class="form-control" id="email-<?php echo $formId; ?>" name="email" required>
|
||||
<br><small class="form-text text-muted"><?php echo i18n('Email_not_published'); ?></small>
|
||||
</div>
|
||||
<br clear="all">
|
||||
<div class="form-group">
|
||||
<label for="comment-<?php echo $formId; ?>"><?php echo i18n('Comment'); ?> <span class="required">*</span></label>
|
||||
<textarea class="form-control" id="comment-<?php echo $formId; ?>" name="comment" rows="5" required></textarea>
|
||||
<small class="form-text text-muted"><?php echo i18n('Comment_formatting_help'); ?></small>
|
||||
</div>
|
||||
<!-- Emidio 20251105 - temporarily disabled
|
||||
<div class="form-group form-check">
|
||||
<input type="checkbox" class="form-check-input" id="notify-<?php echo $formId; ?>" name="notify" value="1">
|
||||
<label class="form-check-label" for="notify-<?php echo $formId; ?>">
|
||||
<?php echo i18n('Notify_new_comments'); ?>
|
||||
</label>
|
||||
</div>
|
||||
-->
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary submit-comment"><?php echo $parentId ? i18n('Post_Reply') : i18n('Post_Comment'); ?></button>
|
||||
<?php if ($parentId): ?>
|
||||
<button type="button" class="btn btn-secondary cancel-reply" onclick="cancelReply('<?php echo $parentId; ?>')"><?php echo i18n('Cancel'); ?></button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display single comment
|
||||
*
|
||||
* @param array $comment Comment data
|
||||
* @param string $postId Post ID
|
||||
* @return void
|
||||
*/
|
||||
function displayComment($comment, $postId)
|
||||
{
|
||||
$indent = isset($comment['level']) ? $comment['level'] : 0;
|
||||
$marginLeft = $indent * 0; // 40px per level - changed to 0 Emidio 20251106
|
||||
|
||||
// Add visual depth indicator
|
||||
$depthClass = 'comment-level-' . min($indent, 5); // Max 5 for styling
|
||||
$borderColor = $indent > 0 ? '#ddd' : '#007bff';
|
||||
?>
|
||||
<div id="comment-<?php echo $comment['id']; ?>" class="comment-item <?php echo $depthClass; ?>"
|
||||
style="margin-left: <?php echo $marginLeft; ?>px; border-left: 3px solid <?php echo $borderColor; ?>;"
|
||||
data-level="<?php echo $indent; ?>">
|
||||
<div class="comment-header">
|
||||
<strong class="comment-author"><?php echo _h($comment['name']); ?></strong>
|
||||
<span class="comment-date"><?php echo format_date($comment['timestamp']); ?></span>
|
||||
<!---
|
||||
<?php if ($indent > 0): ?>
|
||||
<span class="comment-level-badge"><?php echo i18n('Level'); ?> <?php echo $indent; ?></span>
|
||||
<?php endif; ?>
|
||||
--->
|
||||
</div>
|
||||
<div class="comment-body">
|
||||
<?php echo formatCommentText($comment['comment']); ?>
|
||||
</div>
|
||||
<div class="comment-footer">
|
||||
<button class="btn btn-sm btn-link reply-button" onclick="showReplyForm('<?php echo $comment['id']; ?>', '<?php echo $postId; ?>')">
|
||||
<i class="fa fa-reply"></i> <?php echo i18n('Reply'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<div id="reply-container-<?php echo $comment['id']; ?>" class="reply-container" style="display:none; margin-top:15px;">
|
||||
<!-- Reply form will be inserted here via JavaScript -->
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Display child comments (recursive - unlimited depth)
|
||||
if (!empty($comment['children'])) {
|
||||
echo '<div class="comment-children">';
|
||||
foreach ($comment['children'] as $child) {
|
||||
displayComment($child, $postId);
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display all comments for a post
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @return void
|
||||
*/
|
||||
function displayComments($postId)
|
||||
{
|
||||
if (!local()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$comments = getComments($postId);
|
||||
|
||||
if (empty($comments)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build comment tree
|
||||
$commentTree = buildCommentTree($comments);
|
||||
|
||||
?>
|
||||
<div class="comments-list">
|
||||
<!--- <h4><?php echo i18n('Comments'); ?> (<?php echo count($comments); ?>)</h4> --->
|
||||
<?php
|
||||
foreach ($commentTree as $comment) {
|
||||
displayComment($comment, $postId);
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Display complete comments section (list + form)
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @return void
|
||||
*/
|
||||
function displayCommentsSection($postId)
|
||||
{
|
||||
if (!local()) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<section class="comments comment-box" id="comments">
|
||||
<!---
|
||||
<div class="comments-number">
|
||||
<h3><?php echo i18n("Comments"); ?></h3>
|
||||
</div>
|
||||
--->
|
||||
|
||||
<?php
|
||||
// Show success/error messages
|
||||
$hash = isset($_SERVER['REQUEST_URI']) ? parse_url($_SERVER['REQUEST_URI'], PHP_URL_FRAGMENT) : '';
|
||||
if ($hash === 'comment-success'):
|
||||
?>
|
||||
<div class="alert alert-success">
|
||||
<?php
|
||||
if (comments_config('comments.moderation') === 'true') {
|
||||
echo i18n('Comment_submitted_moderation');
|
||||
} else {
|
||||
echo i18n('Comment_submitted_success');
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php elseif ($hash === 'comment-error'): ?>
|
||||
<div class="alert alert-danger">
|
||||
<?php echo i18n('Comment_submission_error'); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php displayComments($postId); ?>
|
||||
|
||||
<div class="comment-form-section">
|
||||
<h4><?php echo i18n('Leave_a_comment'); ?></h4>
|
||||
<?php displayCommentsForm($postId); ?>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
function showReplyForm(commentId, postId) {
|
||||
// Hide all other reply forms
|
||||
document.querySelectorAll('.reply-container').forEach(function(el) {
|
||||
el.style.display = 'none';
|
||||
el.innerHTML = '';
|
||||
});
|
||||
|
||||
// Show this reply form
|
||||
var container = document.getElementById('reply-container-' + commentId);
|
||||
if (container) {
|
||||
container.style.display = 'block';
|
||||
|
||||
// Build form HTML
|
||||
var submitUrl = '<?php echo site_url(); ?>comments/submit';
|
||||
var formId = 'reply-form-' + commentId;
|
||||
|
||||
var formHtml = '<form id="' + formId + '" method="POST" action="' + submitUrl + '" class="comment-form">' +
|
||||
'<input type="hidden" name="post_id" value="' + postId + '">' +
|
||||
'<input type="hidden" name="parent_id" value="' + commentId + '">' +
|
||||
'<div style="position:absolute;left:-5000px;" aria-hidden="true">' +
|
||||
'<input type="text" name="website" tabindex="-1" value="" autocomplete="off">' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
'<label for="name-' + formId + '"><?php echo i18n("Name"); ?> <span class="required">*</span></label>' +
|
||||
'<input type="text" class="form-control" id="name-' + formId + '" name="name" required>' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
'<label for="email-' + formId + '"><?php echo i18n("Email"); ?> <span class="required">*</span></label>' +
|
||||
'<input type="email" class="form-control" id="email-' + formId + '" name="email" required>' +
|
||||
'<small class="form-text text-muted"><?php echo i18n("Email_not_published"); ?></small>' +
|
||||
'</div>' +
|
||||
'<div class="form-group">' +
|
||||
'<label for="comment-' + formId + '"><?php echo i18n("Comment"); ?> <span class="required">*</span></label>' +
|
||||
'<textarea class="form-control" id="comment-' + formId + '" name="comment" rows="5" required></textarea>' +
|
||||
'<small class="form-text text-muted"><?php echo i18n("Comment_formatting_help"); ?></small>' +
|
||||
'</div>' +
|
||||
'<!-- Emidio 20251105 - temporarily disabled ' +
|
||||
'<div class="form-group form-check">' +
|
||||
'<input type="checkbox" class="form-check-input" id="notify-' + formId + '" name="notify" value="1">' +
|
||||
'<label class="form-check-label" for="notify-' + formId + '"><?php echo i18n("Notify_new_comments"); ?></label>' +
|
||||
'</div>' +
|
||||
' -->' +
|
||||
'<br><div class="form-group">' +
|
||||
'<button type="submit" class="btn btn-primary submit-reply"><?php echo i18n("Post_Reply"); ?></button> ' +
|
||||
'<button type="button" class="btn btn-secondary cancel-reply" onclick="cancelReply(\'' + commentId + '\')"><?php echo i18n("Cancel"); ?></button>' +
|
||||
'</div>' +
|
||||
'</form>';
|
||||
|
||||
container.innerHTML = formHtml;
|
||||
}
|
||||
}
|
||||
|
||||
function cancelReply(commentId) {
|
||||
var container = document.getElementById('reply-container-' + commentId);
|
||||
if (container) {
|
||||
container.style.display = 'none';
|
||||
container.innerHTML = '';
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
643
system/includes/comments.php
Normal file
643
system/includes/comments.php
Normal file
|
|
@ -0,0 +1,643 @@
|
|||
<?php
|
||||
if (!defined('HTMLY')) die('HTMLy');
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
|
||||
/**
|
||||
* Check if local comments system is enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function local()
|
||||
{
|
||||
return config('comment.system') === 'local';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments configuration value
|
||||
*
|
||||
* @param string $key Configuration key (use 'reload' to force cache reload)
|
||||
* @return mixed Configuration value or null
|
||||
*/
|
||||
function comments_config($key)
|
||||
{
|
||||
static $_config = array();
|
||||
|
||||
$config_file = 'config/comments.ini';
|
||||
|
||||
// Allow cache reload
|
||||
if ($key === 'reload') {
|
||||
$_config = array();
|
||||
return null;
|
||||
}
|
||||
|
||||
if (empty($_config) && file_exists($config_file)) {
|
||||
$_config = parse_ini_file($config_file, false);
|
||||
}
|
||||
|
||||
return isset($_config[$key]) ? $_config[$key] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save comments configuration
|
||||
*
|
||||
* @param array $data Configuration data to save
|
||||
* @return bool Success status
|
||||
*/
|
||||
function save_comments_config($data = array())
|
||||
{
|
||||
$config_file = 'config/comments.ini';
|
||||
|
||||
if (!file_exists($config_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$string = file_get_contents($config_file);
|
||||
|
||||
foreach ($data as $word => $value) {
|
||||
// Ensure null and empty values are saved as empty strings
|
||||
if ($value === null || $value === '') {
|
||||
$value = '""';
|
||||
} else {
|
||||
// Encode value
|
||||
$value = json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$map = array('\r\n' => ' \n ', '\r' => ' \n ');
|
||||
$value = trim(strtr($value, $map));
|
||||
|
||||
// Escape dots in the key for regex
|
||||
$escapedWord = str_replace('.', '\.', $word);
|
||||
|
||||
// Try to replace existing line
|
||||
$pattern = "/^" . $escapedWord . " = .*/m";
|
||||
if (preg_match($pattern, $string)) {
|
||||
$string = preg_replace($pattern, $word . ' = ' . $value, $string);
|
||||
} else {
|
||||
// If line doesn't exist, add it at the end
|
||||
$string = rtrim($string) . "\n" . $word . ' = ' . $value . "\n";
|
||||
}
|
||||
}
|
||||
|
||||
$string = rtrim($string) . "\n";
|
||||
$result = file_put_contents($config_file, $string, LOCK_EX);
|
||||
|
||||
// Clear PHP opcache for this file
|
||||
if (function_exists('opcache_invalidate')) {
|
||||
opcache_invalidate($config_file, true);
|
||||
}
|
||||
|
||||
// Clear cache after saving
|
||||
if ($result !== false) {
|
||||
comments_config('reload');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comments file path for a post/page
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @return string File path
|
||||
*/
|
||||
function get_comments_file($postId)
|
||||
{
|
||||
$dir = 'content/comments/';
|
||||
if (!is_dir($dir)) {
|
||||
mkdir($dir, 0775, true);
|
||||
}
|
||||
return $dir . sanitize_filename($postId) . '.json';
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize filename
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string Sanitized filename
|
||||
*/
|
||||
function sanitize_filename($filename)
|
||||
{
|
||||
return preg_replace('/[^a-z0-9\-_]/i', '_', $filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all comments for a post/page
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param bool $includeUnpublished Include unpublished comments (for admin)
|
||||
* @return array Comments array
|
||||
*/
|
||||
function getComments($postId, $includeUnpublished = false)
|
||||
{
|
||||
$file = get_comments_file($postId);
|
||||
|
||||
if (!file_exists($file)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
$comments = json_decode($content, true);
|
||||
|
||||
if (!is_array($comments)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Filter unpublished comments if not admin view
|
||||
if (!$includeUnpublished) {
|
||||
$comments = array_filter($comments, function($comment) {
|
||||
return isset($comment['published']) && $comment['published'] === true;
|
||||
});
|
||||
}
|
||||
|
||||
// Sort by date (oldest first)
|
||||
usort($comments, function($a, $b) {
|
||||
return $a['timestamp'] - $b['timestamp'];
|
||||
});
|
||||
|
||||
return $comments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all comments across all posts (for admin)
|
||||
*
|
||||
* @return array All comments with post info
|
||||
*/
|
||||
function getAllComments()
|
||||
{
|
||||
$commentsDir = 'content/comments/';
|
||||
if (!is_dir($commentsDir)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$files = glob($commentsDir . '*.json');
|
||||
$allComments = array();
|
||||
|
||||
foreach ($files as $file) {
|
||||
$postId = basename($file, '.json');
|
||||
$comments = getComments($postId, true);
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
$comment['post_id'] = $postId;
|
||||
$allComments[] = $comment;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort by date (newest first)
|
||||
usort($allComments, function($a, $b) {
|
||||
return $b['timestamp'] - $a['timestamp'];
|
||||
});
|
||||
|
||||
return $allComments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique comment ID
|
||||
*
|
||||
* @return string Unique comment ID
|
||||
*/
|
||||
function generateCommentId()
|
||||
{
|
||||
return uniqid('comment_', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build comment tree for nested display
|
||||
*
|
||||
* @param array $comments Flat array of comments
|
||||
* @param string $parentId Parent comment ID (null for root)
|
||||
* @param int $level Nesting level
|
||||
* @return array Tree structure
|
||||
*/
|
||||
function buildCommentTree($comments, $parentId = null, $level = 0)
|
||||
{
|
||||
$tree = array();
|
||||
|
||||
foreach ($comments as $comment) {
|
||||
$commentParent = isset($comment['parent_id']) ? $comment['parent_id'] : null;
|
||||
|
||||
if ($commentParent === $parentId) {
|
||||
$comment['level'] = $level;
|
||||
$comment['children'] = buildCommentTree($comments, $comment['id'], $level + 1);
|
||||
$tree[] = $comment;
|
||||
}
|
||||
}
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate comment data
|
||||
*
|
||||
* @param array $data Comment data
|
||||
* @return array Array with 'valid' boolean and 'errors' array
|
||||
*/
|
||||
function validateComment($data)
|
||||
{
|
||||
$errors = array();
|
||||
|
||||
// Validate name
|
||||
if (empty($data['name']) || strlen(trim($data['name'])) < 2) {
|
||||
$errors[] = 'Name is required and must be at least 2 characters';
|
||||
}
|
||||
|
||||
// Validate email
|
||||
if (empty($data['email']) || !filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$errors[] = 'Valid email is required';
|
||||
}
|
||||
|
||||
// Validate comment text
|
||||
if (empty($data['comment']) || strlen(trim($data['comment'])) < 3) {
|
||||
$errors[] = 'Comment is required and must be at least 3 characters';
|
||||
}
|
||||
|
||||
// Validate honeypot (if enabled)
|
||||
if (comments_config('comments.honeypot') === 'true') {
|
||||
if (!empty($data['website'])) {
|
||||
$errors[] = 'Spam detected';
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'valid' => empty($errors),
|
||||
'errors' => $errors
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a new comment
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param array $data Comment data (name, email, comment, parent_id, notify)
|
||||
* @return array Result with 'success' boolean and 'message' or 'comment_id'
|
||||
*/
|
||||
function commentInsert($postId, $data)
|
||||
{
|
||||
// Validate comment
|
||||
$validation = validateComment($data);
|
||||
if (!$validation['valid']) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => implode(', ', $validation['errors'])
|
||||
);
|
||||
}
|
||||
|
||||
// Get existing comments
|
||||
$file = get_comments_file($postId);
|
||||
$comments = array();
|
||||
if (file_exists($file)) {
|
||||
$content = file_get_contents($file);
|
||||
$comments = json_decode($content, true);
|
||||
if (!is_array($comments)) {
|
||||
$comments = array();
|
||||
}
|
||||
}
|
||||
|
||||
// Create new comment
|
||||
$commentId = generateCommentId();
|
||||
$timestamp = time();
|
||||
|
||||
$comment = array(
|
||||
'id' => $commentId,
|
||||
'name' => trim($data['name']),
|
||||
'email' => trim($data['email']),
|
||||
'comment' => trim($data['comment']),
|
||||
'timestamp' => $timestamp,
|
||||
'date' => date('Y-m-d H:i:s', $timestamp),
|
||||
'parent_id' => isset($data['parent_id']) && !empty($data['parent_id']) ? $data['parent_id'] : null,
|
||||
'notify' => isset($data['notify']) && $data['notify'] === '1',
|
||||
'published' => comments_config('comments.moderation') !== 'true', // Auto-publish if moderation disabled
|
||||
'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown'
|
||||
);
|
||||
|
||||
// Add comment to array
|
||||
$comments[] = $comment;
|
||||
|
||||
// Save to file
|
||||
$json = json_encode($comments, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
if (file_put_contents($file, $json, LOCK_EX) === false) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'message' => 'Failed to save comment'
|
||||
);
|
||||
}
|
||||
|
||||
// Send notifications
|
||||
sendCommentNotifications($postId, $comment, $comments);
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'comment_id' => $commentId,
|
||||
'message' => $comment['published'] ? 'Comment published successfully' : 'Comment submitted for moderation'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish a comment (approve from moderation)
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param string $commentId Comment ID
|
||||
* @return bool Success status
|
||||
*/
|
||||
function commentPublish($postId, $commentId)
|
||||
{
|
||||
$file = get_comments_file($postId);
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
$comments = json_decode($content, true);
|
||||
|
||||
if (!is_array($comments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updated = false;
|
||||
foreach ($comments as &$comment) {
|
||||
if ($comment['id'] === $commentId) {
|
||||
$comment['published'] = true;
|
||||
$updated = true;
|
||||
|
||||
// Send notifications to other commenters
|
||||
sendCommentNotifications($postId, $comment, $comments, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$updated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$json = json_encode($comments, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
return file_put_contents($file, $json, LOCK_EX) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a comment
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param string $commentId Comment ID
|
||||
* @return bool Success status
|
||||
*/
|
||||
function commentDelete($postId, $commentId)
|
||||
{
|
||||
$file = get_comments_file($postId);
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
$comments = json_decode($content, true);
|
||||
|
||||
if (!is_array($comments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Remove comment and its children
|
||||
$comments = array_filter($comments, function($comment) use ($commentId) {
|
||||
return $comment['id'] !== $commentId &&
|
||||
(empty($comment['parent_id']) || $comment['parent_id'] !== $commentId);
|
||||
});
|
||||
|
||||
// Reindex array
|
||||
$comments = array_values($comments);
|
||||
|
||||
$json = json_encode($comments, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
return file_put_contents($file, $json, LOCK_EX) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify a comment
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param string $commentId Comment ID
|
||||
* @param array $data New comment data
|
||||
* @return bool Success status
|
||||
*/
|
||||
function commentModify($postId, $commentId, $data)
|
||||
{
|
||||
$file = get_comments_file($postId);
|
||||
if (!file_exists($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = file_get_contents($file);
|
||||
$comments = json_decode($content, true);
|
||||
|
||||
if (!is_array($comments)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$updated = false;
|
||||
foreach ($comments as &$comment) {
|
||||
if ($comment['id'] === $commentId) {
|
||||
// Update fields
|
||||
if (isset($data['name'])) {
|
||||
$comment['name'] = trim($data['name']);
|
||||
}
|
||||
if (isset($data['email'])) {
|
||||
$comment['email'] = trim($data['email']);
|
||||
}
|
||||
if (isset($data['comment'])) {
|
||||
$comment['comment'] = trim($data['comment']);
|
||||
}
|
||||
if (isset($data['published'])) {
|
||||
$comment['published'] = (bool)$data['published'];
|
||||
}
|
||||
|
||||
$comment['modified'] = date('Y-m-d H:i:s');
|
||||
$updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$updated) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$json = json_encode($comments, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
return file_put_contents($file, $json, LOCK_EX) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send comment notifications
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param array $newComment The new comment
|
||||
* @param array $allComments All comments for this post
|
||||
* @param bool $notifyAdmin Notify admin (default true)
|
||||
* @return void
|
||||
*/
|
||||
function sendCommentNotifications($postId, $newComment, $allComments, $notifyAdmin = true)
|
||||
{
|
||||
// Check if notifications are enabled
|
||||
if (comments_config('comments.notify') !== 'true' ||
|
||||
comments_config('comments.mail.enabled') !== 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
$recipients = array();
|
||||
|
||||
// Add admin email
|
||||
if ($notifyAdmin) {
|
||||
$adminEmail = comments_config('comments.admin.email');
|
||||
if (!empty($adminEmail) && filter_var($adminEmail, FILTER_VALIDATE_EMAIL)) {
|
||||
$recipients[$adminEmail] = array(
|
||||
'name' => 'Administrator',
|
||||
'type' => 'admin'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add parent comment author (if replying)
|
||||
if (!empty($newComment['parent_id'])) {
|
||||
foreach ($allComments as $comment) {
|
||||
if ($comment['id'] === $newComment['parent_id'] &&
|
||||
$comment['notify'] &&
|
||||
$comment['email'] !== $newComment['email']) {
|
||||
$recipients[$comment['email']] = array(
|
||||
'name' => $comment['name'],
|
||||
'type' => 'parent'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add other commenters in same thread who want notifications
|
||||
foreach ($allComments as $comment) {
|
||||
if ($comment['notify'] &&
|
||||
$comment['email'] !== $newComment['email'] &&
|
||||
$comment['id'] !== $newComment['id']) {
|
||||
// Same thread = same parent or no parent
|
||||
if ($comment['parent_id'] === $newComment['parent_id']) {
|
||||
$recipients[$comment['email']] = array(
|
||||
'name' => $comment['name'],
|
||||
'type' => 'thread'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send emails
|
||||
foreach ($recipients as $email => $info) {
|
||||
sendCommentEmail($email, $info['name'], $postId, $newComment, $info['type']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a single comment notification email
|
||||
*
|
||||
* @param string $to Recipient email
|
||||
* @param string $toName Recipient name
|
||||
* @param string $postId Post ID
|
||||
* @param array $comment Comment data
|
||||
* @param string $type Notification type (admin, parent, thread)
|
||||
* @return bool Success status
|
||||
*/
|
||||
function sendCommentEmail($to, $toName, $postId, $comment, $type = 'admin')
|
||||
{
|
||||
try {
|
||||
$mail = new PHPMailer(true);
|
||||
|
||||
// Server settings
|
||||
$mail->isSMTP();
|
||||
$mail->Host = comments_config('comments.mail.host');
|
||||
$mail->SMTPAuth = true;
|
||||
$mail->Username = comments_config('comments.mail.username');
|
||||
$mail->Password = comments_config('comments.mail.password');
|
||||
$mail->Port = comments_config('comments.mail.port');
|
||||
|
||||
$encryption = comments_config('comments.mail.encryption');
|
||||
if ($encryption === 'tls') {
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
|
||||
} elseif ($encryption === 'ssl') {
|
||||
$mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
|
||||
}
|
||||
|
||||
// Recipients
|
||||
$mail->setFrom(
|
||||
comments_config('comments.mail.from.email'),
|
||||
comments_config('comments.mail.from.name')
|
||||
);
|
||||
$mail->addAddress($to, $toName);
|
||||
|
||||
// Content
|
||||
$mail->isHTML(true);
|
||||
$mail->CharSet = 'UTF-8';
|
||||
|
||||
if ($type === 'admin') {
|
||||
$mail->Subject = 'New comment awaiting moderation';
|
||||
$mail->Body = "
|
||||
<h3>New comment on: $postId</h3>
|
||||
<p><strong>From:</strong> {$comment['name']} ({$comment['email']})</p>
|
||||
<p><strong>Comment:</strong></p>
|
||||
<p>" . nl2br(htmlspecialchars($comment['comment'])) . "</p>
|
||||
<p><a href='" . site_url() . "admin/comments'>Moderate comments</a></p>
|
||||
";
|
||||
} else {
|
||||
$mail->Subject = 'New reply to your comment';
|
||||
$mail->Body = "
|
||||
<h3>Someone replied to your comment on: $postId</h3>
|
||||
<p><strong>From:</strong> {$comment['name']}</p>
|
||||
<p><strong>Comment:</strong></p>
|
||||
<p>" . nl2br(htmlspecialchars($comment['comment'])) . "</p>
|
||||
<p><a href='" . site_url() . "$postId#comment-{$comment['id']}'>View comment</a></p>
|
||||
";
|
||||
}
|
||||
|
||||
$mail->send();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log("Comment notification email failed: {$mail->ErrorInfo}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comment count for a post
|
||||
*
|
||||
* @param string $postId Post or page ID
|
||||
* @param bool $includeUnpublished Include unpublished comments
|
||||
* @return int Comment count
|
||||
*/
|
||||
function getCommentCount($postId, $includeUnpublished = false)
|
||||
{
|
||||
$comments = getComments($postId, $includeUnpublished);
|
||||
return count($comments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pending comments count (for admin)
|
||||
*
|
||||
* @return int Pending comments count
|
||||
*/
|
||||
function getPendingCommentsCount()
|
||||
{
|
||||
$allComments = getAllComments();
|
||||
$pending = array_filter($allComments, function($comment) {
|
||||
return !$comment['published'];
|
||||
});
|
||||
return count($pending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format comment text (allow basic formatting)
|
||||
*
|
||||
* @param string $text Comment text
|
||||
* @return string Formatted text
|
||||
*/
|
||||
function formatCommentText($text)
|
||||
{
|
||||
// Convert line breaks
|
||||
$text = nl2br(htmlspecialchars($text, ENT_QUOTES, 'UTF-8'));
|
||||
|
||||
// Allow simple bold with **text** or __text__
|
||||
$text = preg_replace('/\*\*(.+?)\*\*/', '<strong>$1</strong>', $text);
|
||||
$text = preg_replace('/__(.+?)__/', '<strong>$1</strong>', $text);
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -3535,7 +3535,7 @@ function is_index()
|
|||
}
|
||||
} else {
|
||||
$req = strtok($_SERVER["REQUEST_URI"], '?');
|
||||
if (stripos($req, '/category/') !== false || stripos($req, '/archive/') !== false || stripos($req, '/tag/') !== false || stripos($req, '/search/') !== false || stripos($req, '/type/') !== false || stripos($req, '/' . blog_path()) !== false || $req == site_path() . '/') {
|
||||
if (stripos($req, '/category/') !== false || stripos($req, '/archive/') !== false || stripos($req, '/tag/') !== false || stripos($req, '/search/') !== false || stripos($req, '/type/') !== false || stripos($req, '/' . blog_path()) !== false || $req == site_path() . '/' || $req == '/') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
|
|
|||
2
system/vendor/composer/autoload_files.php
vendored
2
system/vendor/composer/autoload_files.php
vendored
|
|
@ -12,4 +12,6 @@ return array(
|
|||
'8432047aca7938f88a2098a2f7770228' => $baseDir . '/system/admin/admin.php',
|
||||
'1b9bf2d9d029f1364c3d7262b5375c41' => $baseDir . '/system/includes/session.php',
|
||||
'62f038defb1b29aab3998eb437e01df9' => $baseDir . '/system/includes/opml.php',
|
||||
'7d7ae14f7bb933ac50b7f6e42f6a7d60' => $baseDir . '/system/includes/comments.php',
|
||||
'2591226a04118e81824e40ae6712427b' => $baseDir . '/system/includes/comments-frontend.php',
|
||||
);
|
||||
|
|
|
|||
2
system/vendor/composer/autoload_static.php
vendored
2
system/vendor/composer/autoload_static.php
vendored
|
|
@ -13,6 +13,8 @@ class ComposerStaticInitd88c6c25320034df85dd42f1462fbda7
|
|||
'8432047aca7938f88a2098a2f7770228' => __DIR__ . '/../../..' . '/system/admin/admin.php',
|
||||
'1b9bf2d9d029f1364c3d7262b5375c41' => __DIR__ . '/../../..' . '/system/includes/session.php',
|
||||
'62f038defb1b29aab3998eb437e01df9' => __DIR__ . '/../../..' . '/system/includes/opml.php',
|
||||
'7d7ae14f7bb933ac50b7f6e42f6a7d60' => __DIR__ . '/../../..' . '/system/includes/comments.php',
|
||||
'2591226a04118e81824e40ae6712427b' => __DIR__ . '/../../..' . '/system/includes/comments-frontend.php',
|
||||
);
|
||||
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue