Post Page Configuration
This page explains the post page configuration: hero image, meta info under the title (date/word count/reading time/views), TOC, comments, reward, copyright, math and diagrams. Everything lives in the post section of the theme config.
The authoritative source of the theme config is
userConfig/_config.tmp.yml(it overwrites the theme config at CI time).
Display & Layout
1. Post Page Hero Image
Purpose: the banner at the top of post pages (distinct from the homepage hero; set independently).
Config (theme config, post section):
post:
banner_img: /img/default.png # post page hero image
banner_img_height: 70 # hero image height (percentage of screen, 0-100)
banner_mask_alpha: 0.3 # black mask opacity (0-1)A single post can override the global setting with banner_img in front-matter.
Hero image source priority (_partial/post/post-cover rendering logic):
- front-matter
img(e.g.img: /medias_webp/xxx.webp) — explicit - without
img, pick one fromtheme.featureImagesby a hash of the title (/medias_webp/featureimages/0-44.webp; the same title always gets the same image) - when random background is on (
theme.background.image.random), the post banner is hidden
Note:
featureImagesonly sources frommedias_webp/featureimages/(webp, numbered 0-44, with adark/subdirectory); the legacymedias/featureimages/(jpg) is removed — do not reference.jpgpaths.
2. Meta (meta)
Purpose: the info row under the post title: date, word count, reading time, views — each independently toggleable.
Config (theme config, post.meta section):
post:
meta:
author: # author (front-matter author first, then site author)
enable: false
date: # post date (front-matter date first, then md file date)
enable: true
format: "LL a" # ISO-8601 date format
wordcount: # word count
enable: true
min2read: # reading time estimate
enable: true
awl: 1 # average word length (chars per word): 1 for CJK-dominant sites
wpm: 300 # words per minute: 250-350 recommended for CJK technical content
views: # view counter
enable: true
source: "umami" # data source: busuanzi | leancloud | umami | walineNotes: post.meta.views.source decides where views come from — this blog uses umami (self-hosted analytics); alternatives include busuanzi (zero config) or Waline comment views.
3. Updated Notice (updated)
Purpose: show “last updated on X” at the top of the post; defaults to the md file modification time, overridable with updated in front-matter.
Config (theme config):
post:
updated:
enable: false # off by default
date_format: "LL a" # ISO-8601 format
relative: false # true = relative time ("3 days ago")
note_class: info # notice style: default | primary | info | success | warning | danger | light4. TOC
Purpose: chapter navigation in the post sidebar, current chapter highlighted while scrolling, collapsible.
Config (theme config, top-level toc section):
toc:
enable: true # global switch
headingSelector: "h2,h3,h4,h5,h6" # heading levels included
collapseDepth: 0 # collapse depth (0 all collapsed, >0 expands when children exist)Disable for a single post: add toc: false in front-matter.
Interaction & Copyright
5. Comments (comments)
Purpose: site-wide comment system switch and engine selection.
Config (theme config, post.comments section):
post:
comments:
enable: true
type: waline # engines: utterances | disqus | gitalk | gitment | valine | waline | changyan | livere | remark42 | twikoo | cusdis | giscus | discussNotes: whichever engine type points to, you must also configure that plugin’s required params (e.g. this blog’s waline.serverURL, see the Layout & Pages chapter). Page-level control uses front-matter comments: true/false (same for standalone pages, message pages and friends pages).
5.1 Comment Engine Configs
Waline (this blog’s primary, detailed):
waline:
enable: true
serverURL: 'https://waline.17lai.site' # Waline service address (self-hosted, required)
avatar: 'mp' # avatar style: ''/mp/identicon/monsterid/wavatar/retro/hide
lang: zh-CN # UI language
dark: 'html[data-user-color-scheme="dark"]' # dark mode selector
login: enable # login mode: enable | force
wordLimit: 1000 # comment word limit (0 = unlimited)
pageSize: 10 # comments per page
pageview: false # post page views v2 (with post.meta.views.source: waline)
comment: true # comment count v2 (with postInfo.commentCount)
reaction: | # post reactions (custom emoji URL array, matching _config.tmp.yml)
[
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_agree.png',
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_look_down.png',
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_sunglasses.png',
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_pick_nose.png',
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_awkward.png',
'https://testingcf.jsdelivr.net/npm/@waline/emojis/tieba/tieba_sleep.png'
]
search: false # emoji search (default provided by giphy)
imageUploader: false # image upload (false disables; default embeds as Base64)
meta: "['nick', 'mail', 'link']" # fields guests can fill
requiredMeta: "['nick', 'mail']" # required fields
recaptchaV3Key: '' # reCAPTCHA v3 key (anti-spam, optional)
highlight:
enable: false # disable Waline's built-in highlighter
custom_highlighter: | # custom highlight function (waline.ejs reads highlight.custom_highlighter)
(code, lang) => { /* highlight with Prism */ }These are the keys actually read by
waline.ejs(serverURL/avatar/lang/dark/login/wordLimit/pageSize/pageview/comment/reaction/search/imageUploader/meta/requiredMeta/recaptchaV3Key/highlight.custom_highlighter). Valine-specific keys (enableQQ/recordIP/requiredFields/guest_info/count/visitor) are not read by waline.ejs — configuring them has no effect.
Other engines (condensed config):
| Engine | Config key | Required params | Notes |
|---|---|---|---|
| Valine | valine | appId/appKey/serverURLs (Valine-specific keys enableQQ/recordIP/requiredFields/guest_info/count/visitor) | legacy comments (Waline’s predecessor), params same as Waline, needs LeanCloud credentials; prefer Waline |
| Gitalk | gitalk | owner/repo/oauth.clientId/oauth.clientSecret/admin | GitHub Issues-based; OAuth app has excessive permissions, not recommended |
| Gitment | gitment | owner/repo/oauth.clientId/oauth.clientSecret | GitHub Issues-based; same security issue as Gitalk (see §13) |
| Disqus | disqus | shortname | mainstream foreign comment service, unstable in China |
| Livere | livere | uid | Korean service, works in China |
| Changyan | changyan | appId/conf | Sohu service, requires ICP filing |
| Twikoo | twikoo | envId (optional region/path) | Tencent CloudBase deployment, see twikoo.js.org |
| Cusdis | cusdis | host/app_id/lang | third-party or self-hosted, see cusdis.com |
| Giscus | giscus | repo/repo-id/category/category-id (optional mapping/theme-light/theme-dark/lang) | GitHub Discussions-based, see giscus.app |
| Remark42 | remark42 | host/site_id (optional max_shown_comments/locale/components) | requires self-hosted server, see remark42.com |
| Discuss | discuss | serverURLs/path | self-hosted, multi-platform multi-database, see discuss.js.org |
| Utterances | utterances | repo/label (optional issue_term/theme/theme_dark) | lightweight GitHub Issues-based comments, needs a GitHub repo, see utteranc.es |
Switching engines in three steps: ① set
post.comments.typeto the target engine; ② fill in the required params from the table above; ③hexo clean && hexo generateto rebuild. GitHub-based engines (Gitalk/Gitment) carry OAuth permission risks — prefer utterances/giscus-style single-repo solutions.
6. Reward (reward)
Purpose: a tipping card at the end of posts showing WeChat/Alipay payment QR codes.
Config (theme config):
post:
reward:
enable: true
title: 码字辛苦,打赏作者!
wechat: /medias_webp/reward/wechat.webp # WeChat payment QR image
alipay: /medias_webp/reward/alipay.webp # Alipay payment QR imageNotes: replace the QR images with your own; full URLs for network images are supported.
7. Copyright (copyright)
Purpose: copyright card at the bottom of posts: author, original link and reprint license.
Config (theme config):
post:
copyright:
enable: true # show copyright notice
license: 'cc_by_nc_sa' # default reprint rule (sub-key of copyright, site-wide)Per-post front-matter override:
reprintPolicy: cc_by_nc # this post: Attribution-NonCommercialAvailable rules: cc_by, cc_by_nd, cc_by_sa, cc_by_nc, cc_by_nc_nd, cc_by_nc_sa (meanings at Creative Commons).
Content Rendering
8. Math (math)
Purpose: render $...$ / $$...$$ formulas in posts.
Config (theme config):
post:
math:
enable: false # posts use it by default when enabled
specific: true # true = only posts with mathjax: true in front-matter load it (saves bandwidth)
engine: mathjax # engine: mathjax | katexNotes: specific: true is this blog’s recommended usage — posts without formulas don’t load the engine; when needed, add mathjax: true in front-matter (markdown-plugins.ejs checks page.mathjax). Custom pages (non-post) using formulas also need mathjax: true in front-matter.
9. Diagrams (mermaid)
Purpose: render mermaid flowcharts/sequence diagrams/gantt charts in posts (```mermaid code blocks or the tag plugin).
Config (theme config):
post:
mermaid:
enable: true # posts use it by default when enabled
specific: true # true = only posts with mermaid: true in front-matter load it
options: # mermaidAPI config
theme: 'default' # theme (dynamically overridden by light/dark mode)
startOnLoad: true
securityLevel: 'loose'
flowchart:
useMaxWidth: false # don't stretch to container width in flowcharts
gantt:
useMaxWidth: true
barHeight: 20
barGap: 4Notes: the mermaid library is slow to load; with specific: true, write mermaid: true in front-matter to enable it (the same on-demand loading pattern as math). theme is dynamically overridden by light/dark mode but serves as the default.
10. Other Post Page Features
The post section also includes (see the Layout & Pages chapter):
post:
prev_next:
enable: true # prev/next navigation cards
outdate: # outdated content notice (off by default)
enable: false
warning_day: 365
error_day: 3650
category_bar: # show posts of the current category in the sidebar
enable: true
specific: true # true = only shows with category_bar: true in front-matter
post_order_by: '-date' # example: date desc (theme default config sorts by title)
post_limit: 0 # max items shown (0 = unlimited)
webpush: # browser push subscription button (webpushr)
enable: true
advertisements: # sidebar ad cards (array, individually toggleable)
- id: "ad-1"
text: "Ad copy"
enable: trueBrowser push subscription (webpush): with post.webpush.enable: true, the post detail page shows a webpushr subscribe button at the bottom (_partial/common/webpush); readers who allow it receive browser push notifications when new posts are published. Register your site at app.webpushr.com and inject the subscription script (the webpushr site ID lives in the theme head template).
Info Display
11. Post Info (postInfo)
Purpose: independent switches for the post info bar — author, date, word count, total count, reading time, reading mode, read count, comment count. This is a separate mechanism from §2 post.meta.
Config (theme config):
postInfo:
author: true # author
date: true # publish date
update: true # update date
wordCount: true # post word count
totalCount: true # site total word count
> `totalCount` (`totalcount(site)`) covers **posts + wiki pages**: **deduplicated across language versions** (same content counted once) and **encrypted posts counted by plaintext**.
min2read: true # reading time
readMode: true # reading mode
readCount: true # read count
commentCount: true # comment count (currently supports waline)Notes: Word count and reading time are provided by the theme’s built-in helpers (scripts/helpers/wordcount.js) — no extra plugin is required. The wordcount / min2read / totalcount helpers are theme-native; totalcount renders the site-wide total in the footer (including wiki pages and the plaintext count of encrypted posts).
12. Decorative HR (hr)
Purpose: beautified horizontal rule for --- dividers in posts.
Config (theme config):
hr:
enable: false # false | trueNotes: when enabled, Markdown --- renders as a decorated divider instead of a plain thin line.
Stats & Verification
13. Gitment Comments (gitment)
Purpose: GitHub Issues-based comment system (Gitment). Disabled by default — this blog primarily uses Waline.
Config (theme config):
gitment:
enable: false
owner: # GitHub username
repo: # repo that stores comments
oauth:
clientId: # GitHub OAuth App Client ID
clientSecret: # GitHub OAuth App Client SecretNotes: requires creating a GitHub OAuth App and filling owner/repo/clientId/clientSecret. Security warning: Gitment/Gitalk-style OAuth apps have excessive permissions (can read/write all of the authorizer’s public repos) — an attacker with the Token can wipe your public repos. Prefer utterances-style GitHub Apps scoped to a single repo (see config comments).
14. Tencent Captcha (tcaptcha)
Purpose: Tencent captcha (slider/click) before comment submission, to block spam.
Config (theme config):
tcaptcha:
enable: false
appid: 2057160203 # your appidNotes: currently only adapted and tested with Valine — other comment systems are unverified. Create a captcha in the Tencent Cloud Captcha console to get an appid; intro: official docs.
15. Waline Site Counter (minWalineCount)
Purpose: footer site-wide PV (page views) counter, served by Waline.
Config (theme config):
minWalineCount:
enable: true
serverURL: 'https://waline.17lai.site'
pageview: true # page view stats v2Notes: the footer “site PV” is fetched and updated from the Waline service by walineCount.ejs.
16. Waline Comment Counter (minWalineCommentCount)
Purpose: site-wide comment count statistics.
Config (theme config):
minWalineCommentCount:
enable: false
serverURL: 'https://waline.17lai.site'
comment: true # comment count stats v2Notes: disabled by default — comment counts are already handled by waline.ejs (theme.waline.comment); enabling this would duplicate requests.
17. Post Password Verification (verifyPassword)
Purpose: set an access password for specific posts; readers must enter it to read.
Config (theme config):
verifyPassword:
enable: false
promptMessage: 请输入访问本文章的密码
errorMessage: 密码错误,将返回主页!Post front-matter (in-house HBE v4 since 2026-08-09; the password is plaintext, a SHA256 hash is no longer required):
password: "your password" # plaintext passwordNotes: in-house HBE v4 (AES-256-GCM, replacing hexo-blog-encrypt since 2026-08-09) — server-side AES-256-GCM encryption stores ciphertext in HTML (no plaintext leakage), front-end WebCrypto decryption. Write the plaintext password directly in front-matter password (no SHA256 pre-hashing needed).
Other encryption methods:
- Content snippet encryption:
{% encrypt password "title" "abstract" %}...{% endencrypt %}(paragraph-level, supports nested tags, see Tag Plugins §15) - Wiki-wide encryption: add
encrypt_passwordto{wiki}-sidebar.yml(see Layout & Pages §8) - Password storage: autoSave stores the derived DK (not the plaintext password), 1-day TTL
See the Layout & Pages chapter for full configuration.
Sharing & Recommendations
18. Post Sharing (sharejs)
Purpose: share buttons at the bottom of posts, supporting multiple platforms.
Config (theme config):
sharejs:
enable: true
sites: twitter,facebook,qq,qzone,wechat,weibo,doubanNotes: sites is a comma-separated list; options: twitter, facebook, google, qq, qzone, wechat, weibo, douban, linkedin.
19. AddThis Sharing (addthis)
Purpose: AddThis-based sharing module (alternative to sharejs).
Config (theme config):
addthis:
enable: false
pubid: 613a04428f842fe1 # get from https://www.addthis.com/Notes: choose one of sharejs/addthis; enable: true uses AddThis sharing; pubid is obtained after registering at AddThis.
20. Related Posts (related_posts)
Purpose: related post recommendations at the bottom of posts.
Config (theme config):
related_posts:
enable: false
title: 相关文章推荐 # custom header, empty = default
display_in_home: false # show on homepage too
params:
maxCount: 5 # max recommendations
PPMixingRate: 0.25 # mixing ratio
isDate: false # show date
isImage: false # show image
isExcerpt: false # show excerptNotes: recommends by tag/category similarity; with display_in_home: true, homepage post cards also show related recommendations.
21. LeanCloud Read Count (leancloud_visitors)
Purpose: LeanCloud-based post read count (the data source when post.meta.views.source: leancloud).
Config (theme config):
leancloud_visitors:
enable: true
app_id: v2hJTCLDHLnGF4iSJkBJ8mga-MdYXbMMI
app_key: Hu4UNHLVERHkhfH6G5xqdqN3Notes: after enabling, set §2 post.meta.views.source to leancloud for it to take effect; this blog uses umami by default, this config is kept as a backup.
22. Google AdSense (googleAd)
Purpose: Google AdSense ad slot on post pages.
Config (theme config):
googleAd:
enable: false
adClient: "ca-pub-2899930387274309"Notes: adClient is the AdSense publisher ID (ca-pub- prefix), obtained after registering at Google AdSense. The config comment marks it “not yet complete”.
Appendix: Post Page Config Quick Reference
| Config item | Location | Description |
|---|---|---|
| Post hero | post.banner_img etc. | per-post override via front-matter banner_img |
| Author/date | post.meta.author / post.meta.date | date format "LL a" |
| Word count/time | post.meta.wordcount / post.meta.min2read | awl 1 / wpm 300 |
| Views | post.meta.views | sources umami/busuanzi/leancloud/waline |
| Updated | post.updated | off by default, front-matter updated overrides |
| TOC | toc | per-post off via front-matter toc: false |
| Comments | post.comments | type: waline, front-matter comments controls |
| Reward | post.reward | WeChat/Alipay payment QR |
| Copyright | post.copyright (with license sub-key) | per-post override via front-matter reprintPolicy |
| Math | post.math | specific: true + front-matter mathjax: true |
| Diagrams | post.mermaid | specific: true + front-matter mermaid: true |
| Prev/next, outdate, category bar, ads | post.prev_next / outdate / category_bar / advertisements | see the Layout & Pages chapter |