WhatsApp social and minor fixes

This commit is contained in:
Emidio Reggiani 2026-03-23 16:31:00 +01:00
commit cc0538c401
12 changed files with 50 additions and 339 deletions

View file

@ -266,6 +266,12 @@
<input type="text" name="-config-social.youtube" class="form-control" id="social.youtube" value="<?php echo config('social.youtube');?>" placeholder="https://www.youtube.com/user/username">
</div>
</div>
<div class="form-group row">
<label for="social.whatsapp" class="col-sm-2 col-form-label">WhatsApp</label>
<div class="col-sm-10">
<input type="text" name="-config-social.whatsapp" class="form-control" id="social.whatsapp" value="<?php echo config('social.whatsapp');?>" placeholder="https://whatsapp.com/channel/id or https://wa.me/number">
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-primary"><?php echo i18n('Save_Config');?></button>

View file

@ -1,336 +0,0 @@
<?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($url, $mdfile = null, $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="url" value="<?php echo _h($url); ?>">
<?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>
<!-- JS check & time check field (hidden from users) -->
<div style="position:absolute;left:-6000px;" aria-hidden="true">
<input type="text" name="company" tabindex="-2" 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>
<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 ltrim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'); ?>')">
<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($url, $file = null)
{
if (!local()) {
return;
}
$comments = getComments($url, $file = null);
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, $url, $file = null);
}
?>
</div>
<?php
}
/**
* Display complete comments section (list + form)
*
* @param string $postId Post or page ID
* @return void
* type can be post, author, page, subpage (same a view variable)
*/
function displayCommentsSection($url, $file = null)
{
if (!local()) {
return;
}
$urlpath = ltrim(parse_url($url, PHP_URL_PATH), '/');
?>
<section class="comments comment-box" id="comments">
<!---
<div class="comments-number">
<h3><?php echo i18n("Comments"); ?></h3>
</div>
--->
<div class="comment-alert-status" id="comment-alert-status" style="display:none;">
</div>
<?php displayComments($urlpath, $file = null); ?>
<div class="comment-form-section">
<h4><?php echo i18n('Leave_a_comment'); ?></h4>
<?php displayCommentsForm($urlpath, $file = null); ?>
</div>
</section>
<script type="text/javascript">
function showReplyForm(commentId, commentUrl) {
// 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="url" value="' + commentUrl + '">' +
'<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 style="position:absolute;left:-6000px;" aria-hidden="true">' +
'<input type="text" name="company" tabindex="-2" 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>' +
'<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;
// Populate antispam company field with current timestamp
const timestampSeconds = Math.floor(Date.now() / 1000);
const companyField = container.querySelector('[name="company"]');
if (companyField) {
companyField.value = timestampSeconds;
}
}
}
function cancelReply(commentId) {
var container = document.getElementById('reply-container-' + commentId);
if (container) {
container.style.display = 'none';
container.innerHTML = '';
}
}
function handleCommentStatus() {
// Setting messages
const messages = {
comment_submission_success: "<?php echo i18n('comment_submission_success'); ?>",
comment_submission_moderation: "<?php echo i18n('comment_submission_moderation'); ?>",
comment_submission_error: "<?php echo i18n('comment_submission_error'); ?>",
comment_submission_error_shortname: "<?php echo i18n('comment_submission_error_shortname'); ?>",
comment_submission_error_email: "<?php echo i18n('comment_submission_error_email'); ?>",
comment_submission_error_short: "<?php echo i18n('comment_submission_error_short'); ?>",
comment_submission_error_spam: "<?php echo i18n('comment_submission_error_spam'); ?>"
};
// Get the hash in the URL
const hash = window.location.hash;
// Check if there's #comment-status
if (hash.startsWith('#comment-status')) {
// Get the part after +
const parts = hash.split('+');
if (parts.length > 1) {
const statusKey = parts[1];
const alertDiv = document.querySelector('.comment-alert-status');
if (alertDiv && messages[statusKey]) {
// Set message to display
alertDiv.textContent = messages[statusKey];
// Set div colors (classes) based on message type
if (statusKey.includes('error')) {
alertDiv.className = 'comment-alert-status comment-alert-status-error'
} else if (statusKey.includes('success')) {
alertDiv.className = 'comment-alert-status comment-alert-status-success'
} else if (statusKey.includes('moderation')) {
alertDiv.className = 'comment-alert-status comment-alert-status-warning'
}
// Showing status message div
alertDiv.style.display = 'block';
// Scroll to status message
document.getElementById('comments').scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
}
}
// Antispam protection, executed when page is loaded
document.addEventListener('DOMContentLoaded', function () {
const timestampSeconds = Math.floor(Date.now() / 1000);
// Select all forms in page
document.querySelectorAll('form').forEach(function (form) {
// Finds all fields named "company"
form.querySelectorAll('[name="company"]').forEach(function (field) {
field.value = timestampSeconds;
});
});
});
// Executed when page is loaded
document.addEventListener('DOMContentLoaded', handleCommentStatus);
// Executed also when page hash changes (navigating in same page)
window.addEventListener('hashchange', handleCommentStatus);
</script>
<?php
}
?>

View file

@ -11,7 +11,7 @@ Some major fixes to comment system:
* added subscription verification system
## 2026-03-22
Reworked functions to match HTMLy coding style, changed local() to comments. Comment system has been integrated in existing themes (some css to adapt to the theme layout added), and added a system messages function (to give messages during subsciption/unsubscription process) - it can be used for other integrations.
Reworked functions to match HTMLy coding style, changed local() to comments. Comment system has been integrated in existing themes (some css to adapt to the theme layout added), and added a system messages function (to give messages during subsciption/unsubscription processes) - it can be used for other widgets and functionalites integration.
Also, comments configuration is now in config.ini.
@ -29,4 +29,3 @@ Users can ask for email notification when a new comment is published in a subscr
Notification email are sent on comment publish (if validation is enabled) or comment insert (if moderation is disabled, not recommended).
**TODO**: limit comment insert by time from same IP address

View file

@ -2513,6 +2513,7 @@ function social($class = null)
$youtube = config('social.youtube');
$mastodon = config('social.mastodon');
$tiktok = config('social.tiktok');
$whatsapp = config('social.whatsapp');
$rss = site_url() . 'feed/rss';
$social = '';
@ -2553,6 +2554,10 @@ function social($class = null)
$social .= '<a class="social-logo-tiktok" href="' . $tiktok . '" target="_blank" rel="nofollow"><span class="screen-reader-text">TikTok</span></a>';
}
if (!empty($whatsapp)) {
$social .= '<a class="social-logo-whatsapp" href="' . $whatsapp . '" target="_blank" rel="nofollow"><span class="screen-reader-text">WhatsApp</span></a>';
}
$social .= '<a class="social-logo-feed" href="' . $rss . '" target="_blank"><span class="screen-reader-text">RSS</span></a>';
$social .= '</div>';
return $social;

