<?php
if (!defined('_PS_VERSION_')) {
exit;
}

class OffreSpecialeBadge extends Module
{
const BADGE_TYPES = array('BF10', 'BF20', 'BF30');

public function __construct()
{
$this->name = 'offrespecialebadge';
$this->tab = 'front_office_features';
$this->version = '1.0.1';
$this->author = 'Greg';
$this->need_instance = 0;

parent::__construct();

$this->displayName = $this->l('Offre Spéciale Badge');
$this->description = $this->l('Ajoute des badges d\'offre spéciale (BF10, BF20, BF30) sur des produits spécifiques');
}

public function install()
{
// Créer la table
$sql = 'CREATE TABLE IF NOT EXISTS `' . _DB_PREFIX_ . 'offre_speciale_products` (
`id_product` int(11) NOT NULL,
`badge_type` varchar(10) NOT NULL,
`date_add` datetime NOT NULL,
PRIMARY KEY (`id_product`),
KEY `badge_type` (`badge_type`)
) ENGINE=' . _MYSQL_ENGINE_ . ' DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';

return parent::install()
&& Db::getInstance()->execute($sql)
&& $this->registerHook('displayProductListReviews')
&& $this->registerHook('displayProductAdditionalInfo')
&& $this->registerHook('header')
&& $this->registerHook('displayAfterBodyOpeningTag')
&& $this->registerHook('actionOutputHTMLBefore');
}

public function uninstall()
{
// Supprimer la table
$sql = 'DROP TABLE IF EXISTS `' . _DB_PREFIX_ . 'offre_speciale_products`';

return parent::uninstall()
&& Db::getInstance()->execute($sql);
}

public function hookHeader()
{
// Ajouter le CSS
$this->context->controller->addCSS($this->_path . 'views/css/offrespeciale.css');

// Ajouter le JavaScript pour gérer les shortcodes côté client
$this->context->controller->addJS($this->_path . 'views/js/offrespeciale.js');

// Récupérer TOUS les badges pour injection en JavaScript
$allBadges = $this->getAllBadgesForJS();

// Injecter les données des badges en JavaScript
$idProduct = 0;
if (isset($this->context->controller->php_self) && $this->context->controller->php_self == 'product') {
$idProduct = (int)Tools::getValue('id_product');
}

$badgeData = $this->getBadgeForProduct($idProduct);

Media::addJsDef(array(
'offreSpecialeBadgeData' => array(
'currentProductId' => $idProduct,
'currentBadge' => $badgeData,
'allBadges' => $allBadges,
'ajaxUrl' => $this->context->link->getModuleLink('offrespecialebadge', 'ajax', array(), true)
)
));
}

