Directory Structure & Content Management
1. Blog Directory Structure
A typical Hexo + matery site layout (this blog as reference):
blog/
├── _config.yml # Site config (Hexo core + all plugin configs)
├── package.json # Dependencies and npm scripts
├── source/ # ★ Content and standalone pages
│ ├── _posts/ # Posts (Markdown)
│ ├── _drafts/ # Drafts (render_drafts: false, not rendered by default)
│ ├── _data/ # Data files (friends/galleries/sidebar etc., single source)
│ ├── _template/ # Reusable Markdown fragments
│ ├── about/ # Standalone pages (one directory + index.md each)
│ ├── tags/
│ ├── categories/
│ ├── friends/
│ ├── galleries/
│ └── ... # Other standalone pages (msg, nav, docs etc.)
├── scaffolds/ # Templates used by hexo new (post/page/draft/gallery)
├── themes/
│ └── matery/ # Theme (layout templates + source static assets + scripts)
├── tools/ # CI/CD scripts and toolchain (customized for this blog)
├── userConfig/ # User config and build templates (customized for this blog)
└── public/ # Build output (generated by hexo generate, don't edit)Key conventions:
- Every Markdown file under
source/is rendered to HTML; standalone pages needlayoutin front-matter (e.g.layout: about), otherwise they render with the defaultpostlayout public/is build output, deleted byhexo clean— never edit it manually- Some paths in this blog (nav/, docs/, js/, libs/ etc.) are copied as-is via
skip_render
2. Post Management
Create a Post
hexo new post "Post title" # creates source/_posts/post-title.md
hexo new post --path 2026/xxx title # custom pathQuote the title if it contains spaces; filenames are auto-lowered (filename_case: 1). After creation, edit the Markdown file.
Drafts
hexo new draft "Unfinished idea" # creates in source/_drafts/
hexo publish "Unfinished idea" # publish: move to _posts/ and set the daterender_drafts: false in _config.yml means drafts are not generated by default. To preview drafts locally use hexo server --draft or hexo generate --draft.
Cache Notes After Changing Config/Data
- After changing theme config or
scripts/scripts:hexo clean && hexo generate(rm -rf publicis not enough — it misses hexo’s internal cache) - After changing
source/_data/*.ymldata files: deletedb.jsonbefore generating, otherwise stale data may be read
3. Permanent Links (abbrlink)
Default permalink format:
# _config.yml
permalink: posts/:abbrlink/The hexo-abbrlink plugin generates a short code per post with crc32 + hex (e.g. posts/40300608/). writeback: false (disabled since 2026-09-22 to prevent a resident server from clobbering source files) means the plugin does not write back — abbrlink is written into the front-matter on first generation and stays fixed:
---
title: My post
abbrlink: a1b2c3d4 # written on first generation, don't edit manually
---Once generated, abbrlink is fixed — renaming the file or changing the title won’t affect the URL, which keeps external links stable. Configuration:
abbrlink:
alg: crc32 # algorithm: crc16 / crc32
rep: hex # representation: dec / hex
drafts: false # generate for drafts
force: false # force recompute (changes existing URLs, use with care)4. Front-matter Quick Reference
Front-matter is the YAML block at the top of a post (wrapped in ---), defining post metadata. Common fields used by the matery theme:
| Field | Description | Default |
|---|---|---|
title | Post title | filename |
date | Creation date | file creation time |
updated | Update date | file modification time |
layout | Layout: post / page / about / tags etc. | post |
categories | Categories (array, supports nesting [parent, child]) | - |
tags | Tags (array) | - |
keywords | SEO keywords | - |
excerpt | Homepage excerpt (plain text) | - |
img | Post cover image (shown on homepage cards) | - |
top | Pin to homepage | false |
hide | Fully hide: not in homepage list, not in carousel | false |
cover | Enter homepage carousel (ineffective when hide: true) | false |
coverImg | Custom carousel image (takes priority over default) | - |
toc | Show table of contents | true |
tochide | Hide the TOC sidebar by default | false |
mathjax | Load MathJax for math formulas | false |
mermaid | Load Mermaid for diagrams | false |
echarts | Load ECharts | false |
comments | Enable comments | true |
comment | Comment engine (e.g. waline; false disables) | theme default |
password | Post encryption password (for per-post encryption) | - |
reprintPolicy | Copyright policy (e.g. cc_by_nc_sa) | - |
abbrlink | Permalink short code | written on first generation (no writeback) |
Example:
---
title: Example post
date: 2026-08-16 12:00:00
categories: [Tutorial]
tags:
- hexo
- matery
img: /medias_webp/cover/write.webp
top: false
hide: false
toc: true
mathjax: false
mermaid: true
comments: true
comment: waline
---When creating a post,
scaffolds/post.mdbrings in the template fields above — add or remove as needed.
5. Data Files (_data)
source/_data/ holds the single sources of truth the theme reads, avoiding scattered duplicate data. Hexo auto-loads yml/yaml/json files in this directory — the filename (minus extension) becomes the key, accessible in templates via site.data.<filename>.
5.1 File Inventory
| File | Purpose | Consumer |
|---|---|---|
friends.yml | Friend link data — each entry has name / avatar / introduction / url / title (optional) | friends.ejs template, site.data.friends |
galleries.yml | Gallery data — top-level galleries: array; each gallery has name / cover / description / photos (supports single-image objects, path strings, and directory scanning) | galleries.ejs template, site.data.galleries |
tutorial-sidebar.yml | Tutorial wiki sidebar navigation | wiki.js helper’s wiki_sidebar() |
api-sidebar.yml | API wiki sidebar navigation | same |
dev-sidebar.yml | Dev wiki sidebar navigation (also has encrypt_password and other encryption metadata at the top, not part of navigation) | same |
docs-sidebar.yml | Docs wiki sidebar navigation | same |
5.2 Sidebar File Structure
The four *-sidebar.yml files share a uniform structure:
# Language-agnostic page tree (section → page → html path)
structure:
getting_started:
overview: index.html
features: features.html
guides:
layout: guide/layout.html
# Per-language display text (key = preference.lang_meta namespace)
i18n:
zh-cn:
getting_started: 开始使用
overview: 概述
en:
getting_started: Getting Started
overview: Overviewstructure: defines the navigation hierarchy and page paths, contains no language-specific texti18n: display text grouped by language; keys correspond topreference.lang_metainlanguages/*.ymlencrypt_*(only indev-sidebar.yml): top-level metadata controlling wiki encryption (encrypt_passwordrequired,encrypt_message/encrypt_placeholderoptional); not used in navigation rendering
The consumer is themes/matery/scripts/helpers/wiki.js’s wiki_sidebar() function, which reads site.data[wiki + '-sidebar'] and merges i18n text.
5.3 How to Add
| Action | Steps |
|---|---|
| Add a friend link | Append a - name: xxx block at the end of friends.yml, fill in all 5 fields |
| Add a gallery | Append an entry to the galleries: array in galleries.yml; also create source/galleries/<name>/index.md with layout: gallery |
| Add a wiki sidebar entry | Add a key + html path in the structure of the relevant {wiki}-sidebar.yml, and add translations in i18n for each language |
5.4 Cache Notes
After modifying _data/*.yml, you must delete db.json before rebuilding (rm -f db.json && hexo generate), otherwise Hexo’s incremental cache may serve stale data, causing blank pages. The tools/cicd.sh -d build handles this automatically.
Next Steps
- Feature Guide: layouts, tag plugins and interactions