Website

Pages and forms

MarketplaceContent and documentsVersion 0.2.0manifest

What it is for ​

Hold the content of a public website: pages, menus, blog posts and the form submissions visitors send. This app stores and organises content; something else renders it. Publishing needs approval.

What the package does and does not do ​

Content for a public website: pages with a slug and a draft, published, archived flow, navigation menu items, blog posts with a byline and a publish date, translations of both, and the form submissions visitors send in. When the instance runs with the public site enabled it serves the published content to visitors as a server-rendered website with SEO and no login; only the fields marked public are ever visible to them. Publishing makes content public and needs a human approval, agents may only propose it. Senders are personal data and are never public.

Models ​

website_page ​

A page of the website

Read group: website.user. Write group: website.user.

FieldKindData classPersonal dataGroupAgents seeDescription
titletextnonenowebsite.userin clearPage title
slugtextnonenowebsite.userin clearURL path of the page without slashes at the ends, lowercase with dashes, for example about-us. The page with slug home is the front page
bodylongtextnonenowebsite.userin clearPage content in Markdown (a safe subset: headings, lists, links, emphasis, code, quotes, tables)
seo_titletextnonenowebsite.userin clearTitle shown in search results; empty means the page title
seo_descriptiontextnonenowebsite.userin clearDescription shown in search results
published_ondatenonenowebsite.userin clearDay the page went public (YYYY-MM-DD)
stateselect (draft, published, archived)nonenowebsite.userin clearPage status: draft, published, archived

website_menu_item ​

An entry of the site navigation

Read group: website.user. Write group: website.manager.

FieldKindData classPersonal dataGroupAgents seeDescription
labeltextnonenowebsite.userin clearText shown in the menu
urltextnonenowebsite.userin clearWhere the entry leads: a page slug starting with a slash or a full address
parent_idref → website_menu_itemnonenowebsite.userin clearThe entry this one is nested under; empty for a top-level entry
sequencenumbernonenowebsite.userin clearOrder among its siblings, lowest first
visibleboolnonenowebsite.userin clearWhether the entry is shown
new_windowboolnonenowebsite.userin clearWhether the link opens in a new window

website_blog_post ​

A blog post

Read group: website.user. Write group: website.user.

FieldKindData classPersonal dataGroupAgents seeDescription
titletextnonenowebsite.userin clearPost title
slugtextnonenowebsite.userin clearURL part of the post, lowercase with dashes
author_nametextpublic_directoryyeswebsite.usermaskedName of the author, for the team's own records
bylinetextnonenowebsite.userin clearAuthor line shown publicly, for example the team or brand name; use a name here only if the person agreed to it
summarytextnonenowebsite.userin clearTeaser shown in listings
bodylongtextnonenowebsite.userin clearPost content in Markdown (a safe subset: headings, lists, links, emphasis, code, quotes, tables)
tagstextnonenowebsite.userin clearComma-separated tags, for example news,product
published_ondatenonenowebsite.userin clearDay the post is dated (YYYY-MM-DD)
stateselect (draft, published, archived)nonenowebsite.userin clearPost status: draft, published, archived

website_form_submission ​

A message a visitor sent through a form on the site

Read group: website.user. Write group: website.user.

FieldKindData classPersonal dataGroupAgents seeDescription
form_nametextnonenowebsite.userin clearWhich form it came from, for example contact
sender_nametextinternalyeswebsite.usermaskedName the visitor gave
sender_emailtextinternalyeswebsite.usermaskedEmail address the visitor gave
sender_phonetextinternalyeswebsite.usermaskedPhone number the visitor gave
messagelongtextinternalyeswebsite.usermaskedWhat the visitor wrote
source_pagetextnonenowebsite.userin clearSlug of the page the form was on
submitted_ondatenonenowebsite.userin clearDay of the submission (YYYY-MM-DD)
consent_givenboolnonenowebsite.userin clearWhether the visitor ticked the consent box for being contacted
stateselect (new, handled, spam)nonenowebsite.userin clearHandling status: new, handled, spam

website_page_translation ​

A page translated into another language; the public site shows it to visitors who read that language

Read group: website.user. Write group: website.user.

FieldKindData classPersonal dataGroupAgents seeDescription
page_idref → website_pagenonenowebsite.userin clearThe page this translates
langselect (en, de, fr, pl, fi, sv, es)nonenowebsite.userin clearLanguage of the translation: en, de, fr, pl, fi, sv or es
titletextnonenowebsite.userin clearTranslated page title
bodylongtextnonenowebsite.userin clearTranslated page content in Markdown
seo_titletextnonenowebsite.userin clearTranslated title shown in search results
seo_descriptiontextnonenowebsite.userin clearTranslated description shown in search results
publishedboolnonenowebsite.userin clearWhether the translation is shown; it is only reachable while its page is published

website_blog_post_translation ​

A blog post translated into another language

Read group: website.user. Write group: website.user.

FieldKindData classPersonal dataGroupAgents seeDescription
post_idref → website_blog_postnonenowebsite.userin clearThe post this translates
langselect (en, de, fr, pl, fi, sv, es)nonenowebsite.userin clearLanguage of the translation: en, de, fr, pl, fi, sv or es
titletextnonenowebsite.userin clearTranslated post title
summarytextnonenowebsite.userin clearTranslated teaser
bodylongtextnonenowebsite.userin clearTranslated post content in Markdown
publishedboolnonenowebsite.userin clearWhether the translation is shown; it is only reachable while its post is published

Workflows ​

website_page ​

ActionMovesWho may run itApproval
website_page.publishstate: draft → publishedwebsite.manageryes
website_page.unpublishstate: published → draftwebsite.managerno
website_page.archivestate: published → archivedwebsite.managerno

website_blog_post ​

ActionMovesWho may run itApproval
website_blog_post.publishstate: draft → publishedwebsite.manageryes
website_blog_post.unpublishstate: published → draftwebsite.managerno
website_blog_post.archivestate: published → archivedwebsite.managerno

website_form_submission ​

ActionMovesWho may run itApproval
website_form_submission.handlestate: new → handledwebsite.userno
website_form_submission.mark_spamstate: new → spamwebsite.userno

Permission groups ​

Groups used by this app:

  • website.manager
  • website.user

Approval steps ​

Steps an agent can only propose:

  • website_page.publish
  • website_blog_post.publish

What agents can and cannot do ​

An agent can read, search, create and update records of this app, and run the actions that need no approval, within the permission groups of its token.

It can only propose these steps, and a person must approve them: website_page.publish, website_blog_post.publish, website_page.delete, website_menu_item.delete, website_blog_post.delete, website_form_submission.delete, website_page_translation.delete, website_blog_post_translation.delete.

Personal data is masked as placeholder tokens: website_blog_post.author_name, website_form_submission.sender_name, website_form_submission.sender_email, website_form_submission.sender_phone, website_form_submission.message.

Dependencies ​

None.

Install ​

Install it from the Customize app (Marketplace), or from the command line:

bash
obop modules install-from website

Needs a database and administrator rights.

Build your own ​

The module guide shows how apps like this one are written