# Service Colors — Palette Gutenberg

Le service `Colors` (Devopress) permet de gérer la palette de couleurs de l'éditeur Gutenberg via `wp_options`. Il s'enregistre automatiquement dans le Kernel.

## API

```php
$colors = $this->getService(Colors::NAME);

$colors->add(['name' => 'Primaire', 'slug' => 'primary', 'color' => '#0073e6']);
$colors->update('primary', ['color' => '#005bb5']);
$colors->remove('primary');
$colors->get('primary');   // ?array
$colors->getAll();         // array
$colors->register();       // appelle add_theme_support('editor-color-palette', ...)
$colors->reset();          // vide la palette
```

> **Note :** Les slugs sont sanitizés via `sanitize_title()` au stockage. `primary_test` devient `primary-test` pour correspondre aux classes CSS générées par Gutenberg (`.has-primary-test-color`).

## Injection CSS front-end

Le service injecte automatiquement les classes `.has-{slug}-color` et `.has-{slug}-background-color` via `wp_enqueue_scripts` (priorité 20).

## Intégration Customizer — `add_to_editor`

Les champs de type `color_contrast` dans la configuration YAML du Customizer acceptent la propriété `add_to_editor: true`. Cela enregistre automatiquement la couleur dans la palette Gutenberg.

```yaml
my_color:
    label: "Couleur principale"
    type: "color_contrast"
    default: "#2d2a24"
    add_to_editor: true
    editor_slug: "primary"   # slug propre pour Gutenberg (optionnel, défaut: id du champ)
```

---

# Customizer — Sélecteur CSS pour les sections dynamiques

Les sections avec `iteration` dans la config YAML génèrent plusieurs instances d'une même section. Pour que le Selective Refresh du Customizer cible le bon élément dans la prévisualisation, le sélecteur CSS supporte le placeholder `{i}`.

## Utilisation

Dans la config YAML d'un champ, définir un `selector` avec `{i}` :

```yaml
my_panel:
    sections:
        my_section:
            iteration: 3
            fields:
                my_field:
                    label: "Titre"
                    type: "text"
                    selector: ".my-component[data-iteration={i}] .title"
```

Au runtime, `{i}` est remplacé par `data-iteration=<numéro>`, ce qui donne pour l'itération 2 :

```css
.my-component[data-iteration=2] .title
```

Cela permet au Customizer de rafraîchir uniquement l'instance concernée sans recharger la page entière.

---

# Blocs Gutenberg — Rendu Twig

## Problème : `$this->render()` inaccessible dans les blocs

`GutenbergBlock` étend `Controller`, mais le service `Blocks` instancie les blocs **avant** `TwigService` dans l'ordre de boot du Kernel :

```
… → Blocks → … → TwigService → ControllerResolver
```

Le constructeur de `Controller` initialise `$this->twig` via `$kernel->getService(TwigService::NAME)`. Comme ce service n'existe pas encore au moment de l'instanciation des blocs, les constructeurs de blocs **ne peuvent pas** appeler `parent::__construct()`. La propriété `$this->twig` reste donc non initialisée, et tout appel à `$this->render()` dans `renderBlock()` provoque une erreur fatale :

```
Typed property Elementum\Abstract\Controller::$twig must not be accessed before initialization
```

## Solution : utiliser `$this->getService()` dans `renderBlock()`

La méthode `getService()` (héritée de `Controller`) accède directement au Kernel via `global $kernel`, sans dépendre du constructeur. Au moment où `renderBlock()` est appelé (lors du rendu front), tous les services sont disponibles.

```php
<?php

namespace Elementum\MonPlugin\Blocks;

use Elementum\Abstract\GutenbergBlock;
use Elementum\Services\Twig\TwigService;

class MonBlock extends GutenbergBlock
{
    public function __construct()
    {
        $this
            ->setBlockFile(__FILE__)
            ->setName('Mon bloc')
            ->setSlug('mon-bloc')
            ->setPrefix('mon-plugin')
            ->addAttribute('title', 'string', '');

        // ⚠ NE PAS appeler parent::__construct() — TwigService n'est pas encore enregistré.
    }

    public function renderBlock($attributes): void
    {
        // ✅ Récupérer TwigService à la demande via getService()
        $twig = $this->getService(TwigService::NAME);
        echo $twig->render('@mon-plugin/blocks/mon-bloc.html.twig', [
            'title' => $attributes['title'] ?? '',
            'innerBlocks' => $attributes['innerBlocks'] ?? '',
        ]);
    }
}
```

### Points importants

| Règle | Détail |
|---|---|
| Ne pas appeler `parent::__construct()` | TwigService n'est pas disponible au boot des blocs |
| Ne pas utiliser `$this->render()` | Dépend de `$this->twig` initialisé par le constructeur parent |
| Utiliser `$this->getService(TwigService::NAME)` | Accès direct au Kernel, fonctionne à tout moment après le boot |
| Namespace Twig obligatoire | `@theme/`, `@nexus/`, `@mon-plugin/` — requis car on appelle `$twig->render()` directement au lieu de `$this->render()` du Controller |

