Content Concept

Note: In itself, this is marked as complete since it works already, although we will be making many additions, the basic concepts will remain the same.

The content is organized on a per page basis. It is formed of one to many elements. We use the Qt XSLT library with XML templates to finalize the output of a page with the dynamically generated data. (Details see Content Object in Cassandra (Content Tree)).

cTemplate basics1

The cTemplate library is used to transform inline tags with a corresponding value.

The system offers a set of default tags such as {{DATE-YEAR}} which is replaced with the current year. It also offers variables specific to the current page environment. For example, a page has an author (or a list of authors,) a last modification date, a creation date, a version number (<branch>.<revision>), etc.

cTemplate accepts a map of variables. The name of the variable is DATE-YEAR, the content of the variable is the current year.


Organization of the content of a page in term of branches, revisions, and drafts.
Click to see a version showing branch details.

The data in the Cassandra database is organized per page: the URI of a page is its key.

The data has four main locations at this point:

1. Page

In the content table, the URI maps one to one to a page. For example:

The content table defines the current branch and revision displayed to the visitors. It also includes information about other branches, revisions, locales (language/country) and defines global parameters such as whether a page can include sub-pages (is final or not), whether the sub-pages are considered dynamic, and the short URI for this page.

2. Secret

The secret table is used in a way similar to the revision table: we save user data in that table. However, we use the URI as the key to access the data, just like in the content table:

The difference between the revision and the secret table is that the secret table is a one to one relationship to the page URI which means that you do not benefit from revision backups. Also the functions that allow various system to access the user entered data, such as the filter module, does not give you access to the data saved in the secret table.

The secret table can be used to save information such as password and keys that should never be published without a very specific set of rules defined in a plugin. The user account do not use this table for the user password. Instead, the user password is saved in the users table. It is extensively used by payment processing plugins though.

3. Branch

In the branch table, each page has any number of branches. A branch defines the main characteristics of the page such as its type, list content, and other similar parameters.

