PageFactory
What is PageFactory?
PageFactory is a plugin for the Kirby CMS.
→ See Kirby in a nutshell for a compact intro into to Kirbyj CMS.
What's the Goal?
PageFactory's goal is to simplify and streamline the task of creating web pages.
To pick just one of many aspects:
Most of what defines a web page is controlled from a single file, namely a MarkdownPlus file.
This way, the webmaster can define, resp. influence content (markdown, variables, macros), appearance (CSS), behavior (JS) and even side effects, if required.
Moreover, PageFactory (and optionally its plug-ins) provide basic buidling blocks, thus avoiding a lot of "re-inventing the wheel".
Installation and Jumpstart
→ See chapter Installation
What's the Idea?
Let's take a step back: what are the fundamental aspects of any web page?
- Contents & Semantics
- Page Structure
- Visual Appearance
- Frontend behaviour
- Business Logic
It is good practice to keep these aspects separated as much as possible, both during development as well as later on while maintaining a website.
As shown in the following table, there is a pretty nice match between these aspects and related formalisms, i.e. programming languages:
Aspect | Encoded as |
---|---|
Contents & Semantics | Markdown |
Page Structure | HTML |
Visual Appearance | CSS |
Frontend behaviour | JavaScript |
Business Logic | PHP |
The challenge for any CMS is to support practical and elegant ways for keeping things (i.e. the elements above) tidy and user friendly.
Let's see, how PageFactory approaches this.
Example
Here we compare the "classical template" approach (typically used in Kirby and other CMSs) with PageFactory.
The second box shows a Twig template which calls up values that PageFactory has prepared in the background.
Note: Using Twig is optional, but actually an elegant way to deploy PageFactory.
Kirby Snippet snippets/header.php
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title><?= $site->title()->esc() ?> | <?= $page->title()->esc() ?></title> <?= css([ 'assets/css/prism.css', 'assets/css/lightbox.css', 'assets/css/index.css', '@auto' ]) ?> <link rel="shortcut icon" type="image/x-icon" href="<?= url('favicon.ico') ?>"> </head> <body> <header class="header"> <a class="logo" href="<?= $site->url() ?>"> <?= $site->title()->esc() ?> </a> <nav class="menu"> <?php foreach ($site->children()->listed() as $item): ?> <a <?php e($item->isOpen(), 'aria-current ') ?> href="<?= $item->url() ?>"><?= $item->title()->esc() ?></a> <?php endforeach ?> <?php snippet('social') ?> </nav> </header> <main class="main">
Twig Template default.twig
<!DOCTYPE html> <html lang="{{ page.lang }}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>{{ page.pageTitle }}</title> {{ snippet('favicon') }} {{ page.headInjections|raw }} </head> <body class='{{ page.bodyTagClasses }}'> <header class="header"> {{ page.pageTitleLink|raw }} {{ nav({ type: 'top' }) }} {{ page.social|raw }} </header> <main class="main"> {{ page.pageContent|raw }} </main> {{ page.bodyEndInjections|raw }} </body> </html>
Easy to see that the second box looks way cleaner. And it is easier to read and understand.
To be fair, though, both boxes are not totally equivalent: the second box already contains a complete page template, while the first box will need at least a footer.php template and one that ties them together.
Note that the lines {{ page.headInjections|raw }}, {{ page.pageContent|raw }} and {{ page.bodyEndInjections|raw }} is where most of PageFactory's magic happens.
PageFactory in a Nutshell
Basics
The PageFactory plugin works in the background and provides lots of services, which make life easier for web developers and authors.
You start from a simple template which basically contains everything that's common to all pages within the website. Preferably, use the Twig plugin to simplify that step even further.
Some portions of said template may still be parameterized, be it statically or just as well dynamically.
Example: {{ page.lang }} will be rendered as the currently active language code.
{{ nav({type: 'top'}) }} is an example of a parameterized Macro call.The main part of any web page, i.e. the actual content, is rendered by {{ page.pageContent }}. Thus, there aren't many reasons to use more than one template. The task of composing a page out of a multitude of elements, blocks and fields etc. is shifted into the markdown .md source file(s).
Two main mechanisms support this:
- An extension of Markdown, named MarkdownPlus
- A replacement mechanism (similar to and interoperable with Twig) that supports Variables and Macros.
As normal in Kirby, page content is defined inside the file system, i.e. in folders under content/. Each page resides in its own folder.
Page content is defined in .md file(s). PageFactory loads, compiles and renders all .md files found in the page folder. The filenames just control the order of appearance. Apart of that you can name them whatever reflects their content or purpose best.
As PageFactory wraps the HTML output of each source file in a <section> tag, individual styling can be applied. This provides a first basic mechanism for assembling complex pages.
Apart of {{ page.pageContent }}, PageFactory provides further elements to templates:
- {{ page.lang }}
- {{ page.headInjections }}
- {{ page.bodyTagClasses }}
- {{ page.bodyTagAttributes }}
- {{ page.bodyEndInjections }}
- and some others
→ These variables further reduce the need for multiple templates – you'll hardly ever need more than one.
Each .md file may contain a Frontmatter section which permits to control lots of things:
- adding styles and javascripts
- instructing the browser to load resource files (.css, .js, etc)
- defining HTML head tags: description, keywords, author, robots etc.
- defining/overriding variables
- controlling visibility depending on time/date
- and much more…
MarkdownPlus
PageFactory relies on MarkdownPlus, an extended Markdown compiler.
Standard Markdown is very limited by design.
With only a few additional syntax elements MarkdownPlus extends the expressiveness significantly, most notably by allowing to wrap content in blocks (compiled to <div> tags), which can thus be styled by CSS or manipulated by Javascript.
In addition, a attribute injection syntax let's you apply ids, classes and any other HTML attributes without leaving markdown.
Just for the sake of completness:
Of course you could embed HTML code like <div></div>
in your markdown source. However, that is both ugly and prone to cause some awkward suprizes…
Basic Operation Scheme
It is worth noticing that a normal Kirby template will echo (i.e. output) its output line by line.
In contrast, PageFactory finishes its job before the template (whether Kirby or Twig) even starts rendering. Thus, the entire page content is compiled in memory (in a PHP variable).
Thus, Macros invoked inside the page's markdown source can for instance retroactively add code to the <head> element (e.g. to load a style sheet).
With Kirby's normal rendering scheme that would be rather difficult.
Build-in Tool-Chain
PageFactory has several tools on board that work out of the box:
- MarkdownPlus-Compiler
- SCSS-Compiler
- SmartyPants
- Icons/Emojis
They work in the background without the need to configure or invoke them. (Caching avoids unnecessarily processing overhead.)
Variables and Macros()
Variables can be defined in multiple ways: statically in dedicated resource files, in Markdown files or dynamically by PageFactory itself or custom Macros etc.
Variables are inherently language-aware: values are automatically rendered according to the currently active language. No need to worry about language filters or the like each time you use a Variable.
Variables are accessible in Twig as {{ page.varName }} resp. in PHP-Templates as <?= $page->varName()?>.
Fields defined in the page's meta-file are accessible in .md sources as normal Variables,
e.g. fieldText:
as {{ text }}.
Macros are implemented as simple PHP-functions which return HTML strings. PageFactory provides a set of useful Macros. And it is easy to code your own Custom Macros. They serve the same purpose as Kirby's Snippets. Macros are automatically available in Twig as Twig-functions.
Macros can invoke side effects (unlike snippets). For instance, a macro can request loading of a CSS-file, which leads to code automatially added to the
<head>
tag.
All in One
The above mentioned features MarkdownPlus and Frontmatter allow to keep almost everything that makes up a web page inside one .md file: HTML, CSS, JS. (As well as server-side PHP-code via custom Macros.)
Whether that's good or bad depends on the way you use it. But it can be pretty beneficial to keep everything close together, as opposed to having bits and pieces spread all over the file system.
When/How is Pagefactory Useful?
Rapid Prototyping
The All in One scheme allows to keep almost everything (regarding a page) inside one file, be it styling or adding JavaScript etc.
You can whip up a web page or even an entire site with lightening speed.
Ad Hoc Websites
PageFactory has proven useful for somewhat temporary websites, such as the announcement of an event.
Dedicated plug-ins for PageFactory could, for instance, provide functionality targeted to event management, dramatically reducing the complexity involved.
Casual Webmasters
While professional web developers tend to use well constructed and optimized tool-chains, more casual webmasters may find their task significantly simplified when using PageFactory, as a lot of useful tools are seemlessly integrated without explicit configuration.
Everything works out of the box and there is a relatively smooth learning curve.
State of the Project
This project is currently in beta state. First of all it is meant as a prove of concept.
Additional development resources will be required to reach readiness for producive systems. Support is always welcome!
Hint for Visitors of this Website
Comments
Please send comments regarding bugs and possible improvements to webmaster@pagefactory.info.