/**
* Récupère tous les badges pour injection JavaScript
*/
private function getAllBadgesForJS()
{
$badges = Db::getInstance()->executeS('
SELECT id_product, badge_type
FROM `' . _DB_PREFIX_ . 'offre_speciale_products`
');

$badgesArray = array();
if ($badges) {
foreach ($badges as $badge) {
$badgesArray[$badge['id_product']] = $badge['badge_type'];
}
}

return $badgesArray;
}

/**
* Hook pour remplacer les shortcodes dans le HTML avant affichage
*/
public function hookActionOutputHTMLBefore($params)
{
if (isset($params['html'])) {
$params['html'] = $this->processShortcodes($params['html']);
}
}

/**
* Traite les shortcodes dans le contenu HTML
*/
private function processShortcodes($html)
{
// Pattern pour {offre_badge} ou {offre_badge id=123}
$pattern = '/\{offre_badge(?:\s+id=(\d+))?\}/';

$html = preg_replace_callback($pattern, function($matches) {
$idProduct = isset($matches[1]) ? (int)$matches[1] : 0;

// Si pas d'ID fourni, essayer de récupérer le produit actuel
if (!$idProduct && isset($this->context->controller->php_self) && $this->context->controller->php_self == 'product') {
$idProduct = (int)Tools::getValue('id_product');
}

if ($idProduct) {
return $this->displayBadge($idProduct);
}

return '<span class="offre-badge-placeholder" data-product-id="current"></span>';
}, $html);

return $html;
}

private function getBadgeForProduct($productId)
{
if (!$productId) {
return null;
}

$badge = Db::getInstance()->getRow('
SELECT badge_type
FROM `' . _DB_PREFIX_ . 'offre_speciale_products`
WHERE id_product = ' . (int)$productId
);

return $badge ? $badge['badge_type'] : null;
}

public function getContent()
{
$output = '';

// Traitement de l'ajout de produits
if (Tools::isSubmit('submitOffreSpecialeProducts')) {
$badgeType = Tools::getValue('BADGE_TYPE');
$products = Tools::getValue('OFFRE_PRODUCTS');

if (!in_array($badgeType, self::BADGE_TYPES)) {
$output .= $this->displayError($this->l('Type de badge invalide'));
} else {
$result = $this->addProducts($products, $badgeType);

if ($result['success']) {
$output .= $this->displayConfirmation(
sprintf($this->l('%d produit(s) ajouté(s) avec le badge %s'), $result['added'], $badgeType)
);
}
if ($result['errors'] > 0) {
$output .= $this->displayWarning(
sprintf($this->l('%d produit(s) déjà présent(s) ou invalide(s)'), $result['errors'])
);
}
}
}

// Traitement de la suppression d'un badge spécifique
if (Tools::isSubmit('submitClearBadge')) {
$badgeType = Tools::getValue('clear_badge_type');
if ($this->clearBadgeProducts($badgeType)) {
$output .= $this->displayConfirmation(
sprintf($this->l('Tous les produits du badge %s ont été supprimés'), $badgeType)
);
}
}

// Traitement de la suppression totale
if (Tools::isSubmit('submitClearAll')) {
if ($this->clearAllProducts()) {
$output .= $this->displayConfirmation($this->l('Tous les produits ont été supprimés'));
}
}

// Traitement de la suppression d'un produit spécifique
if (Tools::isSubmit('deleteProduct')) {
$idProduct = (int)Tools::getValue('id_product');
if ($this->removeProduct($idProduct)) {
$output .= $this->displayConfirmation($this->l('Produit supprimé'));
}
}

return $output . $this->displayShortcodeInfo() . $this->displayForm() . $this->displayCurrentProducts();
}

public function displayShortcodeInfo()
{
$html = '<div class="alert alert-info">
<h4><i class="icon-code"></i> ' . $this->l('Utilisation des shortcodes dans Creative Elements') . '</h4>
<p><strong>' . $this->l('Pour afficher le badge d\'un produit spécifique :') . '</strong></p>
<code>{offre_badge id=5139}</code>
<p style="margin-top: 10px;"><strong>' . $this->l('Pour afficher le badge du produit actuel (page produit) :') . '</strong></p>
<code>{offre_badge}</code>
<p style="margin-top: 10px;"><strong>' . $this->l('Alternative avec balise HTML (fonctionne partout) :') . '</strong></p>
<code>&lt;span class="offre-badge-shortcode" data-product-id="5139"&gt;&lt;/span&gt;</code>
<p style="margin-top: 5px;"><em>' . $this->l('Pour le produit actuel :') . '</em></p>
<code>&lt;span class="offre-badge-shortcode" data-product-id="current"&gt;&lt;/span&gt;</code>
</div>';

return $html;
}

public function displayForm()
{
$badgeOptions = array();
foreach (self::BADGE_TYPES as $badge) {
$badgeOptions[] = array(
'id' => $badge,
'name' => $badge
);
}

$fields_form = array(
'form' => array(
'legend' => array(
'title' => $this->l('Ajouter des produits avec badge'),
'icon' => 'icon-tag'
),
'input' => array(
array(
'type' => 'select',
'label' => $this->l('Type de badge'),
'name' => 'BADGE_TYPE',
'required' => true,
'options' => array(
'query' => $badgeOptions,
'id' => 'id',
'name' => 'name'
)
),
array(
'type' => 'textarea',
'label' => $this->l('IDs des produits'),
'desc' => $this->l('Entrez les IDs séparés par des virgules, espaces ou retours à la ligne (ex: 1, 5, 12, 45)'),
'name' => 'OFFRE_PRODUCTS',
'rows' => 5,
'cols' => 60,
'required' => true,
),
),
'submit' => array(
'title' => $this->l('Ajouter les produits'),
'class' => 'btn btn-default pull-right',
'icon' => 'process-icon-plus'
),
'buttons' => array(
array(
'href' => AdminController::$currentIndex . '&configure=' . $this->name . '&submitClearAll=1&token=' . Tools::getAdminTokenLite('AdminModules'),
'title' => $this->l('Tout supprimer'),
'icon' => 'process-icon-eraser',
'class' => 'btn btn-danger',
'js' => 'return confirm(\'' . $this->l('Êtes-vous sûr de vouloir supprimer tous les produits ?') . '\');'
)
)
),
);

$helper = new HelperForm();
$helper->module = $this;
$helper->name_controller = $this->name;
$helper->token = Tools::getAdminTokenLite('AdminModules');
$helper->currentIndex = AdminController::$currentIndex . '&configure=' . $this->name;
$helper->submit_action = 'submitOffreSpecialeProducts';

return $helper->generateForm(array($fields_form));
}

