feat(main): Introduce USP block type and custom classes for HTML groups

This release adds a new "USP" (Unique Selling Proposition) block type,
allowing for flexible display of image-based selling points with optional links.

Additionally, administrators can now assign custom CSS classes to Custom HTML Groups,
enhancing layout and styling capabilities.

Includes a refinement to the FAQ accordion template to ensure questions without answers
do not display a collapse button, improving usability.

Updates module version to 1.13.0 with a database upgrade script for the new `custom_class` column.
This commit is contained in:
2026-08-20 15:22:15 +02:00
parent a4e479490b
commit 06e98a429b
19 changed files with 156 additions and 66 deletions
+52 -43
View File
@@ -1,48 +1,57 @@
{if !empty($block.faqs)}
<div class="accordion customhtml-faq-accordion" id="customhtml-faq-{$block.id_ws_customhtml|intval}">
{foreach from=$block.faqs item="faq" name="customhtmlFaqLoop"}
<div class="card">
<div class="card-header" id="customhtml-faq-heading-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}">
<button
class="btn btn-link col-12 d-flex text-left {if !$smarty.foreach.customhtmlFaqLoop.first} collapsed{/if}"
type="button"
data-toggle="collapse"
data-target="#customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
aria-expanded="{if $smarty.foreach.customhtmlFaqLoop.first}true{else}false{/if}"
aria-controls="customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
>
<div class="col">
{$faq.question|escape:'html':'UTF-8'}
</div>
<div class="col-auto d-flex align-items-center ">
<span class="accordion-icons accordion-icon-minus">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="2" viewBox="0 0 28 2">
<line id="Line_18" data-name="Line 18" x2="26" transform="translate(1 1)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
</svg>
</span>
<span class="accordion-icons accordion-icon-plus">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28">
<g id="Group_31" data-name="Group 31" transform="translate(-1615 -4031.5)">
<line id="Line_21" data-name="Line 21" x2="26" transform="translate(1616 4045.5)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
<line id="Line_22" data-name="Line 22" x2="26" transform="translate(1629 4032.5) rotate(90)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
</g>
</svg>
</span>
<div class="accordion customhtml-faq-accordion" id="customhtml-faq-{$block.id_ws_customhtml|intval}">
{foreach from=$block.faqs item="faq" name="customhtmlFaqLoop"}
<div class="card">
<div class="card-header" id="customhtml-faq-heading-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}">
{if !empty($faq.answer)}
<button
class="btn btn-link col-12 d-flex text-left{if !$smarty.foreach.customhtmlFaqLoop.first} collapsed{/if}"
type="button"
data-toggle="collapse"
data-target="#customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
aria-expanded="{if $smarty.foreach.customhtmlFaqLoop.first}true{else}false{/if}"
aria-controls="customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
>
{/if}
<div class="faq-question col pl-0">
{$faq.question|escape:'html':'UTF-8'}
</div>
{if !empty($faq.answer)}
<div class="col-auto d-flex align-items-center">
<span class="accordion-icons accordion-icon-minus">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="2" viewBox="0 0 28 2">
<line id="Line_18" data-name="Line 18" x2="26" transform="translate(1 1)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
</svg>
</span>
<span class="accordion-icons accordion-icon-plus">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28">
<g id="Group_31" data-name="Group 31" transform="translate(-1615 -4031.5)">
<line id="Line_21" data-name="Line 21" x2="26" transform="translate(1616 4045.5)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
<line id="Line_22" data-name="Line 22" x2="26" transform="translate(1629 4032.5) rotate(90)" fill="none" stroke="#272727" stroke-linecap="round" stroke-width="2"/>
</g>
</svg>
</span>
</div>
</button>
{/if}
</div>
</button>
</div>
<div
id="customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
class="collapse{if $smarty.foreach.customhtmlFaqLoop.first} show{/if}"
aria-labelledby="customhtml-faq-heading-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
data-parent="#customhtml-faq-{$block.id_ws_customhtml|intval}"
>
<div class="card-body">
{$faq.answer nofilter}
{if !empty($faq.answer)}
<div
id="customhtml-faq-collapse-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
class="collapse{if $smarty.foreach.customhtmlFaqLoop.first} show{/if}"
aria-labelledby="customhtml-faq-heading-{$block.id_ws_customhtml|intval}-{$faq.id_ws_customhtml_faq|intval}"
data-parent="#customhtml-faq-{$block.id_ws_customhtml|intval}"
>
<div class="card-body">
{$faq.answer nofilter}
</div>
</div>
{/if}
</div>
</div>
{/foreach}
</div>
{/foreach}
</div>
{/if}
+20
View File
@@ -0,0 +1,20 @@
{if !empty($block.image_url) || ($block.show_title && !empty($block.title))}
{if !empty($block.link)}
<a href="{$block.link|escape:'html':'UTF-8'}" class="customhtml-usp d-flex align-items-center">
{else}
<div class="customhtml-usp d-flex align-items-center">
{/if}
{if !empty($block.image_url)}
<span class="customhtml-usp-icon">
<img src="{$block.image_url|escape:'html':'UTF-8'}" alt="">
</span>
{/if}
{if $block.show_title && !empty($block.title)}
<span class="customhtml-usp-text">{$block.title|escape:'html':'UTF-8'}</span>
{/if}
{if !empty($block.link)}
</a>
{else}
</div>
{/if}
{/if}
+3 -1
View File
@@ -1,7 +1,7 @@
{if !empty($groupList)}
<div class="customhtml-container {$hookName|escape:'html':'UTF-8'}--container">
{foreach from=$groupList item="group"}
<div class="customhtml-group customhtml-group-{$group.id_ws_customhtml_group|intval} row">
<div class="customhtml-group customhtml-group-{$group.id_ws_customhtml_group|intval} row{if !empty($group.custom_class)} {$group.custom_class|escape:'html':'UTF-8'}{/if}">
{foreach from=$group.blocks item="block"}
<div class="customhtml-block col{if !empty($block.custom_class)} {$block.custom_class|escape:'html':'UTF-8'}{/if}">
{assign var="customhtmlOverridePath" value="{$smarty.const._PS_THEME_DIR_}modules/ws_customhtml/views/templates/hook/{$hookName}/{$block.type}.tpl"}
@@ -17,6 +17,8 @@
{include file="module:ws_customhtml/views/templates/hook/_banner.tpl" block=$block}
{elseif $block.type == 'alert'}
{include file="module:ws_customhtml/views/templates/hook/_alert.tpl" block=$block}
{elseif $block.type == 'usp'}
{include file="module:ws_customhtml/views/templates/hook/_usp.tpl" block=$block}
{else}
{if $block.show_title && !empty($block.title)}
<div class="customhtml-title">{$block.title|escape:'html':'UTF-8'}</div>