Skip to content
V
For developers
Architecture, conventions, the core and security
Modules / Blog

Blog#

The site's editorial content — articles, news, events, galleries, carousels, a guestbook and a contact form. The code lives in app/UI/Api/Blog/, the front end in app/UI/Front/Blog/.

The blog is also the system's reference module: it was the first content wired into Elasticsearch and its front presenter is the model for splitting into traits. Anyone looking for how something is done properly in this CMS starts here.

What the module is made of#

Group Entities Note
content Article, News, Event, Intro plus their *Text each has its own category and listing
media Gallery + GalleryAssetRel, Carousel + CarouselItem
taxonomy Category (a tree), Tag (a flat list)
interaction Guestbook + GuestbookMessage, ContactMessage, ArticleDiscussionMessage
extras FlashMessage, ArticlePollRel, ArticleAdvertRel links to polls and advertising

Two models to copy from#

Model File Why this one
an Elasticsearch source app/UI/Api/Blog/Models/Search/ArticleDocumentSource.php the article was the first content wired in; there are four sources today and all derive from it
splitting a presenter into traits app/UI/Front/Blog/Presenters/Traits/Inits/, Lists/, Details/ one of the few presenters where the split follows the convention

In detail: Elasticsearch and Code conventions.

Do not copy patterns from the guestbook

It is the oldest part of the module and some of its code is still in the previous generation's shape. It looks like a valid model because it is the same module — but it is not.

Categories and tags#

Categories form a tree and are reflected in URLs; tags are a flat list and only label.

A tag is cheaper than a category

A category changes the structure and the URLs — and with them the translations, the sitemaps and inbound links. When labelling is enough, use a tag.

Blog categories have a GLOBALLY unique href

cms_mod_blog_category_texts and cms_mod_blog_article_category_texts carry UNIQUE(href)without the language. The other category tables in the system correctly have UNIQUE(href, language_id). Two categories in different languages therefore cannot share an address here, and Czech and Slovak share plenty of words (doprava, zahrada). It surfaces only when the second language is created, as Duplicate entry 'doprava' for key 'ind_href' — a collision check before the insert therefore has to run without a language filter.

Multilingual content#

The texts live in a child entity, one per language (ArticleText, NewsText, …).

An empty translation beats the fallback

A stored empty string is a valid value, so it wins over the fallback and the element comes out with no name. Either translate it or do not create the row at all — in detail Translations.

A text entity has a derived identity

It has no key of its own — it is composed of the parent and the language. A missing use ORM in such an entity surfaces silently: the mapping is not loaded and the entity behaves as if it had no columns.

Comments, ratings and polls#

The blog does not handle them itself — they are shared components from the Base module (Comment, CommentThread, Rating, RatingThread, Poll).

Changing a shared component affects three other modules

Comments and ratings are used, besides the blog, by the e-shop (products), classifieds and the company catalogue. A fix "just for articles" shows up everywhere — and only gets tested by whoever remembers to.

User-entered text is an XSS trap

addSimpleEditor() sanitises nothing by itself. Rich text has to be purified in the Api beforeSave, plain text is printed through |breaklines. In detail: Forms.

Scheduled tasks#

Endpoint What it does Recommended interval
/cron/blog/elastic/sync incremental index synchronisation every 10 min
/cron/blog/elastic/reindex a full reindex nightly
/cron/blog/sitemap/{article,event,news} content sitemaps nightly
/cron/blog/sitemap/{article,event,news}-category category sitemaps nightly

Where to look#

I want Where
the model search source app/UI/Api/Blog/Models/Search/ArticleDocumentSource.php
the model presenter split app/UI/Front/Blog/Presenters/Traits/
the content managers app/UI/Api/Blog/Models/Managers/
the shared comments and ratings app/UI/Api/Base/Models/Entities/
the cron tasks app/UI/Cron/Blog/Presenters/

Follow-up chapters: Elasticsearch · Discussion · Translations · Code conventions