# plain.pages **Serve static pages, markdown, and assets from templates/pages directories.** - [Overview](https://plainframework.com/docs/plain-pages/plain/pages/?llm#overview) - [Page types](https://plainframework.com/docs/plain-pages/plain/pages/?llm#page-types) - [HTML pages](https://plainframework.com/docs/plain-pages/plain/pages/?llm#html-pages) - [Markdown pages](https://plainframework.com/docs/plain-pages/plain/pages/?llm#markdown-pages) - [Redirect pages](https://plainframework.com/docs/plain-pages/plain/pages/?llm#redirect-pages) - [Assets](https://plainframework.com/docs/plain-pages/plain/pages/?llm#assets) - [Template pages](https://plainframework.com/docs/plain-pages/plain/pages/?llm#template-pages) - [Serving raw markdown](https://plainframework.com/docs/plain-pages/plain/pages/?llm#serving-raw-markdown) - [Linking to markdown URLs](https://plainframework.com/docs/plain-pages/plain/pages/?llm#linking-to-markdown-urls) - [Frontmatter](https://plainframework.com/docs/plain-pages/plain/pages/?llm#frontmatter) - [Custom views](https://plainframework.com/docs/plain-pages/plain/pages/?llm#custom-views) - [Settings](https://plainframework.com/docs/plain-pages/plain/pages/?llm#settings) - [FAQs](https://plainframework.com/docs/plain-pages/plain/pages/?llm#faqs) - [Installation](https://plainframework.com/docs/plain-pages/plain/pages/?llm#installation) ## Overview The plain.pages package automatically discovers and serves static pages from `templates/pages` directories in your app and installed packages. Pages can be HTML, Markdown, redirects, or static assets, with support for frontmatter variables and template rendering. ```python # app/templates/pages/about.md --- title: About Us --- # About Our Company We build great software. ``` This creates a page at `/about/` that renders the markdown content with the title "About Us". Pages are discovered from: - `{package}/templates/pages/` for each installed package - `app/templates/pages/` in your main application The file path determines the URL: - `index.html` or `index.md` → `/` - `about.html` or `about.md` → `/about/` - `docs/getting-started.md` → `/docs/getting-started/` - `styles.css` → `/styles.css` (served as static asset) ## Page types ### HTML pages HTML files are rendered as templates with access to the standard template context: ```html --- title: Features ---

{{ page.title }}

Current user: {{ get_current_user() }}

``` ### Markdown pages Markdown files (`.md`) are automatically converted to HTML: ```markdown --- title: User Guide template_name: custom-page.html --- # User Guide This is **markdown** content with [links](https://plainframework.com/docs/other-page/?llm). ``` ### Redirect pages Files with `.redirect` extension create redirects: ```yaml # app/templates/pages/old-url.redirect --- url: /new-url/ temporary: false --- ``` ### Assets Any file that isn't HTML, Markdown, or a redirect is served as a static asset: ``` app/templates/pages/ ├── favicon.ico ├── robots.txt ├── images/ │ └── logo.png └── docs/ └── guide.pdf ``` These are served at their exact paths: `/favicon.ico`, `/images/logo.png`, etc. ### Template pages Files containing `.template.` in their name are skipped and not served as pages. Use these for shared template fragments: ``` app/templates/pages/ ├── base.template.html # Not served └── index.html # Served at / ``` ## Serving raw markdown You can optionally serve raw markdown content (without frontmatter) alongside rendered HTML pages. When enabled, markdown pages can be accessed as raw markdown via: 1. **Accept header negotiation** - Send `Accept: text/markdown` or `Accept: text/plain` to get raw markdown 2. **Separate .md URLs** - Access `/docs/guide.md` alongside `/docs/guide/` ```python # settings.py PAGES_SERVE_MARKDOWN = True ``` With this setting enabled: - `/docs/guide/` with `Accept: text/html` → Rendered HTML page - `/docs/guide/` with `Accept: text/markdown` → Raw markdown content - `/docs/guide.md` → Raw markdown content (without frontmatter) The raw markdown serves with `text/plain` content type, making it useful for: - External markdown processors - API consumers needing markdown source - Documentation tools that need raw content - Command-line tools like curl or httpie **Note**: This feature is disabled by default. Only enable it if you need to serve raw markdown content. ### Linking to markdown URLs When markdown serving is enabled, you can link to the raw markdown version from templates: ```html View Source Download Markdown ``` The `get_markdown_url()` method returns: - The `.md` URL (e.g., `/docs/guide.md`) if the page is a markdown page or an HTML page with a companion `.md` file - `None` if the page has no markdown URL or the feature is disabled ## Frontmatter Pages support YAML frontmatter for configuration: ```yaml --- title: Custom Title template_name: my-template.html render_plain: true custom_var: value --- ``` Available frontmatter options: - `title`: Page title (defaults to filename) - `template_name`: Custom template to use - `render_plain`: Skip template rendering (for markdown) - `url`: Redirect URL (for .redirect files) - `temporary`: Redirect type (for .redirect files) - Any custom variables accessible via `page.vars` ## Custom views You can extend the view classes to customize page rendering: ```python from plain.pages.views import PageView class CustomPageView(PageView): def get_template_context(self): context = super().get_template_context() context["extra_data"] = self.get_extra_data() return context ``` The main view classes are: - [`PageView`](https://plainframework.com/docs/plain-pages/plain/pages/views.py?llm#PageView): Renders HTML and Markdown pages - [`PageRedirectView`](https://plainframework.com/docs/plain-pages/plain/pages/views.py?llm#PageRedirectView): Handles redirects - [`PageAssetView`](https://plainframework.com/docs/plain-pages/plain/pages/views.py?llm#PageAssetView): Serves static assets - [`PageMarkdownView`](https://plainframework.com/docs/plain-pages/plain/pages/views.py?llm#PageMarkdownView): Serves raw markdown content ## Settings | Setting | Default | Env var | | ---------------------- | ------- | ------- | | `PAGES_SERVE_MARKDOWN` | `False` | - | See [`default_settings.py`](https://plainframework.com/docs/plain-pages/plain/pages/default_settings.py?llm) for more details. ## FAQs #### How do I use a custom base template for markdown pages? Set the `template_name` in frontmatter to specify your own template. Your template should include `{{ page.content }}` to render the markdown content. #### Can I use template tags and filters in markdown files? Yes. Unless you set `render_plain: true` in the frontmatter, markdown files are processed as templates first, then converted to HTML. You can use any template tags and filters available in your project. #### How do I access frontmatter variables in templates? Custom frontmatter variables are available through `page.vars`. For example, if your frontmatter includes `author: Jane Doe`, you can access it with `{{ page.vars.author }}`. #### Why isn't my page showing up? Check that your file is in a `templates/pages/` directory and doesn't contain `.template.` in the filename. Template files are intentionally skipped. ## Installation Install the `plain.pages` package from [PyPI](https://pypi.org/project/plain.pages/): ```bash uv add plain.pages ```