The key to a branch is defined by the page URI followed by a hash (#) and the branch number. For example:

4. Revision

In the revision table, each branch has any number of revisions. Revisions are also related by their key to the page the branch is from.

A revision is created each time the user saves a page to the database. This allows for easy tracking of what was done to the page and we can restore an older revision if needed.

The key to a revision also includes the locale information. The locale is the language and optionally the country that this revision pertains to. For example, an English version that uses the word "color" can be marked as "en_US". For England, another version can be created where you spell the word "colour" instead. That other revision will be marked with locale "en_UK". Note that in most cases you probably only want to define a language ("en") and not the country.

So, the key for a revision is the page URI followed by a hash (#), the locale or just the language ("en_US" or just "en"), a slash (/) the branch number, a period (.), and finally the revision number. The language can be set to "xx" to represent the neutral language (i.e. an image or a movie without writing or spoken words.)

Note that it is possible to create revisions without a locale. This is only used when a page cannot be translated. For example, when you upload a CSS file, that file is never translated to any human languages and thus it can be saved without the locale.

For a page that has no specific language, but could get translated at a later time (i.e. a page considered as having a neutral language) use the language "xx".

Important Note: The special names "user" and "suggestion" are reserved for user drafts and suggestions (see below.)

5. Attachment

A page can represent a file, also called an attachment. In that case, the revision table includes a link to the files table. The link is the MD5 sum of the file. This allows us to save a lot of space in the event the exact same file is uploaded hundred of times by many different people or the same person. In all those cases the exact same file will be referenced. The files table includes a link back to all the pages that reference it.

The page with a file represents an attachment to its parent page. They actually appear as attachment of the parent page when viewing/editing the parent.

Attachment pages are always viewed as final although that does not prevent the use of sub-paths to access variations of the attachment (i.e. the image up side down, flipped, rotated, resized; a Word document using the ODT or PDF formats; etc.)

6. Draft

A draft is similar to a revision in what it accepts in its row. You can save one draft per user per page. The idea is simply to avoid creating new revisions each time you save a small change when you're not yet finished to work on a page. Actually, in most cases drafts are saved automatically for you.

The draft uses a key that includes the page URI, a hash (#), the word "user", followed by a slash (/) and the user identifier, another slash (/), and the branch number. (<protocol>://<uri>#user/<id>/<branch>)

This represents the draft of user 17 on branch 3. We expect the system to automatically remind users that they have a draft when they go to a page with such.

7. Suggestions (see detailed branch / revision relations)

Similar to a draft, although not attached to a specific user, a page can receive suggestions (corrections offered by visitors.)

The suggestion uses a key that includes the page URI, a hash (#), the word "suggestion", followed by a slash (/), the branch number, a period (.), and a suggestion number. The suggestion row includes a reference to the specific revision and locale to which it applies but its key does not include the revision or locale information.

A suggestion can also be marked as New, Spam, Rejected, or Applied. When marked Applied, the suggestion includes a reference to the revision to which it was applied and the resulting revision.

(This feature is not yet implemented, plus we'd have to take in account the fact that stupid spammers will make use of the suggestion feature to spam our users.)


Some of the elements are globally defined for the entire website. This is generally referenced as the theme. For example, you may want to show a small list of the recent comments that appeared on your website. This will certainly be shown in the same area on all pages. This is considered to be part of the global environment of the website.

Theme Selection

In most cases, the theme is selected by the administrator when setting up a new website.

However, it is likely that different sections of the same website need to look different from each others. In that case each section makes use of a different theme (it can also be the same theme, but composed of somewhat different divisions.)

The selection of the theme can be based on many parameters, including the sub-domain, the device used to connect, or path selectors. For example, you may want a product page to look like a landing page. That very specific product page can thus be set to show a specific global theme. In this case, it is a page attribute rather than a selector feature.

A page is linked to a theme which in effect defines the theme selection for that page. If the page is not directly linked to a theme, then the system checks the parent content of the page and uses that parent content theme. Again, if the parent does not have a theme selection, then the grand parent of the page is used. This goes on until the Root of the tree is reached and a default theme is used if necessary.


Each page can use a different layout. The layout of a page is how and where and what data will be shown on that page. This is different from the theme which only offers a wide area where you can display data. The reason for having a layout separate from the theme is to offer the end users an easy way to change the look and feel of their pages without having to always rely on each theme to offer hundreds of layouts (i.e. if many default layouts are offered in the system, then it becomes a lot easier to handle them than having each themer create them each time. A theme should still be allowed to offer some specialized layouts specific it it's look (and offered feel.) For example, you may have a special location for the your Search Box or your social media icons.

By default, the layout has no say on the global theme definition so that way most of the pages of your websites look alike which is a good thing.

However, you may not want to show a user login box on the plain login page as it would be the same form shown twice...2 In other words, that specific global box may need to be hidden in that specific circumstance.

All the boxes available on a given page are shown to the administrators of that page. It includes a small square at the top-right. When the square is empty, the box is visible. When the square has a cross, the box is not visible in that page. When not visible, only the title of the box is shown to administrators using a different color (i.e. dark red.) This gives the administrators the ability to easily tweak these pages and know exactly that such and such box may appear on such and such page (instead of having to try all the possibilities with 100's of users.)

Layout Selection

Layouts are pre-defined in the system. Column based layout are generally defined using CSS only capabilities (i.e. floating boxes.) More complex layouts may make use of tables to simplify the layout. Especially in some cases you may need to force the size of a box which is generally easier with a table cell than a div in floating columns.

In order to allow any number of layouts, we use external layout files. The files are basic XHTML files that make use of XSLT. For example, one such file could include a table that looks like this:

<page_content/> <most_recent_comments/>
<similar_page_teaser/> <most_recent_posts/>

In order to make the final result look good, the user who creates such layouts will want to define specific sizes for such and such cell, maybe even use scrollbars within the page.

Layers of Layouts

There is no need for the system to offer a way to include layouts inside other layouts. This is because you can offer a layout that includes another page which itself uses another layout.


The theme as a whole is 100% similar to a layout. It is just that it is used by the core system and can be changed by the user in a different section. Although it will be possible to specify a theme for a page, that's not directly linked with the page concept per se.

Also, there is one theme per final page. When a page includes another, it does not include the theme, only the page layout and contents. This is the difference between calling (inserting) the <page_content/> and a full <page/> in your XSLT variables.

  • 1. cTemplate will not be used since XSLT is enough to do the job offered by cTemplate plus much more.
  • 2. This is probably a bad example since the system will manage that specific case automatically, yet I think that's a good example to understand the concept.

Snap! Websites
An Open Source CMS System in C++

Contact Us Directly