If you are interested in contributing to pyOpenSci, please read about how we work in pyOpenSci's organization-wide contributing guide.
Blog posts live in content/blog/. Full front matter reference (every
field, what it does, and a fully filled-out example) lives in
clean-hugo theme: blog formatting and shortcode reference.
To scaffold a new post, run from the repository root:
hugo new content blog/your-post-slug.mdThis creates content/blog/your-post-slug.md pre-filled with the
required and recommended front matter fields, based on the archetype
at themes/clean-hugo/archetypes/blog.md. Fill in title, url,
excerpt, and blog_topic, then write the post body in Markdown.
Preview locally with hugo server --disableFastRender before opening
a pull request.
We have a bash script, scripts/date-updated.sh, that walks blog posts and sets
the lastmod: date in front matter from your local git history. It only
updates posts that already include a lastmod: key.
Hugo blog posts live in content/blog/.
From the repository root:
chmod +x scripts/date-updated.sh
./scripts/date-updated.shIn the future we will add this step to our CI build.
If you are interested in contributing to a specific repository, please review
the README.md and CONTRIBUTING.md files in the repository. If you have any
questions, please open an issue in the repository or contact us via Slack.
This repository, pyOpenSci/pyopensci.github.io,
contains the source code for the pyOpenSci.org website.
The site is built with Hugo. Source lives at the repo
root (content/, data/, themes/clean-hugo/).
If you want to contribute pages, blog posts, theme layouts, SCSS, or shortcodes, start here:
- Read README.md for prerequisites and local setup (
npm ci,hugo server --disableFastRender). - Read DEVELOPMENT.md for CSS architecture and the Hugo asset pipeline.
Please test changes locally before opening a pull request.
Hugo picks a page template in one of two ways:
layout:in front matter — for standalone pages incontent/(landing pages, guides, special listings). Maps tothemes/clean-hugo/layouts/_default/<layout>.html.- Content section +
type:— for pages inside a folder such ascontent/blog/orcontent/events/. Maps tolayouts/<section>/list.html(section index) orlayouts/<section>/single.html(each page in the section).
All layouts extend layouts/_default/baseof.html (site chrome: nav, footer, CSS).
| Layout | Template | How it is selected | Purpose | Live pages |
|---|---|---|---|---|
| splash | _default/splash.html |
layout: splash |
Full-width marketing/landing pages: hero, optional home “What’s next” band, then shortcodes (swoosh sections, cards, feature rows) without a narrow prose column | / (home), /about-peer-review/, /python-packaging-science/, /learn/, /learn-universities-labs/, /partners/, /resources/, /volunteer/, /ways-to-give/ |
| single | _default/single.html |
layout: single |
Hero + narrow prose column (content-main, ~65ch) for long-form Markdown pages |
/how-to-submit-a-package-to-pyopensci/ |
| people-list | _default/people-list.html |
layout: people-list |
Community directory with filters and role-based grids (data from data/contributors.yml) |
/our-community/ |
| packages-list | _default/packages-list.html |
layout: packages-list |
Package catalog with metrics bar, filters, and Alpine.js grid (data from data/packages.yml) |
/python-packages/ |
| docs | _default/docs.html |
layout: docs |
Multi-page documentation book: sidebar nav, mobile toggle, in-page TOC | (not in use yet — see below) |
| blog list | blog/list.html |
type: blog on content/blog/_index.md |
Blog index: featured post, sidebar, topic filters, archives | /blog/ |
| blog single | blog/single.html |
type: blog on each post in content/blog/ |
Individual blog post: image/gradient header, date, topic, prose, tags | All posts under /blog/… (65 posts) |
| events list | events/list.html |
Section content/events/_index.md |
Events landing: hero, upcoming cards, past archives | /events/ |
| events single | events/single.html |
Pages in content/events/ |
Event detail: date/location header, prose body | Each file under /events/… |
| You are building… | Use |
|---|---|
| A marketing or program landing page with shortcodes, swooshes, and card grids | layout: splash |
| A long guide page that is mostly Markdown prose in a readable column | layout: single |
| A new blog post | Add a file to content/blog/ with type: blog (uses blog/single.html automatically) |
| A new event | Add a file to content/events/ with event: front matter (uses events/single.html automatically) |
| A multi-page contributor or internal guide with sidebar navigation | layout: docs in a content/documentation/ section |
| A data-driven listing (packages, people) | packages-list or people-list |
These are different layouts for different page shapes:
splash— default for landing pages. Body lives in.splash-page__contentat full theme width so card grids, metrics bars, and swoosh sections can span the layout. Content is almost always shortcodes and HTML blocks, not a wall of prose.single— one standalone prose page. Body lives in.content-mainwith a comfortable line length for reading. Includes an optional publish date (only whendate:is set in front matter). Not used for blog posts — those useblog/single.html, which has its own post header, topic badge, and tag footer.
Blog and event pages do not set layout: in front matter. Hugo uses the folder name:
content/blog/my-post.md → layouts/blog/single.html
content/blog/_index.md → layouts/blog/list.html
content/events/my-event.md → layouts/events/single.html
content/events/_index.md → layouts/events/list.html
Blog posts should include at minimum:
---
title: "Post title"
date: 2026-06-17
type: blog
excerpt: "Short summary for cards and SEO."
blog_topic: community # community | learn | software | updates
---Event pages use nested event: params (start_date, location, etc.) — copy an existing
file in content/events/ as a template.
The theme includes a docs layout for multi-page guides with a sidebar, mobile
toggle, and in-page table of contents. Use it when you want a small “book” of
Hugo pages on the main site (for example, contributor docs or an internal
guide), separate from splash landing pages, single prose pages, and blog posts.
Layout files (in themes/clean-hugo/):
| Path | Role |
|---|---|
layouts/_default/docs.html |
Docs page shell (header, sidebar, content column) |
layouts/partials/docs-sidebar.html |
Auto-built sidebar from content/documentation/ |
layouts/partials/docs-toc.html |
On-page heading TOC for the active page |
layouts/partials/docs-menu-recursive.html |
Nested sidebar items |
assets/css/_docs.scss |
Docs layout styles |
static/js/docs-nav.js, docs-sidebar.js |
Sidebar toggle and scroll behavior |
How to add a documentation section
-
Create a content section at
content/documentation/:content/documentation/ ├── _index.md # Section home (sidebar “Documentation” link) ├── getting-started.md └── shortcodes/ └── _index.md # Nested subsection (optional) -
Set
layout: docson every page in the section (including_index.md):--- title: Getting started layout: docs weight: 10 excerpt: Optional intro paragraph below the header. header: title: Getting started # optional; defaults to page title color: primaryDark # theme token or hex, e.g. "#33205C" ---
-
Order sidebar entries with
weightin front matter (lower numbers first). Nested pages become expandable subsections in the sidebar. -
Write body content as normal Markdown. Headings
h2–h4appear in the inline TOC on the active page (populated bydocs-nav.js). -
Preview locally:
hugo server --disableFastRenderand open/documentation/(or the path matching your section slug).
The sidebar partial looks up Site.GetPage "/documentation" — if you use a
different section slug, update docs-sidebar.html to match.
There is no live documentation section in content/ yet; the layout is ready
when we add one. For theme-level CSS details, see DEVELOPMENT.md.
The Python Package Guide listed on our website is a guide for scientific authors
who are interested in creating a Python package. The guide is built using the
pyData Sphinx theme for Sphinx, which is a static site generator. If you are
interested in contributing to the Python Package Guide, please see the
README.md
in the pyOpenSci/python-package-guide repo.
The Peer Review Guide is a guide for authors who are interested in submitting a
package to pyOpenSci for peer review. The guide is built using the pyData Sphinx
theme for Sphinx, which is a static site generator. If you are interested in
contributing to the Peer Review Guide, please see the
README.md
in the pyOpenSci/software-peer-review repo.