roadiz / abstract-blog-theme
Abstract Blog middleware for your Roadiz theme.
Installs: 1 973
Dependents: 0
Suggesters: 1
Security: 0
Stars: 1
Watchers: 5
Forks: 0
Open Issues: 0
pkg:composer/roadiz/abstract-blog-theme
Requires
- php: >=7.4
- jms/serializer: ^2.3.0 || ^3.1.1
- rezozero/social-links: ^1.5 || ^2.0
- roadiz/roadiz: ~1.7.22
- twig/twig: ^3.0
Requires (Dev)
- phpstan/phpstan: ^0.12.38
- phpstan/phpstan-doctrine: ^0.12.26
- squizlabs/php_codesniffer: ^3.3
- dev-master
- 2.1.1
- 2.1.0
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 1.10.1
- 1.10.0
- 1.9.3
- 1.9.2
- 1.9.1
- 1.9.0
- 1.8.1
- 1.8.0
- 1.7.x-dev
- 1.7.9
- 1.7.8
- 1.7.7
- 1.7.6
- 1.7.5
- 1.7.4
- 1.7.3
- 1.7.2
- 1.7.1
- 1.7.0
- 1.6.3
- 1.6.2
- 1.6.1
- 1.6.0
- v1.5.x-dev
- 1.5.1
- 1.5.0
- 1.4.2
- 1.4.1
- 1.4.0
- 1.3.2
- 1.3.1
- 1.3.0
- 1.2.0
- 1.1.2
- 1.1.1
- 1.1.0
- 1.0.10
- 1.0.9
- 1.0.8
- 1.0.7
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- dev-develop
This package is auto-updated.
Last update: 2025-10-26 18:20:21 UTC
README
Abstract Blog middleware for your Roadiz theme.
- Inheritance
- Dependency injection
- Add node-types
- PostContainerControllerTrait
- PostControllerTrait
- Search engine with Solr
- AMP mobile page support
- Templates
- Twig extension
Inheritance
Your own theme entry class must extend AbstractBlogThemeApp instead of FrontendController to provide essential methods:
use Themes\AbstractBlogTheme\AbstractBlogThemeApp; class MyThemeApp extends AbstractBlogThemeApp { //… }
Dependency injection
Edit your own app/AppKernel.php to register Blog services:
use Themes\AbstractBlogTheme\Services\BlogServiceProvider; /** * {@inheritdoc} */ public function register(\Pimple\Container $container) { parent::register($container); $container->register(new BlogServiceProvider()); }
You must override these services in your custom theme:
- blog_theme.post_container_entity
- blog_theme.post_entity
with your own node-type class names.
/** * @param Container $container */ public static function setupDependencyInjection(Container $container) { parent::setupDependencyInjection($container); $container->extend('blog_theme.post_container_entity', function ($entityClass) { return NSBlogPostContainer::class; }); $container->extend('blog_theme.post_entity', function ($entityClass) { return NSBlogPost::class; }); }
Add node-types
Abstract Blog theme declare 3 node-types to create your blog website:
BlogFeedBlock: to create an automatic feed preview on any pageBlogPost: the main blog post entityBlogPostContainer: the blog container to host every blog post
bin/roadiz themes:install --data Themes/AbstractBlogTheme/AbstractBlogThemeApp bin/roadiz generate:nsentities bin/roadiz orm:schema-tool:update --dump-sql --force
PostContainerControllerTrait
PostContainerControllerTrait will implement your indexAction by handling all request data
to provide your posts, filters and available tags to build your template.
IndexAction will assign:
posts: foundNodesSourcesarray according to your criteriafilters: pagination information arraytags: available filteringTagarraycurrentTag:Tag,array<Tag>ornullcurrentTagNames:array<string>containing current filtering tag(s) name for your filter menu template.currentRelationSource:NodesSourcesornullcontaining the filtering related entitycurrentRelationsSources:array<NodesSources>containing current filtering related entities(s) for your filter menu template.currentRelationsNames:array<string>containing current filtering related entities(s) name for your filter menu template.archives: available years and months of post archivescurrentArchive:stringornot definedcurrentArchiveDateTime:\DateTimeornot defined
Filtering
You can filter your post-container entities using Request attributes or query params :
tag: Filter by a tag’ name using Roadiz nodes’stagsfield. You can pass an array of tag name to combine them.archive: Filter by month and year, or just year onpublishedAtfield, or the one defined bygetPublicationFieldmethod.related: Filter by a related node’ name using Roadiz nodes’sbNodesfield. You can pass an array of node name to combine them.
Usage
All you need to do is creating your PostContainer node-source's Controller in your theme and
implements ConfigurableController and use PostContainerControllerTrait.
You will be able to override any methods to configure your blog listing.
<?php namespace Themes\MyTheme\Controllers; use Themes\AbstractBlogTheme\Controllers\ConfigurableController; use Themes\AbstractBlogTheme\Controllers\PostContainerControllerTrait; use Themes\MyTheme\MyThemeThemeApp; class BlogPostContainerController extends MyThemeThemeApp implements ConfigurableController { use PostContainerControllerTrait; }
Multiple container controllers usage
If you have more than one blog-post type (Blogpost and PressReview for example), we advise strongly to create
an Abstract class in your theme using this Trait before using it, it will ease up
method overriding if you have multiple container controllers classes:
<?php namespace Themes\MyTheme\Controllers; use Themes\AbstractBlogTheme\Controllers\ConfigurableController; use Themes\AbstractBlogTheme\Controllers\PostContainerControllerTrait; use Themes\MyTheme\MyThemeThemeApp; abstract class AbstractContainerController extends MyThemeThemeApp implements ConfigurableController { use PostContainerControllerTrait; // common methods overriding here… }
Then, simply inherit from your Abstract in your multiple container controller definitions:
<?php namespace Themes\MyTheme\Controllers; class BlogPostContainerController extends AbstractContainerController { // override whatever you want } class PressReviewContainerController extends AbstractContainerController { // override whatever you want }
Override PostContainerControllerTrait behaviour
Those methods can be overridden to customize your PostContainerControllerTrait behaviour.
getTemplate: By default it returnspages/post-container.html.twig. It will search in every registered themes for this template and fallback on@AbstractBlogTheme/pages/post-container.html.twig. Make sure your own theme have a higher priority.getRssTemplate: By default it returnspages/post-container.rss.twig. It will search in every registered themes for this template and fallback on@AbstractBlogTheme/pages/post-container.rss.twig. Make sure your own theme have a higher priority.throwExceptionOnEmptyResult: By default it returnstrue. It throws a 404 when no posts found.getPostEntity: By default it returns$this->get('blog_theme.post_entity')as classname string. You can customize it to list other nodes.isScopedToCurrentContainer: By default it returnsfalse,PostContainerControllerTraitwill fetch all blog-post no matter where there are. If your overridenisScopedToCurrentContainermethod returnstrue, all blog post will be fetched only from your current container allowing you to create many blog containers.isTagExclusive: returns true by default, match posts linked with all tags exclusively (intersection). Override it tofalseif you want to match posts with any tags (union).getPublicationField: By default this method returnspublishedAtfield name. You can return whatever name unless field exists in your BlogPost node-type.getDefaultCriteria: returns default post query criteria. We encourage you to overridegetCriteriainstead to keep default tags, archives and related filtering system.getCriteria: Override default post query criteria, this method must return an array.getDefaultOrder: By default this method returns an array :
[
$this->getPublicationField() => 'DESC'
]
getResponseTtl: By default this method returns5(minutes).selectPostCounts: By defaultfalse: make additional queries to get each tag’ post count to display posts count number in your tags menu.prepareListingAssignation: This is the critical method which performs all queries and tag resolutions. We do not recommend overriding this method, override other methods to change your PostContainer behaviour instead.getRelatedNodesSourcesQueryBuilder: if you want to fetch only one type related node-sources. Or filter more precisely.
You can override other methods, just get a look at the PostContainerControllerTrait file…
PostControllerTrait
PostControllerTrait will implement your indexAction by handling all request data
to provide a single post with its multiple formats.
Usage
All you need to do is creating your Post node-source'Controller in your theme and
implements ConfigurableController and use PostControllerTrait.
<?php namespace Themes\MyTheme\Controllers; use Themes\AbstractBlogTheme\Controllers\ConfigurableController; use Themes\AbstractBlogTheme\Controllers\PostControllerTrait; use Themes\MyTheme\MyThemeThemeApp; class BlogPostController extends MyThemeThemeApp implements ConfigurableController { use PostControllerTrait; }
Override PostControllerTrait behaviour
Those methods can be overridden to customize your PostControllerTrait behaviour.
getJsonLdArticle: By default it returns a newJsonLdArticleto be serialized to JSON or AMP friendly format.getTemplate: By default it returnspages/post.html.twig. It will search in every registered themes for this template and fallback on@AbstractBlogTheme/pages/post.html.twig. Make sure your own theme have a higher priority.getAmpTemplate: By default it returnspages/post.amp.twig. It will search in every registered themes for this template and fallback on@AbstractBlogTheme/pages/post.amp.twig. Make sure your own theme have a higher priority.allowAmpFormat: By default it returnstrue.allowJsonFormat: By default it returnstrue.getResponseTtl: By default this method returns5(minutes).
Search engine with Solr
<?php namespace Themes\MyTheme\Controllers; use Themes\AbstractBlogTheme\Controllers\ConfigurableController; use Themes\AbstractBlogTheme\Controllers\SearchControllerTrait; use Themes\MyTheme\MyThemeApp; class SearchController extends MyThemeApp implements ConfigurableController { use SearchControllerTrait; }
searchPageLocale: path: /{_locale}/search.{_format}/{page} defaults: _controller: Themes\MyTheme\Controllers\SearchController::searchAction _locale: en page: 1 _format: html requirements: # Use every 2 letter codes (quick and dirty) _locale: "en|fr" page: "[0-9]+" _format: html|json
Add your search form in your website templates (use GET method to enable user history):
<form method="get" action="{{ path('searchPageLocale', { '_locale': request.locale }) }}" data-json-action="{{ path('searchPageLocale', { '_locale': request.locale, '_format': 'json', }) }}" id="search"> <input type="search" name="q"> <button type="submit">{% trans %}search{% endtrans %}</button> </form>
Then create pages/search.html.twig template.
Override PostControllerTrait behaviour
getTemplate(): stringgetAmpTemplate(): stringgetJsonLdArticle(): JsonLdArticlegetResponseTtl(): stringallowAmpFormat(): booleanallowJsonFormat(): boolean
Search result model
For JSON search responses, SearchControllerTrait uses JMS Serializer with a custom model to decorate your
node-sources and its highlighted text. By default SearchControllerTrait instantiates a Themes\AbstractBlogTheme\Model\SearchResult
object that will be serialized. You can override this model if you want to add custom fields according to your
node-sources data.
Create a child class, then override createSearchResultModel method:
/** * @param $searchResult * * @return SearchResult */ protected function createSearchResultModel($searchResult) { return new SearchResult( $searchResult['nodeSource'], $searchResult['highlighting'], $this->get('document.url_generator'), $this->get('router'), $this->get('translator') ); }
You’ll be able to add new virtual properties in your child SearchResult model.
AMP mobile page support
AMP format is supported for blog-post detail pages.
- Disable
display_debug_panelsetting - Add
?amp=1after your blog-post detail page Url. Or add?amp=1#development=1for dev mode. - Add amp
linkto your HTML template:
{% block share_metas %}
{{ parent() }}
<link rel="amphtml" href="{{ url(nodeSource, {'amp': 1}) }}">
{% endblock %}
RSS feed support
RSS format is supported for blog-post containers listing pages.
- Add RSS
linkinto your HTML template:
{% block share_metas %}
{{ parent() }}
<link rel="alternate" href="{{ url(nodeSource, {
'_format': 'xml',
'page': filters.currentPage,
'tag': currentTag.tagName,
'archive': currentArchive
}) }}" title="{{ pageMeta.title }}" type="application/rss+xml">
{% endblock %}
Templates
Resources/views/ folder contains useful templates for creating your own blog. Feel free to include
them directly in your theme or duplicated them.
By default, your Roadiz website will directly use AbstractBlogTheme templates. You can override them in your inheriting Theme using the exact same path and name.
Twig extension
Functions
get_latest_posts($translation, $count = 4)get_latest_posts_for_tag($tag, $translation, $count = 4)get_previous_post($nodeSource, $count = 1, $scopedToParent = false): Get previous post(s) sorted bypublishedAt.
Returns a singleNodesSourceby default, returns anarrayif count > 1.get_previous_post_for_tag($nodeSource, $tag, $count = 1, $scopedToParent = false): Get previous post(s) sorted bypublishedAtand filtered by oneTag.
Returns a singleNodesSourceby default, returns anarrayif count > 1.get_next_post($nodeSource, $count = 1, $scopedToParent = false): Get next post(s) sorted bypublishedAt.
Returns a single NodesSource by default, returns an array if count > 1.get_next_post_for_tag($nodeSource, $tag, $count = 1, $scopedToParent = false): Get next post(s) sorted bypublishedAtand filtered by oneTag.
Returns a singleNodesSourceby default, returns anarrayif count > 1.
Filters
ampifize: Strips unsupported tags in AMP format and convertimgandiframetags to their AMP equivalent.