Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions cms/modules/block_articles_related/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module:
group: blog
revision: 1
compatible_contents: ['page']
edit_template: '@module/block_articles_related/edit.html.twig'
form_template: '@module/block_articles_related/form.html.twig'
render_template: '@module/block_articles_related/render.html.twig'
module_options:
form_fields:
id:
type: 'id'

class:
type: 'class'

title:
type: 'text'
type_options:
required: false

tag:
type: 'Softspring\CmsBlogPlugin\Form\Type\BlogArticleTagType'
type_options:
required: true

limit:
type: 'integer'
type_options:
required: false
empty_data: 3
default_value: 3
attr:
min: 1

order:
type: 'choice'
type_options:
required: false
default_value: 'published_at_desc'
choices:
'block_articles_related.form.order.values.published_at_desc': 'published_at_desc'
'block_articles_related.form.order.values.published_at_asc': 'published_at_asc'
'block_articles_related.form.order.values.name_asc': 'name_asc'
'block_articles_related.form.order.values.name_desc': 'name_desc'
37 changes: 37 additions & 0 deletions cms/modules/block_articles_related/edit.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{% trans_default_domain 'sfs_cms_modules' %}
{% import '@SfsCms/macros/modules_edit.html.twig' as module %}
{% set articles = sfs_cms_related_blog_articles(form.tag.vars.data|default(''), form.vars.content|default(null), form.limit.vars.data|default(3), form.order.vars.data|default('published_at_desc')) %}

<div {{ module.link_id(form.id) }} {{ module.link_class(form.class) }}>
<strong>{{ form.title.vars.data|default('block_articles_related.render.title'|trans) }}</strong>
{% if form.tag.vars.data|default %}
<div class="small text-muted">{{ form.tag.vars.data }}</div>
{% endif %}
{% if form.order.vars.data|default %}
<div class="small text-muted">{{ ('block_articles_related.form.order.values.' ~ form.order.vars.data)|trans({}, 'sfs_cms_modules') }}</div>
{% endif %}

{% if articles is not empty %}
<ul class="article-list">
{% for article in articles %}
<li class="article-list-item">
<a class="article-list-item__link" href="#">
<div class="article-list-item__media-mask d-block">
{% if article.extraData.image is defined %}
{{ article.extraData.image|sfs_media_render_image('blog_list', {'class':'article-list-item__media img-fluid', 'height':'360'}) }}
{% endif %}
</div>
<div class="article-list-item__wrap">
<p class="article-list-item__date">{{ article.publishedAt ? article.publishedAt|time_ago|lower : '' }}</p>
<h2 class="article-list-item__title">{{ article.extraData.title[app.request.locale]|default(article.name) }}</h2>
<p class="article-list-item__description">{{ article.extraData.description[app.request.locale]|default }}</p>
<p class="article-list-item__read-more">{{ 'article_list.list.read_more'|trans({}, 'sfs_cms_blocks') }}<i class="mdi mdi-chevron-right mdi-36px align-middle"></i></p>
</div>
</a>
</li>
{% endfor %}
</ul>
{% elseif form.tag.vars.data|default %}
<div class="small text-muted mt-2">{{ 'block_articles_related.edit.no_results'|trans }}</div>
{% endif %}
</div>
23 changes: 23 additions & 0 deletions cms/modules/block_articles_related/form.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{{ sfs_cms_admin_module_accordion_block_start(form, accordion, 'attributes') }}
<div class="col-12">
{{ form_row(form.id) }}
</div>
<div class="col-12">
{{ form_row(form.class) }}
</div>
{{ sfs_cms_admin_module_accordion_block_end() }}

{{ sfs_cms_admin_module_accordion_block_start(form, accordion, 'content', true) }}
<div class="col-12">
{{ form_row(form.title) }}
</div>
<div class="col-12">
{{ form_row(form.tag) }}
</div>
<div class="col-12">
{{ form_row(form.limit) }}
</div>
<div class="col-12">
{{ form_row(form.order) }}
</div>
{{ sfs_cms_admin_module_accordion_block_end() }}
33 changes: 33 additions & 0 deletions cms/modules/block_articles_related/render.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% trans_default_domain "sfs_cms_modules" %}
{% import "@SfsCms/macros/modules_render.html.twig" as module %}

{% set articles = sfs_cms_related_blog_articles(tag|default(""), content, limit|default(3), order|default("published_at_desc")) %}

{% if articles is not empty %}
<section {{ module.id(id) }} {{ module.class(class) }}>
<h2>{{ title|default("block_articles_related.render.title"|trans({}, "sfs_cms_modules")) }}</h2>

<ul class="article-list row g-4">
{% for article in articles %}
{% set routePath = article.getCanonicalRoutePath(app.request.locale) ?: article.getCanonicalRoutePath() %}
{% set articleUrl = routePath ? sfs_cms_route_path_path(routePath) : "#" %}

