A bilingual (English/Chinese) research group website built with Hugo and the theme-research-group theme. Deployed to xulab.pages.dev via Cloudflare Pages.
⚠️ GUIDING PRINCIPLE
Keep the code and the content base minimal.
Resist the urge to add features, pages, customizations, or dependencies unless strictly necessary. Every addition has a maintenance cost. When in doubt, leave it out.
For local development and testing changes before pushing to github:
academic package: pip install academicpython update_publications.py --local # reads the running Zotero app; or set ZOTERO_API_KEY and omit --local
academic import --bibtex "Exported Items.bib" content/en/publication/ --overwrite --compact
academic import --bibtex "Exported Items.bib" content/zh/publication/ --overwrite --compact
hugo server
Open http://localhost:1313 in your browser. The server auto-reloads on file changes.
To customize theme templates, vendor the theme first:
hugo mod vendor
Then copy templates from _vendor/github.com/HugoBlox/hugo-blox-builder/modules/blox-bootstrap/v5/layouts/ into layouts/ and edit there. Prefer CSS over custom layout overrides — only copy a theme template if CSS cannot achieve the same result.
All content exists in parallel under content/en/ and content/zh/. Changes to one language usually need a matching change in the other. Language config is in config/_default/languages.yaml.
The layouts/partials/blocks/people.html template implements a fallback mechanism: the Chinese site uses English author profiles as fallback, so only authors with actual Chinese translations need a content/zh/authors/<name>/ directory.
config/_default/hugo.yaml — site title, baseURL, taxonomies, build settingsconfig/_default/params.yaml — theme parameters (colors, features, contact info)config/_default/menus.en.yaml — English navigation menuconfig/_default/menus.zh.yaml — Chinese navigation menuconfig/_default/languages.yaml — language settingsconfig/_default/module.yaml — Hugo module/theme dependencycontent/*/authors/<name>/_index.md + avatar.jpg — lab member profilescontent/*/publication/ — auto-generated from Zotero via Exported Items.bib (do not edit manually)content/*/post/<name>/index.md — blog postscontent/*/event/<name>/index.md — lab eventslayouts/partials/blocks/people.html — custom people/team display blocklayouts/partials/page_author_card.html — author card with avatar, bio, role on publication pageslayouts/partials/page_metadata_authors.html — author list in publication metadata with linking/highlightinglayouts/partials/custom_head.html — extra HTML head contentlayouts/shortcodes/alert.html — alert box shortcode (template placeholder)assets/scss/template.scss — custom SCSS (compiled by Hugo)assets/css/custom.css — additional CSS (processed through Hugo’s asset pipeline)The publication list lives in Zotero, not in this repo: the Publications collection of the xu-research-lab Zotero group. Every build fetches it fresh (update_publications.py → Exported Items.bib, untracked) and generates the pages under content/*/publication/ — do not edit those files manually.
noexport.jiangHighResolutionMicrobiomeAnalysis2025 → /publication/jiang-high-resolution-microbiome-analysis-2025/). Avoid duplicate items: a second copy gets a key with an a suffix and its own page.When the site picks up changes:
gh workflow run publish.yaml;master.To show/hide authors on the publications page, edit config/_default/hugo.yaml:
taxonomies:
author: authors # comment out to hide authors
你可以直接在 GitHub 网页上修改自己的资料,不需要安装软件。修改后提交给网站管理员审核,审核通过并合并后,网站会自动更新。所有成员都应提交英文资料,填写在 content/en/authors/。
1. 找到自己的资料
登录 GitHub,打开成员资料文件夹。找到自己姓名对应的文件夹(如 bingyue-hu),点击其中的 _index.md。如果没有自己的文件夹,可以自行创建,见下方“新成员:创建自己的资料”。
2. 修改文字
点击文件右上角的铅笔按钮(Edit this file)。如果提示 Fork this repository,点击确认:这会在你的账号下创建一份副本,供你提交修改,不会直接改动网站。
文件开头两行 --- 之间是资料设置;第二行 --- 后面可以填写较详细的个人简介。这里是英文资料,简介正文也请用英文填写。 常见字段如下:
| 字段 | 含义 | 如何修改 |
|---|---|---|
title |
显示姓名 | 填写姓名的英文写法,如 Bingyue Hu |
role |
身份 | 如 M.S. student(硕士生)、Ph.D. student(博士生) |
bio |
简短介绍 | 如 bio: 'I study the gut microbiome and host health.' |
interests |
研究兴趣 | 每行填写一项,见下方示例 |
social |
公开联系方式、学术主页 | 按文件中的示例填写;邮箱链接以 mailto: 开头 |
no_link |
是否关闭个人详情页入口 | 有个人简介时改为 false,让访客可以点击进入 |
请保留英文冒号、缩进和每行开头的 -。行首的 # 表示这一行暂不生效;需要启用某项时,去掉该项及其下属行开头的 #,保留缩进。例如,把原来的研究兴趣注释行替换为:
interests:
- Gut microbiome
- Bioinformatics
不要重复添加已有字段。authors、superuser、weight 和 user_groups 请保持原样;身份变更或毕业时,请在提交说明中告知管理员,让管理员同步调整分组和排序。邮箱和简介会公开展示,只填写愿意公开的信息。
3. 提交给管理员审核
点击 Commit changes… 或 Propose changes,填写说明,例如“更新胡冰月的个人简介”。如果可以选择提交位置,请选择 Create a new branch … and start a pull request,不要直接提交到 master。
接着按页面提示点击 Compare & pull request 或 Create pull request,检查修改内容,再点击 Create pull request 完成提交。Pull request(简称 PR)就是一份“请管理员审核这些修改”的申请。若页面显示目标仓库和分支,请确认是 xu-research-lab/xu-research-lab.github.io 的 master 分支。
提交后,把申请页面的链接发给网站管理员。管理员可能会在页面上留言,请按意见修改;合并且自动发布成功后,刷新网站即可看到更新。
更换照片
准备一张竖版个人照片,保存为真正的 JPG 格式,文件名为 avatar.jpg(不要只把 PNG 的扩展名改成 JPG)。在 GitHub 上打开自己的资料文件夹,选择 Add file → Upload files,上传同名照片并按上述流程提交审核。如果文字修改已经提交,请在自己的副本中切换到该申请所用的分支,再上传照片,这样照片会加入同一份申请;不确定时可单独提交,并把两个链接发给管理员。
新成员:创建自己的资料
新成员可以自己创建文件夹并提交审核,无需等待管理员代建:
content/en/authors/ 下同身份成员的 _index.md,点击 Raw 查看原文,复制全部内容作为模板。content/en/authors/,选择 Add file → Create new file。在文件名输入框填写 你的姓名拼音/_index.md,例如 xiaoming-zhang/_index.md。输入 / 后 GitHub 会自动创建文件夹。文件夹名使用小写字母和连字符,不能与已有成员重复。title 和 authors 列表中的姓名都改成自己的英文姓名,填写自己的英文资料及简介。删除或替换从模板复制来的他人联系方式、教育经历和介绍;保留原有注释示例。填写了简介后,将 no_link 设为 false。role 和 user_groups 都要匹配自己的身份:硕士生用 M.S. student,博士生用 Ph.D. student,博士后用 Postdoctoral Researchers。superuser 保持 false。weight 是排序数字:硕士生为 10 加入学年份(如 102026),博士生为 20 加入学年份(如 202026),博士后为 30 加入站年份(如 302026)。不确定时在申请中说明,请管理员核对。add-xiaoming-zhang)并保存。记住这个分支名,接下来保持在该分支,打开新建的姓名文件夹,按“更换照片”的步骤上传自己的 avatar.jpg,保存到同一分支。master 分支,来源选择自己副本中刚才的分支。确认申请包含自己的 _index.md 和 avatar.jpg,然后将申请链接发给网站管理员。如果同时提供中文翻译,在同一分支下回到副本首页,选择 Add file → Create new file,填写 content/zh/authors/xiaoming-zhang/_index.md(换成自己的文件夹名),粘贴并翻译自己的资料,再保存到该分支,即可一起提交审核。
Each member is defined by a folder under content/en/authors/<name>/ containing:
_index.md — profile data (name, role, bio, interests, education, social links, user_groups)avatar.jpg — profile photo (recommended: portrait aspect ratio)Author profiles follow a consistent Hugo Blox template format with these sections (commented out when empty): bio, interests, education, social.
The user_groups field determines which section the member appears in:
Faculty — professorsPostdoctoral ResearchersPh.D. student — doctoral studentsM.S. student — master’s studentsAlumni — former lab membersSet no_link: false to enable links to the member’s profile page, or no_link: true to disable.
Only create content/zh/authors/<name>/ if you have an actual Chinese translation (the English profile is used as fallback).
To remove a member: delete their folder from content/en/authors/ (and from content/zh/authors/ if a Chinese version exists).
To sort members: within each group, members are ordered by weight defined in their profiles. The weight value combines role priority (Postdoc = 30, Ph.D. = 20, M.S. = 10) with year. Use graduation year for alumni, or start year for current members, e.g., 102021. The sorting is configured in content/en/people/index.md.
Each post is a folder under content/en/post/<slug>/ containing index.md.
To add a post: create the folder and index.md. Set draft: true to hide it from the live site. Mirror under content/zh/post/<slug>/ if a Chinese version is needed.
To remove a post: delete the folder from both language directories.
The slider is configured in content/en/activity/index.md and content/zh/activity/index.md.
To add a photo:
assets/media/ (e.g. assets/media/group3.jpg)- title: "2025.9"
content: Lab retreat
align: end
background:
image:
filename: group3.jpg
filters:
brightness: 1.0
To remove a photo: delete its slide entry from both files (and optionally delete the image from assets/media/).
Events are listed at /event/. Each event is a folder under content/en/event/<slug>/ containing index.md.
A minimal event file:
---
title: "Talk: Title of the Talk"
event: Conference or Seminar Name
location: Room 503, Building X
date: 2025-09-01T14:00:00
date_end: 2025-09-01T15:00:00
all_day: false
abstract: "Brief description of the talk."
---
Mirror the file under content/zh/event/<slug>/ with a Chinese version.
Links are defined in content/en/_index.md and content/zh/_index.md as a markdown block:
- block: markdown
content:
title: Useful Links
text: |
- [**Link Name**](https://example.com)
Brief description
design:
columns: '1'
css_class: section-useful-links
Add, remove, or reorder items in the markdown list. Mirror the change in content/zh/_index.md.
Edit content/en/contact/index.md and content/zh/contact/index.md. The address, coordinates, and office details are set in the front matter of those files.
Edit config/_default/menus.en.yaml (English) and config/_default/menus.zh.yaml (Chinese). Each entry under main has a name, url, and weight (lower weight = appears first).
The navigation contains Home, People, Publications, Activities, and Contact, with matching Chinese entries. Events / 学术活动 and Posts / 博客 are hidden from both menus; their content and URLs remain available. Removing a menu entry does not unpublish a page.
To restore a hidden tab, add its entry back to both menu files:
| Tab (English / Chinese) | English URL | Chinese URL | Weight |
|---|---|---|---|
| Events / 学术活动 | /event/ |
/zh/event/ |
43 |
| Posts / 博客 | /post/ |
/zh/post/ |
50 |
Replace assets/media/true.jpg, or edit the design.background.image.filename field in content/en/_index.md and content/zh/_index.md.
Replace assets/media/icon.png (keep the filename).
Edit content/en/authors/we-want-you/_index.md (and content/zh/authors/we-want-you/_index.md) to reflect current open positions.
Specific posts are encrypted after the Hugo build using StaticCrypt. The encrypted HTML is what gets deployed — the plaintext is never served to the browser.
The CI step:
staticrypt public/en/post/lab-nas-guide/index.html -p "$HUGO_SITE_PASSWORD" -d public/en/post/lab-nas-guide/ --short
The --short flag suppresses the interactive confirmation prompt in non-interactive CI environments.
To protect an additional post, add a line in the same form to the “Encrypt protected pages” step in .github/workflows/publish.yaml.
The password is stored as a GitHub secret named HUGO_SITE_PASSWORD. To set or update it:
HUGO_SITE_PASSWORD and Value to your chosen password.Pushes to the master branch, a daily schedule, or a manual run trigger .github/workflows/publish.yaml, which:
update_publications.py to fetch the Zotero group’s “Publications” collection into Exported Items.bib.academic import "Exported Items.bib" content/*/publication/ --compact to regenerate publication pages.--minify --baseURL "https://xulab.pages.dev/").wrangler pages deploy.xulab and complete the wizard.Navigate to Workers & Pages. The Account ID is the hex string in the dashboard URL:
https://dash.cloudflare.com/<ACCOUNT_ID>/workers-and-pages
Go to My Profile → API Tokens → Create Token. Use the “Edit Cloudflare Workers” template, or create a custom token with the “Cloudflare Pages: Edit” permission.
Go to Settings → Secrets and variables → Actions in the GitHub repository and add:
| Secret name | Value |
|---|---|
CLOUDFLARE_API_TOKEN |
The API token from step 3 |
CLOUDFLARE_ACCOUNT_ID |
The Account ID from step 2 |
HUGO_SITE_PASSWORD |
The site password for protected posts |
ZOTERO_API_KEY |
A read-only Zotero API key with access to the xu-research-lab group (zotero.org/settings/keys) |
The site’s search-engine verification and SEO signals live in four places:
layouts/partials/custom_head.html — injected into every page’s <head>:
google-site-verification) and Bing (msvalidate.01) meta tags.Person JSON-LD block (homepage only) for 徐振江 with sameAs links to ORCID, Google Scholar, Web of Science, GitHub, and Twitter. This binds the name query to the site as an entity.baidu-site-verification) slot, unused until the site moves to a China-reachable, ICP-filed domain (Baidu barely crawls *.pages.dev).static/BingSiteAuth.xml — root-level Bing verification file. Needed because the site root (/) is only a redirect stub to /en/, so Bing’s meta-tag check fails there; the XML file verifies against a standalone root URL instead.static/google5d6fb96f91cf1978.html — root-level Google verification file (a second method alongside the meta tag).config/_default/languages.yaml + content/zh/_index.md — a Chinese marketing.seo.description for the zh site (the theme default is English).Both verification files sit in static/ (not the repo root or public/) because Hugo copies static/ verbatim to the site root — that is the Hugo equivalent of “upload the file to your site root.”