Who this is for. The content modeller deciding where a kind of content should live. Afterwards you can say what each built-in type gives you without building anything, and why choosing a book over a page tree costs nothing in capability.

Four types in one table

Pages, books, units and book pages are stored in one table, pages. The entity Pages\Entities\BasePage uses single-table inheritance: a column named entity records the class of each row, which is one of Pages\Entities\Page, Books\Entities\Book, Books\Entities\Unit and Books\Entities\Page. Everything declared on the base class behaves identically on all four:

  • Slug and position. A slug is unique among the records under the same parent on the same site, and the position orders the siblings. (Slugs)
  • Publishing. The published date is the gate a visitor has to pass, and an unpublish date takes the record down again. (The two gates, Scheduled publishing)
  • Revisions, layouts and areas. The content is on the active revision, which names the layout and holds the layout areas. (Revisions)
  • Custom URLs, tags, categories, language and SEO settings. The same fields, edited in the same panels.
  • Owner and permissions. Every record has an owner and can carry permissions of its own.
  • External id, the free identifier an import uses to find the record again.

So the choice between a page tree and a book is a choice of shape, not of features: a tree for content that readers arrive at one page at a time, a book for content that is read in order.

What still differs

PagesBooks, units and book pages
HierarchyA tree of any depth; any page can be a parentExactly three levels. A book cannot have a parent
TemplateThe template of the layout on the active revisionA book page uses its layout's template. Books and units always render books/books/show.html and books/units/show.html, whatever layout they have, except in a signed-in editor's ?revision= preview
Walking the structuregetParent(), getChildren(), getAllParents()getUnits() on a book, getBook() and getPages() on a unit, getUnit() and getPositionInBook() on a book page
TranslationsA source page and related pagesBook pages only; books and units have a language but no source or related records
Tags and categories in the adminOn by defaultOff by default, a switch for each level
SitemapIncluded by defaultOff by default, a switch for each level

The pages that follow cover each type: Pages and the page tree and Books, units and book pages.

The five content types side by side

Blog posts, FAQ questions and custom entity records live in tables of their own, but they follow the same pattern: a record, a chain of revisions and an active revision that holds the layout areas. What differs is the shape around it.

PagesBooksBlog postsFAQ questionsCustom entity records
ShapeA treeBook, unit, page, in reading orderDated posts in a blogQuestions, listed on FAQ pages that form a treeA flat list, with an optional parent and child definitions
LayoutPer revisionPer book page; fixed templates for books and unitsPer revision, else the blog's post layoutPer revisionOne for the whole definition
Listing routeNoneNonePaged, and by tag, category and author, plus RSS/faq/questions, and by tag and categoryWhen the definition has a path
SitemapYes, by defaultOff by defaultYes, by defaultYes, by defaultNo
From a template_query.findBy_query.findBy_query.findBy_query.findBy_query.findCustomEntityRecordsBy
Approval workflowsYesNoYesYesNo
Unpublish dateYesYesNoNoNo

A blog itself, the container of the posts, is the one content record that is not versioned: its layout areas sit on the blog. Blogs and posts and FAQ pages and questions cover the other two built-in types, and Which type, or none works three real decisions through.