Skip to content

Blog

Flow ID: CF-20 | Module(s): blog, Cms domain | Complexity: Medium

Business Overview

Full blog system with articles, categories, tags, authors, and moderated comments. Articles link to products bi-directionally. Blog has its own _remap() dispatcher that resolves slugs to categories, tags, or articles.

What customers experience:

  • /blog or /blog/all main listing with the first article featured
  • /blog/{article-slug} full article page with related articles, products, comments, author bio
  • /blog/{category-slug} category-filtered article listing
  • /blog/{tag-slug} tag-filtered article listing
  • /blog/{author-slug} author page with their articles (6 per page)
  • /blog/search/{term} search results (Solr-powered, supports live AJAX search)
  • /blog/rss RSS feed of all published articles

Key business behaviors:

  • Publishing: is_published = true AND blog_date <= now() (Future-dated articles are hidden from all users. Only unpublished (draft) articles are visible to logged-in customers.)
  • Category/author/tag deletion blocked if articles exist
  • Optional comments (moderated: pending -> approved/rejected) gated by OTHER.ENABLE_BLOG_COMMENTS registry
  • Blog-product two-way sync configurable (BLOG_PRODUCT_TWO_WAY_SYNC)
  • Builder block integration for rich article content via blogArticle position
  • Content embeddings support: product and product list embeds in article body
  • Hit counter incremented per article view
  • RSS feed with configurable title/description per language via Registry

API Reference

REST Endpoints

MethodPathAuthDescription
GET/rest/cms/blog/articleGuestList articles (filterable, sortable, paginated)
GET/rest/cms/blog/article/{id}GuestGet article by ID
POST/rest/cms/blog/articleBackend (CMS)Create article (multipart -- banner)
POST/rest/cms/blog/article/{id}Backend (CMS)Update article
DELETE/rest/cms/blog/article/{id}Backend (CMS)Delete article
GET/rest/cms/blog/authorGuestList authors
POST/rest/cms/blog/authorBackend (CMS)Create/update author
DELETE/rest/cms/blog/author/{id}Backend (CMS)Delete author
GET/rest/cms/blog/categoryGuestList categories
POST/rest/cms/blog/categoryBackend (CMS)Create/update category
DELETE/rest/cms/blog/category/{id}Backend (CMS)Delete category
GET/rest/cms/blog/tagGuestList tags
POST/rest/cms/blog/tagBackend (CMS)Create/update tag
DELETE/rest/cms/blog/tag/{id}Backend (CMS)Delete tag
GET/rest/cms/blog/commentGuestList comments
POST/rest/cms/blog/commentBackend (CMS)Create/update comment
DELETE/rest/cms/blog/comment/{id}Backend (CMS)Delete comment

Full CRUD for all blog entities with Backend (CMS) auth.

Legacy Storefront

URLMethodDescription
/blog or /blog/allindex()Article listing (9/page, first article featured)
/blog/{article-slug}blogArticle($slug)Single article with related content
/blog/{category-slug}blogCategory($slug)Category listing
/blog/{tag-slug}blogTag($slug)Tag listing
/blog/{author-slug}blogAuthor($slug)Author page (6 articles)
/blog/search/{term}/{page}search()Full-page search results
/blog/search/{term} (AJAX)search() -> liveSearch()Live autocomplete search
/blog/rssrss()RSS XML feed

Code Flow

Step 1: URL Routing via _remap()

File: ecommercen/blog/controllers/Adv_blog.php

  1. all: Routes to index()
  2. Method exists: Direct call (e.g., rss, search)
  3. Category slug match: blog_category_model->getCategoryBySlug() (cached) -> blogCategory()
  4. Tag slug match: blog_tags_model->getTagBySlug() (cached) -> blogTag()
  5. Article slug match: blog_model->getArticleBySlug() (cached) -> blogArticle()
  6. Fallback: 404

Step 2: Article Index

File: ecommercen/blog/controllers/Adv_blog.php::index()

  1. Pagination: Page number from URL, offset calculated as (page - 1) * 9
  2. Query: blog_model->getBlogsList() with is_published=true, blog_date<=now()
  3. Featured article: First article on page 1 is shifted to mainArticle
  4. Sidebar: Categories via getCategoriesFront(), tags via getTagsFront()
  5. Hreflang: Language switcher URLs via lang_uri
  6. Hook: indexExtras() -- empty by default
  7. Tag rendering: getBlogListingRelatedTags() for sidebar tags
  8. Render: blogIndex layout

Step 3: Single Article Page

File: ecommercen/blog/controllers/Adv_blog.php::blogArticle()

  1. Fetch: blog_model->getBlogData($slug, $lang) -- 404 if not found or unpublished (guest)
  2. SEO: Meta tags from article MUI fields
  3. Hreflang: MUI slug lookup per language
  4. Content embeddings: renderBlogContentEmbeddings() -- extracts product/product-list embeds from article description
  5. Products: renderBlogProducts() -- fetches linked products from blog_product table (sorted by priority)
  6. Builder block: blockBuilder->frontRender() for blogArticle position using builder_block_id
  7. Related articles: blogRelativeArticles() for sidebar
  8. Author data: blog_author_model->getAuthorRecord() plus categories
  9. Previous/Next: Navigation links via getPreviousNext()
  10. Slider: Optional slider if slider_id set
  11. Hook: blogArticleExtras() -- loads author, categories, related articles, prev/next by default
  12. Events: blogArticleEvents() -- empty hook for client
  13. Comments: manageBlogComments($blogId)
  14. Hit counter: updateArticleHits($blogId)