View file

@ -3581,6 +3581,7 @@ body.dark .social-logo a:hover, .dark .toc-wrapper a:hover {
.list-unstyled li {
margin: 0;
}
/*--------------------------------------------------------------
## - CSS comments
--------------------------------------------------------------*/

View file

@ -1040,6 +1040,7 @@ ul.archivegroup {
border: none;
}
/*--------------------------------------------------------------
## - CSS comments
--------------------------------------------------------------*/

View file

@ -148,6 +148,7 @@
.recent-posts > ul {
padding-left: 15px;
}
/*--------------------------------------------------------------
## - CSS comments
--------------------------------------------------------------*/

View file

@ -6168,6 +6168,7 @@ ul.month {
width:35px;
}
/*--------------------------------------------------------------
## - CSS comments
--------------------------------------------------------------*/

View file

@ -65,11 +65,19 @@
</aside>
<?php endif;?>
<?php if (disqus() || comments()): ?>
<?php if (disqus()): ?>
<aside class="widget widget_meta">
<h2 class="widget-title">Recent comments</h2>
<script src="//<?php echo config('disqus.shortname');?>.disqus.com/recent_comments_widget.js?num_items=5&amp;hide_avatars=0&amp;avatar_size=48&amp;excerpt_length=200&amp;hide_mods=0" type="text/javascript"></script><style>li.dsq-widget-item {padding-top:15px;} img.dsq-widget-avatar {margin-right:5px;}</style>
</aside>
<?php endif;?>
<?php if (comments()): ?>
<aside class="widget widget_meta">
<h2 class="widget-title">Recent comments</h2>
<?php echo last_comments(3); ?>
</aside>
<?php endif;?>
<?php endif;?>
<?php if (theme_config('archive')):?>

View file

@ -4093,6 +4093,7 @@ ul.month {
.social-logo a:before {
line-height: 33px!important;
}
/*--------------------------------------------------------------
## - CSS comments
--------------------------------------------------------------*/

View file

@ -50,6 +50,16 @@
<div id="primary" class="content-area">
<main id="main" class="site-main" role="main">
<!--//sysmessages div-->
<div class="main" id="messages-div">
<div class="section-inner message-alert">
<div class="content">
<div id="messages-text">&nbsp;</div>
</div>
</div>
</div>
<?php echo content();?>
</main><!-- .site-main -->
</div><!-- .content-area -->
@ -85,11 +95,19 @@
</section>
<?php endif;?>
<?php if (disqus() || comments()): ?>
<?php if (disqus()): ?>
<section id="recent-comments" class="widget widget_recent_comments">
<h2 class="widget-title"><?php echo i18n('Comments');?></h2>
<script src="//<?php echo config('disqus.shortname');?>.disqus.com/recent_comments_widget.js?num_items=5&amp;hide_avatars=0&amp;avatar_size=48&amp;excerpt_length=200&amp;hide_mods=0" type="text/javascript"></script><style>li.dsq-widget-item {padding-top:15px;} img.dsq-widget-avatar {margin-right:5px;} .dsq-widget-list {margin-left:0;}</style>
</section>
<?php endif;?>
<?php if (comments()): ?>
<section id="recent-comments" class="widget widget_recent_comments">
<h2 class="widget-title"><?php echo i18n('Comments');?></h2>
<?php echo last_comments(3); ?>
</section>
<?php endif;?>
<?php endif;?>
<?php if(theme_config('archive')):?>
@ -150,6 +168,8 @@
/* ]]> */
</script>
<script type="text/javascript" src="<?php echo theme_path();?>js/functions.js"></script>
<script type="text/javascript" src="<?php echo site_url();?>system/resources/js/sysmessages.js" data-base="<?php echo site_url(); ?>"></script>
<?php if (analytics()): ?><?php echo analytics() ?><?php endif; ?>
</body>
</html>

View file

@ -79,7 +79,7 @@
<?php echo disqus_count() ?>
<?php endif; ?>
<?php if (facebook() || disqus()): ?>
<?php if (facebook() || disqus() || comments()): ?>
<div class="comments-area" id="comments">
<h2 class="comments-title"><?php echo i18n('Comments');?> “<?php echo $p->title;?>”</h2>
@ -92,6 +92,10 @@
<div id="disqus_thread"></div>
<?php endif; ?>
<?php if (comments()): ?>
<?php comments($p); ?>
<?php endif; ?>
</div>
<?php endif; ?>