6 Commits

Author SHA1 Message Date
ea9b67ffc5 fix(extra-features): Add attributes & styles to displaySvgIcon method 2025-12-31 15:22:32 +01:00
e2c4f265c2 feat(extra-features): Refactor smarty helper 2025-12-31 13:57:28 +01:00
28f8794e16 feat(extra-features): Add svg icon and price splitter smarty functions
These are just helpers and useful for many prestashop designs
2025-11-20 16:45:32 +01:00
abd8d60502 Merge branch 'feature/is_themecore-PS9' 2025-11-20 09:51:55 +01:00
60e57a5df6 fix: Add new IsBright helper to replace old Tools::GetBrightness
This is used from prestashop itself but I needed to add it as a smarty helper
2025-11-19 17:17:10 +01:00
3a0468879f FEAT: Add checks to prevent re-registering Smarty plugins 2025-11-19 16:10:42 +01:00
3 changed files with 170 additions and 9 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
is_themecore/vendor/

View File

@ -4,6 +4,7 @@ namespace Oksydan\Module\IsThemeCore\Core\Smarty;
use Oksydan\Module\IsThemeCore\Core\Webp\WebpPictureGenerator; use Oksydan\Module\IsThemeCore\Core\Webp\WebpPictureGenerator;
use Oksydan\Module\IsThemeCore\Form\Settings\WebpConfiguration; use Oksydan\Module\IsThemeCore\Form\Settings\WebpConfiguration;
use PrestaShop\PrestaShop\Core\Util\ColorBrightnessCalculator;
class SmartyHelperFunctions class SmartyHelperFunctions
{ {
@ -189,4 +190,113 @@ class SmartyHelperFunctions
return $content; return $content;
} }
/* CUSTOM ADDITIONS BELOW */
public static function isBright($hexColor)
{
$calculator = new ColorBrightnessCalculator();
return $calculator->isBright($hexColor);
}
public static function displaySvgIcon($params){
/*
Helper to display SVG icons stored in themes/falcon/_dev/img/icons/
registered under public_html/modules/is_themecore/src/Hook/Smarty.php
Usage examples in a TPL file:
{svg_icon file='person.svg' fill='red' width='24' height='24'}
{svg_icon file='person.svg'}
*/
// Grab svg under falcon/_dev/img and display an error if not found
if (empty($params['file'])) {
return '';
}
$icon_path = _PS_THEME_DIR_ . '/_dev/img/' . basename($params['file']);
if (!is_file($icon_path)) {
if (defined('_PS_MODE_DEV_') && _PS_MODE_DEV_) {
return 'Invalid SVG path: ' . htmlspecialchars($icon_path);
}
return '';
}
$svg_content = file_get_contents($icon_path);
/* Define an associative array of SVG properties
If the property is a style, addd it in a style tag.
If the property is an attribute, replace it in the svg code.
This reduces the risk of interfering with other attributes. */
$svg_props = array(
'width' => 'style',
'height' => 'style',
'opacity' => 'style',
'fill' => 'attribute',
'stroke' => 'attribute',
);
// Styles
$styles = [];
foreach ($svg_props as $prop => $type) {
if ($type === 'style' && !empty($params[$prop])) {
$value = $params[$prop];
if (in_array($prop, ['width', 'height']) && is_numeric($value)) {
$value .= 'px';
}
$styles[] = $prop . ': ' . $value;
}
}
if (!empty($styles)) {
$style_attr = 'style="' . implode('; ', $styles) . '"';
$svg_content = preg_replace('/(<svg[^>]*?)>/', '$1 ' . $style_attr . '>', $svg_content, 1);
}
// Attributes
foreach ($svg_props as $prop => $type) {
if ($type === 'attribute' && !empty($params[$prop])) {
$value = $params[$prop];
// Use word boundaries to avoid matching partial names like fill-opacity or stroke-width
// Replace ALL occurrences of the attribute
$svg_content = preg_replace(
'/\b' . preg_quote($prop) . '\b\s*=\s*"[^"]*"/',
$prop . '="' . $value . '"',
$svg_content
);
}
}
return $svg_content;
}
public static function displayPriceSplit($price){
/* Helper to split the price into euros and cents to make it more stylish
registered under public_html/modules/is_themecore/src/Hook/Smarty.php
Usage examples in a TPL file:
{price_split price=$product.price}
*/
//Convert to a string and only keep numbers, commas and dots
$price_string = implode(',', $price);
$price_string = preg_replace('/[^0-9,.]/', '', $price_string);
// Split by comma and wrap each part in a span
$price_parts = explode(',', $price_string);
if (count($price_parts) >= 2) {
echo '<span class="euros" aria-label="euros">' . $price_parts[0] . '</span>';
echo '<sup class="cents" aria-label="cents">' . $price_parts[1] . '</sup>';
} else {
foreach ($price_parts as $part) {
echo '<span>' . $part . '</span>';
}
}
}
} }

View File

@ -8,14 +8,63 @@ class Smarty extends AbstractHook
'actionDispatcherBefore', 'actionDispatcherBefore',
]; ];
public function hookActionDispatcherBefore(): void public function hookActionDispatcherBefore(): void
{ {
$this->context->smarty->registerPlugin('function', 'generateImagesSources', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'generateImagesSources']); if (!isset($this->context->smarty->registered_plugins['function']['generateImagesSources'])) {
$this->context->smarty->registerPlugin('function', 'generateImageSvgPlaceholder', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'generateImageSvgPlaceholder']); $this->context->smarty->registerPlugin('function', 'generateImagesSources', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'generateImagesSources']);
$this->context->smarty->registerPlugin('function', 'appendParamToUrl', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'appendParamToUrl']); } else {
$this->context->smarty->registerPlugin('block', 'images_block', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'imagesBlock']); return;
$this->context->smarty->registerPlugin('block', 'cms_images_block', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'cmsImagesBlock']); }
$this->context->smarty->registerPlugin('block', 'display_mobile', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displayMobileBlock']);
$this->context->smarty->registerPlugin('block', 'display_desktop', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displayDesktopBlock']); if (!isset($this->context->smarty->registered_plugins['function']['generateImageSvgPlaceholder'])) {
$this->context->smarty->registerPlugin('function', 'generateImageSvgPlaceholder', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'generateImageSvgPlaceholder']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['function']['appendParamToUrl'])) {
$this->context->smarty->registerPlugin('function', 'appendParamToUrl', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'appendParamToUrl']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['block']['images_block'])) {
$this->context->smarty->registerPlugin('block', 'images_block', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'imagesBlock']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['block']['cms_images_block'])) {
$this->context->smarty->registerPlugin('block', 'cms_images_block', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'cmsImagesBlock']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['block']['display_mobile'])) {
$this->context->smarty->registerPlugin('block', 'display_mobile', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displayMobileBlock']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['block']['display_desktop'])) {
$this->context->smarty->registerPlugin('block', 'display_desktop', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displayDesktopBlock']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['modifier']['is_bright'])) {
$this->context->smarty->registerPlugin('modifier', 'is_bright', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'isBright']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['function']['svg_icon'])) {
$this->context->smarty->registerPlugin('function', 'svg_icon', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displaySvgIcon']);
} else {
return;
}
if (!isset($this->context->smarty->registered_plugins['function']['price_split'])) {
$this->context->smarty->registerPlugin('function', 'price_split', ['Oksydan\Module\IsThemeCore\Core\Smarty\SmartyHelperFunctions', 'displayPriceSplit']);
} else {
return;
}
} }
} }