public function displayCurrentProducts()
{
$html = '';

foreach (self::BADGE_TYPES as $badgeType) {
$products = $this->getProductsByBadge($badgeType);

$html .= '<div class="panel">
<div class="panel-heading">
<i class="icon-tag"></i> ' . sprintf($this->l('Produits avec badge %s'), $badgeType) . ' (' . count($products) . ')
<span class="panel-heading-action">
<a href="' . AdminController::$currentIndex . '&configure=' . $this->name
. '&submitClearBadge=1&clear_badge_type=' . $badgeType
. '&token=' . Tools::getAdminTokenLite('AdminModules') . '"
class="btn btn-default btn-sm"
onclick="return confirm(\'' . sprintf($this->l('Supprimer tous les produits du badge %s ?'), $badgeType) . '\');">
<i class="icon-eraser"></i> ' . $this->l('Vider ce badge') . '
</a>
</span>
</div>';

if (empty($products)) {
$html .= '<div class="alert alert-info" style="margin: 10px;">'
. sprintf($this->l('Aucun produit avec le badge %s'), $badgeType)
. '</div>';
} else {
$html .= '<table class="table"><thead><tr>
<th>ID</th>
<th>' . $this->l('Nom du produit') . '</th>
<th>' . $this->l('Référence') . '</th>
<th>' . $this->l('Date d\'ajout') . '</th>
<th>' . $this->l('Actions') . '</th>
</tr></thead><tbody>';

foreach ($products as $product) {
$productObj = new Product($product['id_product'], false, $this->context->language->id);
$html .= '<tr>
<td>' . (int)$product['id_product'] . '</td>
<td>' . ($productObj->name ?: $this->l('Produit introuvable')) . '</td>
<td>' . $productObj->reference . '</td>
<td>' . $product['date_add'] . '</td>
<td>
<a href="' . AdminController::$currentIndex . '&configure=' . $this->name
. '&deleteProduct=1&id_product=' . (int)$product['id_product']
. '&token=' . Tools::getAdminTokenLite('AdminModules') . '"
class="btn btn-default btn-sm" onclick="return confirm(\'' . $this->l('Supprimer ce produit ?') . '\');">
<i class="icon-trash"></i>
</a>
</td>
</tr>';
}

$html .= '</tbody></table>';
}

$html .= '</div>';
}

return $html;
}

private function addProducts($productsString, $badgeType)
{
// Nettoyer et extraire les IDs
$productsString = preg_replace('/[^0-9,\s\n\r]/', '', $productsString);
$productIds = preg_split('/[\s,\n\r]+/', $productsString, -1, PREG_SPLIT_NO_EMPTY);
$productIds = array_unique(array_map('intval', $productIds));

$added = 0;
$errors = 0;

foreach ($productIds as $idProduct) {
if ($idProduct <= 0) {
$errors++;
continue;
}

// Vérifier si le produit existe
if (!Product::existsInDatabase($idProduct, 'product')) {
$errors++;
continue;
}

// Supprimer l'ancien badge si existant
Db::getInstance()->delete('offre_speciale_products', 'id_product = ' . (int)$idProduct);

// Insérer le nouveau
$result = Db::getInstance()->insert('offre_speciale_products', array(
'id_product' => (int)$idProduct,
'badge_type' => pSQL($badgeType),
'date_add' => date('Y-m-d H:i:s')
));

if ($result) {
$added++;
} else {
$errors++;
}
}

return array('success' => $added > 0, 'added' => $added, 'errors' => $errors);
}

private function clearAllProducts()
{
return Db::getInstance()->execute('TRUNCATE TABLE `' . _DB_PREFIX_ . 'offre_speciale_products`');
}