Step 4: Comment Submission and Moderation

File: ecommercen/blog/controllers/Adv_blog.php::manageBlogComments()

  1. Feature gate: OTHER.ENABLE_BLOG_COMMENTS registry setting
  2. POST handling: On form submit, validates comment, blog_commenter_email, blog_commenter_name
  3. Save: blog_comments_model->saveComment() -- status defaults to pending
  4. Flash: Success message, redirect to same page
  5. Display: getBlogComments($blogId, 10) -- only shows approved comments, ordered by entry_date DESC

Admin moderation (ecommercen/blog/controllers/Adv_blog_comments_admin.php):

  • List all comments with status filter (approved/rejected/pending), search by content/email/date
  • Single and batch status updates via setReviewStatus() / batchUpdateStatus()
  • Pending count badge via getBlogCommentsCount() (shows "99+" for large queues)

File: ecommercen/blog/controllers/Adv_blog.php::search()

  1. Guard: Empty search term returns 410 Gone
  2. AJAX path: liveSearch($term) -- returns JSON results for autocomplete
  3. Page path: searchPage($term, $pageNumber) -- full rendered search results page
  4. Solr integration: Routes to search_model (v1) or search_model_v2 (v2) based on solrSearch.version config
  5. Results: Paginated articles matching search term, with sidebar categories/tags

Step 6: RSS Feed

File: ecommercen/blog/controllers/Adv_blog.php::rss()

  1. Config: Title and description from Registry BLOG.RSSTITLE / BLOG.RSSDESCRIPTION (per language)
  2. Articles: All published articles via getBlogsList()
  3. Output: XML content type, rendered via blog/rss view template

Domain Layer

ComponentPath
Article Servicesrc/Domains/Cms/Blog/Article/Service.php
Article WriteServicesrc/Domains/Cms/Blog/Article/WriteService.php
Article Entitysrc/Domains/Cms/Blog/Article/Repository/Entity.php
REST Controllerssrc/Rest/Cms/Controllers/BlogArticle.php, BlogCategory.php, BlogTag.php, BlogAuthor.php, BlogComment.php
Legacy Controllerecommercen/blog/controllers/Adv_blog.php
Blog Modelecommercen/blog/models/Adv_blog_model.php (not shown -- main article queries)
Comments Modelecommercen/blog/models/Adv_blog_comments_model.php
Product Link Modelecommercen/blog/models/Adv_blog_product_model.php
Author Modelecommercen/blog/models/Adv_blog_author_model.php
Category Modelecommercen/blog/models/Adv_blog_category_model.php
Tags Modelecommercen/blog/models/Adv_blog_tags_model.php
Admin ControllersAdv_blog_admin.php, Adv_blog_comments_admin.php, Adv_blog_tags_admin.php

Data Model

blog

ColumnTypeDescription
idint (PK, AI)Article ID
blog_author_idint (FK)Author reference
banner_imagevarchar(250)Banner image path
blog_datedatePublish date (future = scheduled)
is_publishedtinyint(1)Whether article is published
is_promotinyint(1)Promotional flag
youtube_video_idvarchar(250)Embedded YouTube video
spotify_podcast_idvarchar(250)Embedded Spotify podcast
hitsintView counter

blog_mui

ColumnTypeDescription
idint (PK, AI)MUI entry ID
blog_idint (FK)Parent article
slugvarchar(250)URL slug
titlevarchar(255)Article title
meta_keywordstextSEO keywords
meta_descriptiontextSEO description
meta_titletextSEO title
descriptionlongtextFull article content (supports content embeddings)
small_descriptiontextExcerpt/summary
langvarchar(2)Language code

blog_comments

ColumnTypeDescription
idint (PK, AI)Comment ID
blog_idint (FK)Parent article
emailvarchar(255)Commenter email
namevarchar(255)Commenter name
comment_contenttextComment text
entry_datedatetimeSubmission timestamp (defaults to current_timestamp())
parent_comment_idint (nullable)For threaded replies
statusenumapproved, pending, rejected (default: pending)
langvarchar(4)Language code

blog_product

ColumnTypeDescription
blog_idint (PK, FK)Article reference
product_idint (PK, FK)Product reference
priorityintDisplay order (0 = default)

Supporting Tables

TablePurpose
blog_categoriesCategory master (banner_image, is_active, ord, parent_id)
blog_categories_muiCategory translations (title, slug, description, meta fields)
blog_blog_categoriesArticle-to-category lookup (blog_id, blog_category_id)
blog_tagsTag master (is_active, ord)
blog_tags_muiTag translations (name, slug, description, meta fields)
blog_blog_tagsArticle-to-tag lookup (blog_id, blog_tag_id, unique)
blog_authorAuthor master (banner_image, ord)
blog_author_muiAuthor translations (name, slug, description, meta fields)

Client Extension Points

  • indexExtras(), blogArticleExtras(), blogCategoryExtras() hooks: Add custom data to respective pages
  • blogArticleEvents() hook: Custom analytics/tracking events on article view
  • Comment moderation: Extend admin workflow; manageBlogComments() is overridable
  • Product relations: blog_product table with priority ordering
  • RSS feed: Available via rss() method; customize title/description via Registry
  • Search: Solr v1/v2 integration via search_model or search_model_v2
  • Content embeddings: Product/product-list shortcodes in article body
  • Builder blocks: blogArticle position for page builder content
  • Views: {client_views}/blog/ -- index, article, category, tag, author, search, rss templates