Update on 2022-11-17#
Today I found that the comment functionality on the blog suddenly stopped working, and it turned out to be an issue with version updates. Previously, I was using the latest waline code, but now I have switched to using a fixed version of the waline code.
In the themes/maupassant/layout/_partial/comments.pug
file, modify the following line of code:
This line of code:
script(src='//unpkg.com/@waline/client@v2/dist/waline.js')
Replace it with:
script(src='//unpkg.com/@waline/[email protected]/dist/waline.js')
Prerequisites#
- A server with a Docker environment
- Familiarity with docker-compose, postgres, and caddy
Here we will use docker + waline + postgres + caddy to set up our own comment system. For detailed information, please refer to the waline official website.
Configure PostgreSQL Database#
Note: If you do not have a database, you can also use the built-in sqlite database for deployment.
First, check the official multi-database service support documentation for PostgreSQL database support. You need to create the tables and table structures first.
In https://github.com/walinejs/waline/blob/main/assets/waline.pgsql
, simply copy the content and run it in the PostgreSQL command line to create it successfully. Here I am using pgAdmin (a management tool for PostgreSQL).
If you cannot access the official website, you can also copy the content below directly into the database command line and press enter.
CREATE SEQUENCE wl_comment_seq;
CREATE TABLE wl_comment (
id int check (id > 0) NOT NULL DEFAULT NEXTVAL ('wl_comment_seq'),
user_id int DEFAULT NULL,
comment text,
insertedAt timestamp(0) without time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
ip varchar(100) DEFAULT '',
link varchar(255) DEFAULT NULL,
mail varchar(255) DEFAULT NULL,
nick varchar(255) DEFAULT NULL,
pid int DEFAULT NULL,
rid int DEFAULT NULL,
sticky boolean DEFAULT NULL,
status varchar(50) NOT NULL DEFAULT '',
"like" int DEFAULT NULL,
ua text,
url varchar(255) DEFAULT NULL,
createdAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
updatedAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ;
CREATE SEQUENCE wl_counter_seq;
CREATE TABLE wl_counter (
id int check (id > 0) NOT NULL DEFAULT NEXTVAL ('wl_counter_seq'),
time int DEFAULT NULL,
url varchar(255) NOT NULL DEFAULT '',
createdAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
updatedAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ;
CREATE SEQUENCE wl_users_seq;
CREATE TABLE wl_users (
id int check (id > 0) NOT NULL DEFAULT NEXTVAL ('wl_users_seq'),
display_name varchar(255) NOT NULL DEFAULT '',
email varchar(255) NOT NULL DEFAULT '',
password varchar(255) NOT NULL DEFAULT '',
type varchar(50) NOT NULL DEFAULT '',
label varchar(255) DEFAULT NULL,
url varchar(255) DEFAULT NULL,
avatar varchar(255) DEFAULT NULL,
github varchar(255) DEFAULT NULL,
twitter varchar(255) DEFAULT NULL,
facebook varchar(255) DEFAULT NULL,
google varchar(255) DEFAULT NULL,
weibo varchar(255) DEFAULT NULL,
qq varchar(255) DEFAULT NULL,
"2fa" varchar(32) DEFAULT NULL,
createdAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
updatedAt timestamp(0) without time zone NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) ;
The specific process for creating the tables is as follows:
Deploy Waline with Docker#
Create a new docker-compose.yml
file in an appropriate location with the following content:
# docker-compose.yml
version: '3'
services:
waline:
container_name: waline
image: lizheming/waline:latest
restart: unless-stopped
ports:
- 9015:8360 # The port number 9015 can be modified arbitrarily, as long as it does not conflict with other applications
environment:
TZ: 'Asia/Shanghai'
SITE_NAME: "Cai Xiao Niu's Blog"
SITE_URL: 'https://cirry.cn' # Website URL
SECURE_DOMAINS: 'cirry.cn' # Domain name
AUTHOR_EMAIL: '[email protected]' # Email
PG_HOST: ******.cirry.fun # Database address, please fill in your own database address
PG_PORT: 5432 # Database port, the default port for PostgreSQL is 5432
PG_DB: hexo # Database name
PG_USER: ****** # Database user, please fill in your own username
PG_PASSWORD: ****** # Database password, please fill in your own password
Configure Caddy#
Expose the waline service running on port 9015 through caddy for reverse proxy and add SSL encryption.
# Caddyfile
# Configure your own website, each person's configuration is different, please do not copy directly
https://waline.cirry.cn:66666 {
reverse_proxy localhost:9015
}
Configure Theme#
In _config.maupassant.yml
, modify the following content:
waline: ## See: https://waline.js.org/
enable: true ## If you want to use the Waline comment system, please set the value to true.
serverURL: https://waline.cirry.cn:66666 ## Your server URL, e.g. https://your-domain.vercel.app
pageSize: 10 ## The desired number of comments shown on each page.
At this point, the comment functionality has been fully set up on your own server. After clearing the cache and restarting, the style is as follows:
Enable Recent Comments Function in Sidebar#
Although the configuration option for recent comments is enabled in _config.maupassant.yml
, the style does not display after configuration.
widgets: ## Seven widgets in the sidebar provided: search, info, category, tag, recent_posts, recent_comments, and links.
- search
- info
- category
- tag
- recent_posts
- recent_comments # Mount recent comments functionality
- links
In themes/maupassant/layout/_widget/recent_comments.pug
, we can see that the theme only configures the recent comments functionality for disqus
by default, so next, we will write our own waline
recent comments functionality.
if theme.disqus.enable == true
.widget
.widget-title
i.fa.fa-comment-o= ' ' + __('recent_comments')
script(type='text/javascript', src='//' + theme.disqus.shortname + '.disqus.com/recent_comments_widget.js?num_items=5&hide_avatars=1&avatar_size=32&excerpt_length=20&hide_mods=1')
First step, add a new configuration item in _config.maupassant.yml
:
waline: ## See: https://waline.js.org/
enable: true ## If you want to use the Waline comment system, please set the value to true.
serverURL: https://************ ## Your server URL, e.g. https://your-domain.vercel.app
pageSize: 20 ## The desired number of comments shown on each page.
wordLimit: 500 ## Limit input word count, 0 means no limit
requiredMeta: ['nick','mail'] ## required user information e.g. ['nick','mail','link']
count: 6 ## The number of recent comments, default is 10
Second step: In themes/maupassant/layout/_widget/recent_comments.pug
, modify the content as follows:
if theme.disqus.enable == true
.widget
.widget-title
i.fa.fa-comment-o= ' ' + __('recent_comments')
script(type='text/javascript', src='//' + theme.disqus.shortname + '.disqus.com/recent_comments_widget.js?num_items=5&hide_avatars=1&avatar_size=32&excerpt_length=20&hide_mods=1')
if theme.waline.enable == true
.widget
.widget-title
i.fa.fa-comment-o= ' ' + __('recent_comments')
#widget-waline-list
script(type='text/javascript', id="recent-comment", serverURL=theme.waline.serverURL, count=theme.waline.count , src=url_for(theme.js) + '/recent-comments.js' + '?v=' + theme.version, async)
Third step: Since this involves sending requests, we first need to create a js file named recent-comments.js
in the themes/maupassant/source/js/
directory.
Fill in the content of recent-comments.js
as follows:
!function () {
let serverURL = document.getElementById("recent-comment").getAttribute("serverURL")
let count = document.getElementById("recent-comment").getAttribute("count")
if (!count) {
count = 10
}
// Format time
function format( date ) {
return new Date(date).toLocaleString()
}
// Handle comments
function dealComment( commentStr ) {
let re = /<a[^>]*href=['"]([^\\"]*)['"][^>]*>(.*?)<\/a>/g;
let arr = [];
while (re.exec(commentStr) != null) {
arr.push(RegExp.$1); // If it is RegExp.$1, then the matched part is the href attribute!
arr.push(RegExp.$2)
}
if (arr.length > 0) { // Indicates that a reply has been matched
commentStr = commentStr.replace(/<a[^>](.*?)<\/a>/, arr[1])
return {
href: arr[0],
author: arr[1],
str: commentStr
}
}
return ''
}
$.ajax({
url: serverURL + '/comment?type=recent',
dataType: 'json',
data: {
count
},
success: function ( response ) {
let comments = '<ul>'
response.forEach(( comment, index ) => {
comments += '<li>' + (index + 1) + '、 ' + format(comment.insertedAt)
if (comment.pid) {
let {href, author, str} = dealComment(comment.comment)
comments += '<div class="waline-comment-content"><a style="display: block" href=' + window.location.origin + comment.url + href + '>'+ str + '</a></div>'
} else {
comments += '<div class="waline-comment-content"><a style="display: block" href=' + window.location.origin + comment.url + '#' + comment.objectId + '>' + comment.comment + '</a></div>'
}
comments += '<div class="waline-comment-content-author">' + '--' + comment.nick + '</div></li>'
})
comments += '</ul>'
$('#widget-waline-list').append(comments)
},
})
}()
This involves the recent comments interface provided by waline
. You can check the waline provided API here.
Fourth step: Adjust styles
This step is only for cases where users have entered emoji expressions in comments, as emojis may appear too large. We will locate the style in themes/maupassant/source/css/style.scss
, specifically in the following position:
Add the following code under #sidebar --> .widget --> ul --> li
.
.wl-emoji{
width: 16px;
}
Finally, append the following style at the end of themes/maupassant/source/css/style.scss
:
/* recent-comments waline style*/
.waline-comment-content {
padding: 6px;
background-color: #f8f8f8;
border-radius: 6px;
overflow: auto;
p {
margin: 0;
display : -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* Here you can set how many lines to show before truncating with ellipsis */
}
}
.waline-comment-content-author {
text-align: end;
margin-bottom: 6px;
}
Enable Word Count Limit and Disable Anonymity#
In themes/maupassant/layout/_partial/comments.pug
, find the waline.init
method and add a configuration item in the method.
Waline.init({
el: '#waline',
comment: true,
serverURL: '#{theme.waline.serverURL}',
pageSize: '#{theme.waline.pageSize}',
wordLimit: 300,
requiredMeta:['nick', 'mail'],
})
Note: Waline has its own spam filtering feature, but it is still better to limit the input from visitors to prevent malicious actions.
Enable Email Notifications#
Here I will directly use QQEmail
as the email service provider.
In the docker-compose.yml
under environment
, add the following email service provider configuration information:
SMTP_HOST: "smtp.qq.com"
SMTP_PORT: 465
SMTP_USER: "your qq email"
SMTP_PASS: "authorization code provided by qq email"
SMTP_SECURE: "true"
Note: The authorization code for qq email can be obtained by going to Login to qq email --> Settings --> Account --> Generate Authorization Code
.
Waline also has a feature to count reading times. I have already used a service called "不蒜子" (Bu Suan Zi) for this, so I won't repeat it here. If it becomes unusable later, I may switch to this one.
This article requires a lot of knowledge. If you have any questions, feel free to leave a comment, and I can write a detailed article on specific topics.
Disable Comment Functionality on Certain Pages#
If you do not want the comment functionality on pages like About Me
or History
, simply set comments: false
in the front matter
of the corresponding document.