private function clearBadgeProducts($badgeType)
{
return Db::getInstance()->delete('offre_speciale_products', 'badge_type = "' . pSQL($badgeType) . '"');
}

private function removeProduct($idProduct)
{
return Db::getInstance()->delete('offre_speciale_products', 'id_product = ' . (int)$idProduct);
}

private function getProductsByBadge($badgeType)
{
return Db::getInstance()->executeS('
SELECT id_product, badge_type, date_add
FROM `' . _DB_PREFIX_ . 'offre_speciale_products`
WHERE badge_type = "' . pSQL($badgeType) . '"
ORDER BY date_add DESC
');
}

public function hookDisplayProductListReviews($params)
{
if (!isset($params['product']['id_product'])) {
return;
}

return $this->displayBadge($params['product']['id_product']);
}

public function hookDisplayProductAdditionalInfo($params)
{
if (!isset($params['product']['id_product'])) {
return;
}

return $this->displayBadge($params['product']['id_product']);
}

public function displayBadge($productId)
{
$badge = Db::getInstance()->getRow('
SELECT badge_type
FROM `' . _DB_PREFIX_ . 'offre_speciale_products`
WHERE id_product = ' . (int)$productId
);

if ($badge && isset($badge['badge_type'])) {
$badgeType = $badge['badge_type'];
$badgeClass = 'badge-offre-' . strtolower($badgeType);

return '<span class="badge-offre-speciale ' . $badgeClass . '">' . $badgeType . '</span>';
}

return '';
}
}

Combinaisons Néoprène & Accessoires | GlissEvolution

Néoprène

Il y a 2 produits.

Les News du Blog Glissevolution

Combinaisons Néoprène & Accessoires – GlissEvolution

Votre Deuxième Peau sur l’Eau

En kitesurf, wingfoil, surf ou stand up paddle, la combinaison néoprène est bien plus qu’un simple équipement : c’est votre seconde peau.
Elle assure confort, protection thermique et liberté de mouvement, quel que soit votre niveau ou la saison.

Une Combinaison Néoprène pour Chaque Pratique

Chez GlissEvolution, nous proposons une large gamme adaptée à toutes les conditions :

  • Combinaisons intégrales : idéales pour l’hiver et les eaux froides.

  • Combinaisons manches courtes & combishorts : parfaites pour l’été.

  • Long John : sans manches, liberté de mouvement maximale pour les bras.

  • Shortys & tops néoprène : adaptés aux sessions estivales ou au SUP.

  • Combinaisons sèches : pour rester au sec en navigation hivernale.

Comment Choisir Votre Combinaison ?

Épaisseur en Fonction de la Température de l’Eau

  • 1-2 mm : eaux chaudes (18-23°C).

  • 3/2 mm : mi-saison (13-18°C).

  • 4/3 mm ou 5/4 mm : hiver (8-14°C).

  • 6/5/4 mm + gants, cagoule, chaussons : eaux très froides (<8°C).

Type de Fermeture

  • Frontzip : ajustement optimal et isolation renforcée.

  • Backzip : enfilage facile.

  • Zipless : liberté de mouvement maximale.

Accessoires Néoprène Indispensables

Complétez votre équipement pour un confort optimal :

  • Cagoules, gants & chaussons : indispensables en hiver.

  • Leggings & shorts néoprène : liberté pour SUP & longe côte.

  • Lycras & tops anti-UV : protection solaire pour l’été.

  • Sacs étanches : transport propre et pratique de votre matériel.

Les Meilleures Marques Disponibles

Nous sélectionnons les références du néoprène :
Rip Curl, Billabong, O’Neill, ION et bien d’autres.
Que vous soyez débutant ou rider confirmé, vous trouverez une combinaison adaptée à vos besoins.

Pourquoi Choisir GlissEvolution ?

  • Large choix de combinaisons et accessoires pour toutes les pratiques.

  • Conseils personnalisés : experts à votre écoute en ligne et en boutique.

  • Essais possibles en magasin à Pornichet.

  • Disponibilité immédiate en boutique et en ligne.

Prêt à Affronter les Vagues ?

Avec GlissEvolution, profitez de combinaisons néoprène et accessoires conçus pour maximiser vos performances et votre confort.
Explorez notre gamme en ligne ou venez en boutique bénéficier de conseils sur-mesure.

VOIR LES Guides et tutos