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