# Afficher des produits

Tout passe par une seule classe. Un développeur qui refait la vitrine
n'a jamais besoin de toucher aux modèles ni de connaître les tables.

```php
require_once __DIR__ . '/../../modules/commerce/Services/Catalog.php';
```

## Lister des produits

```php
$result = Catalog::products([
    'shop'     => 'le-yaki-corner',  // vide = boutique courante
    'category' => 'magnets',
    'search'   => 'rando',
    'sort'     => 'price',           // recent | name | price | price-desc
    'limit'    => 12,
    'page'     => 1,
]);

foreach ($result['items'] as $p) {
    echo $p['name'], ' — ', $p['price_from'], ' — ', $p['url'];
}
```

Le retour porte `items`, `total`, `pages`, `page` et `shop`.

Chaque produit porte : `id`, `slug`, `sku`, `name`,
`short_description`, `image`, `price_from`, `price_to`, `on_sale`,
`available` et `url`.

## Un bloc de produits choisis

Pour une sélection sur l'accueil, dans un article, n'importe où :

```php
$mis_en_avant = Catalog::products(['ids' => [12, 45, 78]]);
```

## Les catégories

```php
foreach (Catalog::categories() as $c) {
    echo $c['name'], ' (', $c['total'], ')';
}
```

Seules celles ayant au moins un produit publiable sortent : un filtre
qui ne ramène rien fait douter du site.

## Un produit précis

```php
$produit = Catalog::product('magnet-rando');

if ($produit === null) {
    // Absent, inactif, ou boutique fermée
}
```

## Ce qui est garanti

Quelle que soit la façon d'appeler, seuls sortent les produits
**publiables** : actifs, non supprimés, d'une boutique ouverte, traduits
dans la langue courante.

Un brouillon ne peut pas fuiter par un gabarit personnalisé.

## Les adresses

Ne les composez pas à la main — elles changeraient sans prévenir.

```php
Catalog::url($shop, 'magnet-rando')          // /boutique/p/magnet-rando
Catalog::categoryUrl($shop, 'magnets')       // /boutique/c/magnets
Catalog::categoryUrl($shop)                  // /boutique
```

## Remplacer l'affichage

Trois niveaux, du plus léger au plus radical.

**Ajouter du contenu** sans rien toucher :

```php
Hooks::on('catalog.card.after', function (array $ctx) {
    echo '<span>' . $ctx['product']['sku'] . '</span>';
});
```

**Transformer la liste** avant affichage :

```php
Hooks::filter('catalog.products', function (array $result) {
    // Marquer les nouveautés, retirer certains produits…
    return $result;
});
```

**Remplacer le gabarit** entièrement : copiez
`views/pages/shop-catalog.php` dans `site/custom/pages/`, le vôtre
prend le dessus.

**Ou ignorez tout ça** : appelez `Catalog::products()` depuis votre
propre page, et n'utilisez rien du module côté affichage.

## Accroches disponibles

```
catalog.before              au-dessus de la liste
catalog.after               en dessous
catalog.card.before         avant chaque vignette
catalog.card.after          après chaque vignette

filter:catalog.products     liste de produits, avant affichage
filter:catalog.categories   liste des catégories
```
