Portal Pages
Frappe Framework not only provides a rich admin interface via the Desk which is an SPA but also static server rendered web pages. These pages are generally built for your website visitors. They can be public or can require login.
Adding pages
Every frappe app including frappe comes with a
www
folder which directly maps
to website urls. Here is what the directory structure looks like:
frappe/www
├── about.html
├── about.py
├── contact.html
├── contact.py
├── desk.html
├── desk.py
├── login.html
├── login.py
├── me.html
└── me.py
This structure enables the routes
/about
,
/contact
,
/desk
,
/login
and
/me
.
To add your own page, just add an HTML file in the
www
folder of your app.
There are multiple ways to organize these portal pages. For example,
custom_app/www
├── custom_page.html
└── custom_page.py
Will be rendered on the route
/custom_page
.
To add subpages you can convert your main page into a folder and add its content in an index file. For example,
custom_app/www
└── custom_page
├── index.html
├── index.py
├── subpage.html
└── subpage.py
Will still be rendered on the route
/custom_page
and
/custom_page/subpage
will also be available.
> You can write
.md
files instead of
.html
for simple static pages like
> documentation. This documentation you are reading is written as a markdown file.
Overriding standard pages
Frappe also allows you to override standard pages through your custom app. For
example, to override the standard
/about
provided by frappe, just add a file
named
about.html
in the
www
folder of your app and it will take precedence.
Templating
You can add dynamic content to Portal Pages using Jinja templates. All of the
portal pages extend from the base template
frappe/templates/web.html
which
itself extends from
frappe/templates/base.html
.
Here is what a sample page might look like:
<!-- about.html -->
{% extends "templates/web.html" %}
{% block title %}{{ _("About Us") }}{% endblock %}
{% block page_content %}
<h1>{{ _("About Us") }}</h1>
<div class="row">
<div class="col-sm-6">
We believe that great companies are driven by excellence,
and add value to both its customers and society.
You will find our team embibes these values.
</div>
</div>
{% endblock %}
You can also omit the
extend
and
block
if you want to the use the default
base template.
<!-- about.html -->
<h1>{{ _("About Us") }}</h1>
<div class="row">
<div class="col-sm-6">
We believe that great companies are driven by excellence,
and add value to both its customers and society.
You will find our team embibes these values.
</div>
</div>
Context
Every portal page can have a python controller which will build
context
for
the page. The controller should have the same name as the
.html
or
.md
file
with a
.py
extension.
custom_app/www
├── custom_page.html
└── custom_page.py
The controller should have a
get_context
method which takes a
context
dict,
adds any data to it and then returns it. Here is what a sample page controller
might look like:
# about.py
import frappe
def get_context(context):
context.about_us_settings = frappe.get_doc('About Us Settings')
return context
Usage in template
<!-- about.html -->
<h1>{{ _("About Us") }}</h1>
<div class="row">
<div class="col-sm-6">
We believe that great companies are driven by excellence,
and add value to both its customers and society.
You will find our team embibes these values.
</div>
{% if about_us_settings.show_contact_us %}
<a class="btn btn-primary" href="/contact">Contact Us</a>
{% endif %}
</div>
> Since Portal Pages are built using Jinja, frappe provides a standard > API to use in jinja templates.
List of standard context keys
Here is a list of all the standard keys that can be set in
context
and their
functionalities.
Context Key | Functionality |
---|---|
add_breadcrumbs
|
Add breadcrumbs to page |
no_breadcrumbs
|
Remove breadcrumbs from page |
show_sidebar
|
Show web sidebar |
safe_render
|
Toggle safe_render |
no_header
|
Hide header |
no_cache
|
Disable caching for this page |
sitemap
|
Include/exclude page in sitemap |
add_next_prev_links
|
Add Next and Previous navigation buttons |
title
|
Set the page title |
safe_render
frappe.render_template
does not render a template which contains the string
.__
to prevent running any illegal python expressions. You may want to disable
this behaviour if you are sure that the content is safe. To do this, you need to
turn off safe render by setting the value of
safe_render
key to
False
in
context.
Set context via frontmatter
You can also set values in context using a frontmatter block. Frontmatter blocks can be used to set static values specific to a page like meta tags.
Take a look at the following example:
---
title: Introduction
metatags:
description: This is description for the introduction page
---
# Introduction
This is an introduction page
The above frontmatter block will update the
context
dict with the following values:
{
'title': 'Introduction',
'metatags': {
'description': 'This is description for the introduction page'
}
}
Set context via comments
You can also set some values in context by adding html comments in your pages.
For example by adding
<!-- add-breadcrumbs -->
to your
.html
or
.md
file,
context.add_breadcrumbs
will be set to
True
and it will automatically generate
breadcrumbs based on folder structure.
<!-- add-breadcrumbs -->
<h1>{{ _("About Us") }}</h1>
<div class="row">
<div class="col-sm-6">
We believe that great companies are driven by excellence,
and add value to both its customers and society.
You will find our team embibes these values.
</div>
{% if about_us_settings.show_contact_us %}
<a class="btn btn-primary" href="/contact">Contact Us</a>
{% endif %}
</div>
Here is a list of keys that you can set and their context values:
Comment | Context Value |
---|---|
<!-- add-breadcrumbs -->
|
add_breadcrumbs = 1
|
<!-- no-breadcrumbs -->
|
no_breadcrumbs = 1
|
<!-- show-sidebar -->
|
show_sidebar = 1
|
<!-- no-header -->
|
no_header = 1
|
<!-- no-cache -->
|
no_cache = 1
|
<!-- no-sitemap -->
|
sitemap = 0
|
<!-- sitemap -->
|
sitemap = 1
|
<!-- add-next-prev-links -->
|
add_next_prev_links = 1
|
<!-- title: Custom Title -->
|
title = 'Custom Title'
|
<!-- base_template: custom_app/path/to/custom_base.html -->
|
base_template = 'custom_app/path/to/custom_base.html'
|
Custom CSS and JS
You can add custom CSS and JS for your pages by dropping a
.css
or
.js
file
of the same name.
custom_app/www
├── custom_page.html
├── custom_page.css
├── custom_page.js
└── custom_page.py
Home Page
The home page for your portal can be defined in
- Role
- Portal Settings (this will be for logged in users)
-
Via Hook
get_website_user_home_page
- Website Settings (this will be for non logged in users as well - i.e. Guest)