Paint the Web - a micro-Blog in .md about Dev, Web and more

Content Management in Flood\Canal

Content management is about managing the content that is structured in to sections which hold articles.

An article is any page that will be displayed. The <article-id>.json is the meta file and the <article-id>.md the content file.

Classes

For handling the content, four main classes are responsible.

  • Namespace: Flood\Canal\Feature\Content
  • Content\Content beholds the whole content and serves as api/container
    • match() determines the active content from the request and match
    • getArticle($id) single article fetcher by ID, uses index
    • getSection($id) single section getter
    • getSection($id)->getArticle($id) single article getter, used to get article of that section
  • Content\Section beholds which section exist and for each section the article, is accessible from Content
  • Content\Article beholds the main content of one page, is accessible from Section and Content, depends on what data you have to get the article
    • getBlock($id = null) gets one or all blocks
  • Content\DocTree\Block beholds single blocks, like sidebar banners etc. which where assigned to one article, is accessible from Article

Default Folders

Default folder for templating.

The feature file will setup default paths and namespaces.

Blocks and Markdown files are Twig enabled by default.

Section and Articles

Adding new Content

A section is a collection of articles, but each article is also independent in some ways.

They are added in _content.php:

They could directly be set as an array during the initializing of a section addSection, or later with getSection($id). As both are returning an instance of Section. A section could only be added once, if there will be added another section with the same name, it will be overwritten.

The ID of the section will be used as the folder containing the article files, you could specify for each section another folder that will be added before the section. Need to be with trailing slash.

<setPath-path/><section-id>/
<section-id>/

The ID of the article will be used to as the file name, when file not defined as parameter.

Section->addArticle could receive ($id, $folder = '', $file = '', $tag = []) and Section->addArticleList the array like:

<?php
[
    [
        'id' => '<article-id>',
        'tag' => [], // optional, recommended
        'folder' => '<article-folder>', // optional
        'file' => '<article-file>', // optional
    ]
];

Example

<?php
/*
 * Folder structure will be defaults, 'folder_structure' = 'same'
 */
$frontend->content->addSection('page')->setPath('demo/')->addArticleList([
    [
        'id' => 'home',
    ],
]);
/*
 * /data/content/demo/home.json
 * /data/content/demo/home.md
 */

$frontend->content->addSection('law')->setPath('law/');
$frontend->content->getSection('law')->addArticle(/*id*/ 'imprint-en', /*tag*/ ['path' => 'law/imprint'], /*folder*/ 'imprint');
/*
 * /data/content/law/imprint/imprint-en.json
 * /data/content/law/imprint/imprint-en.md
 */

$frontend->content->addSection('misc');
$frontend->content->getSection('misc')->addArticle('contact');
/*
 * /data/content/contact.json
 * /data/content/contact.md
 */

Tag's and Wiring to Routes

The easiest way for small pages is to use autowiring. For complex routes or more than a handful articles it is recommended to use tag's.

autowiring

At autowiring the article ID is treated as unique at all existing articles, meaning an article overview can only be existing in any section, only the last added article will be matched.

The article id could be made of:

  • the path part of the request URL
  • the ID of the route $frontend->match['_route'], that's the index of the route you have set in $route->addList()|add() see _route.php

The path part wiring will win if both would match.

Tag

Tags are controlling exactly when an article is active, instead of using the article id for autowiring, using tags on all routes results the possibility to name multiple articles with the same id (in different sections).

{
  "path":"string",
  "marker": "string|array",
  "route": "string"
}
  • path: will be matched against the URL path part
  • marker: for adding custom logic on searching articles
  • route: the id of the route

Parsed Content

After setting an article, creating the meta and content files, to get the content for one or the active article is easy:

access content from the controller

getContent is deprecated and will be switched with getMainText

<?php
$this->frontend->content->getActiveArticle()->getContent(); // deprecated
$this->frontend->content->getActiveArticle()->getMainText();
$this->frontend->content->getSection('page')->getArticle('about')->getMainText();
$this->frontend->content->getArticle('page', 'about')->getMainText();

access content from the template

{{ content.getActiveArticle().getMainText()|raw }}
{{ content.getSection('page').getArticle('about').getMainText()|raw }}
{{ content.getArticle('page', 'about').getMainText()|raw }}

This will execute the .md content file at first with Twig and then with Parsedown.

Meta Information

The meta file will be read in each article and not only when needed.

A minimal meta file:

{
  "date": {
    "create": "2017-12-13 12:00",
    "update": "2017-12-14 12:00"
  },
  "meta": {
    "lang": "en"
  }
}

Recommended minimum:

{
  "date": {
    "create": "2017-12-13 12:00",
    "update": "2017-12-14 12:00"
  },
  "head": {
    "title": "About | New Flood\\Canal Project",
  },
  "meta": {
    "lang": "en",
    "description": "This is the meta description content."
  }
}

With those automatically used in canal-view:

{
  "date": {
    "create": "2017-12-13 12:00",
    "update": "2017-12-14 12:00"
  },
  "head": {
    "title": "About | New Flood\\Canal Project",
    "author": "You",
    "font": "https://fonts.googleapis.com/css?family=Barlow"
  },
  "meta": {
    "lang": "en",
    "description": "This is the meta description content."
  }
}

Getting the meta information

access meta from controller

<?php
$this->frontend->content->getActiveArticle()->meta('date');
$this->frontend->content->getActiveArticle()->meta('date')['create'];
$this->frontend->content->getSection('page')->getArticle('about')->meta('date')['create'];
$this->frontend->content->getArticle('about')->meta('date')['create'];

access meta from template

{{ content.getActiveArticle().meta('date')['create'] }}
{{ content.getSection('page').getArticle('about').meta('date')['create'] }}
{{ content.getArticle('about').meta('date')['create'] }}

Only for `meta` and `head` informations of active article:
{{ head.title }}
{{ meta.description }}

DocTree, Block

The tree is a way of arranging the content of an article in a way so it is possible to change it through another program and split data from the view.

A tree will hold which part should be rendered when, composing meta with templates, using blocks and more.

Block

Modules, Plugins: Any Reusable Component which should be able to use in the Tree.

Needs a block.json where the block is defined, blocks are saved in /data/content/_block/<block-id>, where the folder /data/content/_block/ is added to the View/Templating system as the namespace content_block.

A block needs to be added programmatically, like in _content.php:

<?php

// Adds this block to index: /data/content/_block/intro/block.json
$content->addBlock('intro');

Block Types

Different types of blocks are relying on different type of data, e.g. meta can only receive information which is saved for the meta of the current article.

Types are:

  • meta
  • mainText
  • block