---

# Emails - Tags Twig

Elementum fournit un système de tags Twig pour construire des emails HTML responsive avec une syntaxe lisible, sans manipuler directement les `<table>` de layout.

## Template de base

Tous les emails étendent `@elementum/emails/base.html.twig` qui fournit :

- Le doctype HTML et les meta (charset, viewport)
- Les styles de base (typographie, responsive, classes utilitaires)
- Un layout centré avec conteneur de 800px max

### Blocs disponibles

| Bloc | Rôle |
|---|---|
| `header` | En-tête (logo + titre) |
| `logo` | Logo seul (à l'intérieur du header) |
| `content` | Contenu principal de l'email |
| `footer` | Pied de page (copyright automatique) |

### Classes CSS disponibles

| Classe | Effet |
|---|---|
| `.text-muted` | Texte gris (`#6c757d`) |
| `.text-center` | Texte centré |
| `.mt-3` | Marge haute 1rem |
| `.mb-3` | Marge basse 1rem |

### Variables globales

| Variable | Source |
|---|---|
| `site.name` | Nom du site WordPress |
| `title` | Défini via `{% set title = "..." %}` dans le template enfant |

## Tags

### `{% email_row %}`

Conteneur pleine largeur avec padding horizontal (24px).

```twig
{% email_row %}
    <p>Mon contenu texte.</p>
{% endemail_row %}
```

Avec du style custom :

```twig
{% email_row {style: 'background: #f8f9fa;'} %}
    <p>Contenu avec fond gris.</p>
{% endemail_row %}
```

**HTML généré :**

```html
<table role="presentation" border="0" cellspacing="0" cellpadding="0" width="100%">
  <tr>
    <td style="padding: 0 24px;">
      <p>Mon contenu texte.</p>
    </td>
  </tr>
</table>
```

### `{% email_button %}`

Bouton CTA cliquable, centré par défaut.

```twig
{% email_button {url: adminUrl} %}
    Accéder à l'administration
{% endemail_button %}
```

| Option | Défaut | Description |
|---|---|---|
| `url` | `#` | Lien du bouton (obligatoire) |
| `align` | `center` | Alignement (`left`, `center`, `right`) |
| `bgColor` | `#007bff` | Couleur de fond |
| `color` | `#ffffff` | Couleur du texte |
| `padding` | `12px 24px` | Padding interne |
| `borderRadius` | `4px` | Arrondi des coins |
| `fontSize` | `14px` | Taille du texte |
| `style` | | CSS additionnel |

Exemple avec personnalisation :

```twig
{% email_button {url: resetUrl, bgColor: '#dc3545'} %}
    Réinitialiser mon mot de passe
{% endemail_button %}
```

### `{% email_cols %}` + `{% email_col %}`

Système de colonnes pour disposer du contenu côte à côte.

```twig
{% email_cols %}
    {% email_col {width: '60%'} %}
        <p>Colonne principale</p>
    {% endemail_col %}
    {% email_col {width: '40%'} %}
        <p>Colonne secondaire</p>
    {% endemail_col %}
{% endemail_cols %}
```

**`email_cols` options :**

| Option | Défaut | Description |
|---|---|---|
| `style` | | CSS sur le `<tr>` conteneur |

**`email_col` options :**

| Option | Défaut | Description |
|---|---|---|
| `width` | `50%` | Largeur de la colonne |
| `style` | | CSS additionnel |

## Macro `spacer`

Le spacer reste une macro Twig classique car il n'encapsule pas de contenu.

```twig
{% from "@elementum/emails/macros.html.twig" import spacer %}

{{ spacer(16) }}   {# espace de 16px #}
{{ spacer() }}     {# 16px par défaut #}
{{ spacer(32) }}   {# espace de 32px #}
```

## Exemple complet

```twig
{% extends "@elementum/emails/base.html.twig" %}

{% set title = "Bienvenue" %}

{% block content %}
    {% from "@elementum/emails/macros.html.twig" import spacer %}

    {% email_row %}
        <p>Bonjour <strong>{{ username }}</strong>,</p>
        <p>Votre compte a bien été créé.</p>
    {% endemail_row %}

    {{ spacer(16) }}

    {% email_row %}
        <p class="text-muted" style="font-size: 13px;">
            Vous pouvez maintenant vous connecter.
        </p>
    {% endemail_row %}

    {% email_button {url: loginUrl} %}
        Se connecter
    {% endemail_button %}
{% endblock %}
```

## Fichiers

| Fichier | Rôle |
|---|---|
| `views/emails/base.html.twig` | Layout de base des emails |
| `views/emails/macros.html.twig` | Macro `spacer` |
| `app/Twig/Tags/Emails/Row.php` | Tag `email_row` |
| `app/Twig/Tags/Emails/Button.php` | Tag `email_button` |
| `app/Twig/Tags/Emails/Columns.php` | Tag `email_cols` |
| `app/Twig/Tags/Emails/Column.php` | Tag `email_col` |
