Pages¶
Cubane provides a number of primitives that can be extended to support various structures for your content. The simplest of those structures is a page.
In its simplest form, a page represents a navigable page with a title and content. A page has a URL and one or more content slots.
When a request is made, let’s say /about-us/
, then the content
management system will determine what page corresponds to this url. In its
simplest form, the URL /about-us/
corresponds to the page with the slug
about-us
.
Cubane provides a page model by default, which is
cubane.cms.models.Page
. However, we recommend to declare your own
page model, so that you can add additional properties to CMS pages later in
the process.
To do this, you need to following the same principal that we’ve applied when we set up the settings model.
First, you need to declare a custom page model that is derived from
cubane.cms.models.PageAbstract
:
from cubane.cms.models import PageAbstract
class CustomPage(PageAbstract):
# TODO: Add additional page properties here...
@classmethod
def get_form(cls):
from myapp.forms import CustomPageForm
return CustomPageForm
Likewise a corresponding form needs to be declared:
from cubane.cms.forms import PageForm
class CustomPageForm(PageForm):
class Meta:
model = Settings
fields = '__all__'
Finally we need to point Cubane to the exact class name that shall be used as
the page model for the CMS via the Django’s application setting variable
CMS_PAGE_MODEL
:
CMS_PAGE_MODEL = 'myapp.models.CustomPage'
Again, the given string value is referring to the actual class that is used by Cubane for the page model. The path must include the full path to the class including modules and sub-modules.
Page Templates¶
When creating a CMS page in the backend system, a page template is chosen. The idea is that multiple ways for presenting a page can be offered to content editors.
You may have a layout for a certain type of content and another layout for a different use-case.
Page templates are declared via the Django application setting variable
CMS_TEMPLATES
in the following way:
CMS_TEMPLATES = (
('myapp/page.html', 'Page'),
('myapp/landing_page.html', 'Landing Page')
)
CMS templates are declared like choices: The first column declares the path to the corresponding template file while the second column declares the name of the template as it is being presented by the backend system.
Note
You should not change the path to a template once it has been established. Changing the path will break all existing pages that are still referring to the old path.
Page Slots¶
A CMS page may render a number of content slots. Each content slot can contain arbitrary HTML markup and can be edited by content editors through the backend system by using a rich WYSIWYG editor.
Each content slot must be declared via the Django’s application settings
variable CMS_SLOTNAMES
in the following way:
CMS_SLOTNAMES = [
'content',
'aside'
]
Slot names can be chosen freely, but they should be declared more or less in the order in which they are presented. This may have consequences for some aspects of CMS system, such as the automatic generation of a page’s meta description as further described in section Page Meta Description.
Once a slot has been declared that way, it can be rendered by using the slot
render tag as part of the cms_tags
template library:
{% load cms_tags %}
<!DOCTYPE html>
<html>
<body>
<main>{% slot 'content' %}</main>
<aside>{% slot 'aside' %}</aside>
</body>
</html>
In this example, the page template renders two slots, one with the name
content
and one with the name aside
.
Note
The matching name of the slot and its enclosing HTML tag is coincidental. Slot name and enclosing markup can be chosen freely and are independent of each other.
The slot
template tag renders a slot with the given name based on the
current page. When editing page content via the backend system, a user may
switch between all content slots on the page and can edit their content freely.
Not all slots as declared via CMS_SLOTNAMES
must be rendered by a
page template. Also certain slots may not be rendered under certain
circumstances.
You can test if a slot if empty or not in the following way:
{% load cms_tags %}
<!DOCTYPE html>
<html>
<body>
{% if 'content' in slots or preview %}
<div class="content-slot">{% slot 'content' %}</div>
{% endif %}
</body>
</html>
In this example, the slot with the name content
will only be rendered if
the slot is not empty. The reason why we have this if-statement here is that we
do not want to render the enclosing div element if the slot is indeed empty.
Note
The if condition is also testing for preview mode which is further explained in section Preview.
Page Title¶
A page stores the main title of the page alongside other useful meta data such as the meta title and the meta description.
Most commonly the title of a page is presented somewhere on the page – usually
in between h1
tags, for example:
<!DOCTYPE html>
<html>
<body>
<h1>{{ current_page.title }}</h1>
</body>
</html>
A page must always have a title; the page title cannot be None
or empty.
Paired with content slots this may raise the following issue: Content editors
can simply create headline tags within a slot, so they might introduce another
headline of the same level (h1
) which already exists.
{% load cms_tags %}
<!DOCTYPE html>
<html>
<body>
<h1>{{ current_page.title }}</h1>
{% slot 'content' 1 %}
</body>
</html>
We do not want to have two h1
headlines following each other. On the other
hand, we also do not want content editors having to remember to start headlines
from level 2 onwards.
As a solution, we may pass on an additional argument to the slot
template
tag as a numeric offset by which headlines that are rendered for the slot are
automatically transposed.
Therefore, an offset of 1
would transpose an h1
tag into an h2
tag
and an h2
tag into an h3
tag and so forth.
Likewise, an offset of 2
would transpose an h1
tag into an h3
tag
and and h2
tag into an h4
tag.
Note
The same can be archived by using HTML5 sections, where each section can have its own heading hierarchy.
Page Meta Title¶
The meta title of a page is optional and content editors may provide it or not.
The meta title can be rendered by a template via the meta_title
template
tag as part of the cms_tags
template library:
{% load cms_tags %}
<!DOCTYPE html>
<html>
<head>
<title>{% meta_title %}</title>
</head>
...
</html>
The meta_title
template tag renders the current page’s meta title. If no
meta title is provided then the regular page title is used instead.
Usually, meta titles are written in a specific way, for example:
Pascal | The history of programming languages
In this example, the term Pascal
may refer to the meta title of the current
page while the term The history of programming languages
is referring to
the name of the website as a whole.
The meta_title
tag will automatically construct the entire string based on
the current page’s meta title as well as any information that is provided as
the cubane.cms.models.Settings.meta_name
field as declared by the class
cubane.cms.models.Settings
. If no meta name is declared then the
company name based on the cubane.cms.models.Settings.name
field is used
instead.
If the current page’s meta title already ends with the meta name that is obtained from CMS settings then the meta name is not added another time.
The separator character in between meta title components can be declared via
the settings variable CMS_META_TITLE_SEPARATOR
. By default, the
separator string is set to `` | `` which is a pipe character surrounded by one
single space character.
Page Meta Description¶
Content editors can specify the meta description for a page, but it is an optional field. If the meta description is not specified, the system will automatically generate the meta description based on the content of the page.
This process is based on the content of all page slots that have content
defined for the page. The content is concatenated in the order in which slot
names have been declared via CMS_SLOTNAMES
.
{% load cms_tags %}
<!DOCTYPE html>
<html>
<head>
<title>{% meta_title %}</title>
<meta name="description" content="{{ current_page.meta_description }}">
</head>
...
</html>
Page Meta Keywords¶
In the same way as the meta description, meta keywords can be specified by content editors, but meta keywords are optional. If meta keywords are not specified, then the system will automatically generate those based on the content of the page.
This process is based on the content of all page slots that have content
defined for the page and are declared via CMS_SLOTNAMES
.
{% load cms_tags %}
<!DOCTYPE html>
<html>
<head>
<title>{% meta_title %}</title>
<meta name="description" content="{{ current_page.meta_description }}">
<meta name="keywords" content="{{ current_page.meta_keywords }}">
</head>
...
</html>
Default Page Roles¶
Some CMS pages are so called default pages. For example one page is dedicated to be the homepage of the website. Another page may be dedicated to be the page that is rendered whenever content cannot be found (HTML status code 404).
When rendering templates, the following helper variables are available for testing for default page roles:
Template Variable | Description |
---|---|
is_homepage | True if the current page is the homepage. |
is_contact_page | True if the current page is the contact page. |
is_404_page | True if the current page is the 404 not found page. |
is_enquiry_template | True if the current page is used as the enquiry
confirmation email template. |
The following example demonstrates how one of those variables could be tested in order to change the way a template renders content based on the role of the current page:
{% load cms_tags %}
<!DOCTYPE html>
<html>
<body>
{% if is_homepage %}
{% include 'myapp/elements/homepage_header.html' %}
{% endif %}
</body>
</html>
It is good practice to render page content based on different page roles automatically instead of relying on different page templates. If a page is configured to be the homepage then the page should render itself as the homepage and should not rely on content editors having to change the corresponding page template as well.
Page Hierarchy¶
Pages can be organised within a hierarchy. If enabled, a page can be a parent page of another page. By default this feature is disabled in order to keep the structure very simple. Therefore by default there is only a number of pages next to each other without any hierarchy.
However, page hierarchy can be enabled in application settings via the
PAGE_HIERARCHY
settings variable:
PAGE_HIERARCHY = True
By enabling the page hierarchy feature, the backend allows content editors to arrange pages into a hierarchy by either choosing a specific parent page for each page or by using drag and drop to arrange pages into a hierarchy.
With page hierarchies enabled, the template variable hierarchical_pages
represents a list of all direct child pages of the current page, which can be
used to generate a list for example:
<!DOCTYPE html>
<html>
<body>
{% if hierarchical_pages %}
<ul class="child-pages">
{% for child in hierarchical_pages %}
<li><a href="{{ child.url }}">{{ child.title }}</a></li>
{% endif %}
</ul>
{% endif %}
</body>
</html>
The direct parent of a page can be determined via the parent property:
<!DOCTYPE html>
<html>
<body>
{% if current_page.parent %}
<a href="{{ current_page.parent.url }}">Parent</a></li>
{% endif %}
</body>
</html>
Similarly, the page_path
property can be used to retrieve a list of all
page instances from the root page down to the current page. This can be used to
generate breadcrumbs very easily:
<!DOCTYPE html>
<html>
<body>
<ul>
{% for page in current_page.page_path %}
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
{% endfor %}
</ul>
</body>
</html>
Likewise, the navigation system provides additional information for each navigation item to be able to obtain a list of child pages as part of the navigation. Please refer to section Navigation Item Hierarchy for more information about hierarchies within the navigation system.
The query for determining the direct child pages of the current page can be altered. Please refer to section :ref:`` for more information.