<li class="article-list-item col-12 col-md-6">
<a class="article-list-item__link d-block w-100 h-100 p-0" href="{{ articleUrl }}">
<div class="article-list-item__media-mask d-block">
{% if article.extraData.image is defined %}
{{ article.extraData.image|sfs_media_render_image("blog_list", {"class":"article-list-item__media img-fluid", "height":"360"}) }}
{% endif %}
</div>
<div class="article-list-item__wrap">
<p class="article-list-item__date">{{ article.publishedAt ? article.publishedAt|time_ago|lower : "" }}</p>
<h2 class="article-list-item__title">{{ article.extraData.title[app.request.locale]|default(article.name) }}</h2>
<p class="article-list-item__description">{{ article.extraData.description[app.request.locale]|default }}</p>
<p class="article-list-item__read-more">{{ "article_list.list.read_more"|trans({}, "sfs_cms_blocks") }}<i class="mdi mdi-chevron-right mdi-36px align-middle"></i></p>
</div>
</a>
</li>
{% endfor %}
</ul>
</section>
{% endif %}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
block_articles_related:
label: "Related articles"
prototype_button: "Related articles"
prototype_button_icon: '<i class="bi bi-tags-fill"></i>'
form:
_group:
attributes: "Attributes"
content: "Content"
id.label: "Id"
class.label: "Classes"
title.label: "Title"
tag.label: "Tag"
tag.placeholder: "Select a tag"
limit.label: "Number of articles"
order.label: "Order"
order.values:
published_at_desc: "Newest first"
published_at_asc: "Oldest first"
name_asc: "Name A-Z"
name_desc: "Name Z-A"
render:
title: "Related articles"
edit:
no_results: "There are no published articles for this tag."
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
block_articles_related:
label: "Artículos relacionados"
prototype_button: "Artículos relacionados"
prototype_button_icon: '<i class="bi bi-tags-fill"></i>'
form:
_group:
attributes: "Atributos"
content: "Contenido"
id.label: "Id"
class.label: "Clases"
title.label: "Título"
tag.label: "Etiqueta"
tag.placeholder: "Selecciona una etiqueta"
limit.label: "Número de artículos"
order.label: "Orden"
order.values:
published_at_desc: "Más recientes primero"
published_at_asc: "Más antiguos primero"
name_asc: "Nombre A-Z"
name_desc: "Nombre Z-A"
render:
title: "Artículos relacionados"
edit:
no_results: "No hay artículos publicados para esta etiqueta."
4 changes: 4 additions & 0 deletions config/services/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ services:
resource: '../../src/Form/*'
tags: ['form.type']

Softspring\CmsBlogPlugin\Twig\Extension\:
resource: '../../src/Twig/Extension/*'
tags: ['twig.extension']

Softspring\CmsBlogPlugin\Form\Admin\Article\ArticleCreateForm:
arguments:
$translatableContext: '@Softspring\CmsBundle\Translator\TranslatableContext'
Expand Down
33 changes: 33 additions & 0 deletions src/Form/Type/BlogArticleTagType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace Softspring\CmsBlogPlugin\Form\Type;

use Softspring\CmsBlogPlugin\Manager\ArticleTagManager;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\OptionsResolver\OptionsResolver;

class BlogArticleTagType extends AbstractType
{
public function __construct(protected ArticleTagManager $articleTagManager)
{
}

public function getParent(): string
{
return ChoiceType::class;
}

public function configureOptions(OptionsResolver $resolver): void
{
$tags = $this->articleTagManager->getExistingTags();
$choices = array_combine($tags, $tags) ?: [];

$resolver->setDefaults([
'required' => false,
'placeholder' => 'block_articles_related.form.tag.placeholder',
'choices' => $choices,
'choice_translation_domain' => false,
]);
}
}
56 changes: 56 additions & 0 deletions src/Twig/Extension/BlogArticleExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Softspring\CmsBlogPlugin\Twig\Extension;

use Softspring\CmsBlogPlugin\Entity\ArticleContent;
use Softspring\CmsBundle\Manager\ContentManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;

class BlogArticleExtension extends AbstractExtension
{
public function __construct(protected ContentManagerInterface $contentManager, protected RequestStack $requestStack)
{
}

public function getFunctions(): array
{
return [
new TwigFunction('sfs_cms_related_blog_articles', $this->getRelatedBlogArticles(...)),
];
}

public function getRelatedBlogArticles(string $tag, mixed $content = null, int $limit = 3, string $order = 'published_at_desc'): array
{
$tag = trim($tag);
$locale = $this->requestStack->getCurrentRequest()?->getLocale() ?: 'en';

if ('' === $tag) {
return [];
}

$repo = $this->contentManager->getRepository('article');
$qb = $repo->createQueryBuilder('a');

$qb->andWhere('a.publishedVersion IS NOT NULL');
$qb->andWhere('a.publishedAt <= :publishedAt')->setParameter('publishedAt', time());
$qb->andWhere('a.locales LIKE :locale')->setParameter('locale', '%"'.$locale.'"%');
$qb->andWhere('a.tags LIKE :tag')->setParameter('tag', '%"'.$tag.'"%');

if ($content instanceof ArticleContent && null !== $content->getId()) {
$qb->andWhere('a.id != :current')->setParameter('current', $content->getId());
}

match ($order) {
'published_at_asc' => $qb->addOrderBy('a.publishedAt', 'ASC'),
'name_asc' => $qb->addOrderBy('a.name', 'ASC'),
'name_desc' => $qb->addOrderBy('a.name', 'DESC'),
default => $qb->addOrderBy('a.publishedAt', 'DESC'),
};

$qb->setMaxResults(max(1, $limit));

return $qb->getQuery()->getResult();
}
}