# MediaUpload et MediaPlaceholder : créer un bloc image personnalisé

> Sélection, remplacement, texte alternatif, rendu responsive dans save : le parcours complet pour un bloc image sur mesure, du placeholder vide à la publication.

- Auteur : Clément Hadrot
- Publié le : 2020-08-06
- Mis à jour le : 2020-08-06
- Catégorie : Blocs Gutenberg
- URL : https://wpmoderne.dev.wordpress-developpement.fr/blocs/mediaupload-mediaplaceholder-bloc-image-personnalise/

## L’essentiel

- MediaPlaceholder gère l'état vide et l'import initial
- MediaUpload permet de remplacer une image déjà choisie
- Stocker id et url, jamais url seule, pour garder le lien vers la médiathèque

Un bloc « portrait d'équipe » avec une seule image, un texte alternatif propre et un rendu qui respecte les dimensions réelles du fichier téléversé : voici étape par étape la construction complète, du placeholder vide jusqu'au rendu final côté front.

## Étape 1 : déclarer les attributs

```
{
	"attributes": {
		"mediaId": { "type": "number" },
		"mediaUrl": { "type": "string", "default": "" },
		"mediaAlt": { "type": "string", "default": "" }
	}
}
```

Stocker l'identifiant (`mediaId`) en plus de l'URL n'est pas superflu : il permet de retrouver l'image dans la médiathèque, de la remplacer facilement, et surtout de régénérer les tailles d'image côté serveur si un thème change ses dimensions par défaut.

## Étape 2 : l'état vide avec MediaPlaceholder

```
import { MediaPlaceholder } from '@wordpress/block-editor';

if ( ! attributes.mediaUrl ) {
	return (
		<MediaPlaceholder
			icon="format-image"
			labels={ { title: 'Portrait' } }
			onSelect={ ( media ) => {
				setAttributes( {
					mediaId: media.id,
					mediaUrl: media.url,
					mediaAlt: media.alt,
				} );
			} }
			accept="image/*"
			allowedTypes={ [ 'image' ] }
		/>
	);
}
```

`MediaPlaceholder` affiche par défaut un bouton d'import (glisser-déposer, sélection dans la médiathèque, ou saisie d'une URL externe selon la configuration). Il ne s'affiche que tant qu'aucune image n'est choisie, d'où la condition en tête de la fonction `edit`.

## Étape 3 : remplacer l'image avec MediaUpload

> L'essentiel à retenir : MediaPlaceholder gère l'état vide et l'import initial ; MediaUpload permet de remplacer une image déjà choisie ; Stocker id et url, jamais url seule, pour garder le lien vers la médiathèque

Une fois une image choisie, il faut permettre à l'auteur de la changer sans tout recommencer. `MediaUpload` encapsule ce comportement via une fonction de rendu (render props) :

```
import { MediaUpload } from '@wordpress/block-editor';
import { Button } from '@wordpress/components';

<MediaUpload
	onSelect={ ( media ) =>
		setAttributes( {
			mediaId: media.id,
			mediaUrl: media.url,
			mediaAlt: media.alt,
		} )
	}
	allowedTypes={ [ 'image' ] }
	value={ attributes.mediaId }
	render={ ( { open } ) => (
		<Button onClick={ open } variant="secondary">
			Changer l'image
		</Button>
	) }
/>
```

La prop `value` alimentée avec `mediaId` permet à la médiathèque de présélectionner l'image actuelle quand elle s'ouvre, un détail qui évite à l'utilisateur de devoir la rechercher à nouveau parmi des centaines de fichiers.

## Étape 4 : le texte alternatif, souvent oublié

Le texte alternatif récupéré automatiquement (`media.alt`) correspond au champ renseigné dans la médiathèque, pas nécessairement adapté au contexte précis du bloc. Un champ `TextControl` dans l'inspecteur, relié à `mediaAlt`, permet de le personnaliser sans modifier la médiathèque globale :

```
<TextControl
	label="Texte alternatif"
	value={ attributes.mediaAlt }
	onChange={ ( mediaAlt ) => setAttributes( { mediaAlt } ) }
	help="Décrit l'image pour les lecteurs d'écran."
/>
```

## Étape 5 : un rendu responsive dans save()

```
export default function save( { attributes } ) {
	const { mediaUrl, mediaAlt } = attributes;
	if ( ! mediaUrl ) return null;
	return (
		<figure>
			<img src={ mediaUrl } alt={ mediaAlt } loading="lazy" />
		</figure>
	);
}
```

L'attribut `loading="lazy"` sur l'élément `img` profite du chargement différé natif du navigateur sans script additionnel. Pour un rendu vraiment responsive avec plusieurs tailles (`srcset`), il est possible de basculer sur un bloc dynamique qui reconstruit la balise via `wp_get_attachment_image` côté PHP, au prix d'un aller-retour serveur supplémentaire.

- Toujours prévoir un état où `mediaUrl` est vide, y compris dans `save()`, pour éviter un bloc cassé si l'attribut n'a jamais été rempli.
- Ne jamais coder en dur un identifiant d'image issu d'un autre environnement : entre un serveur de développement et la production, les identifiants de la médiathèque ne coïncident pas forcément.

> Un bloc image sans champ de texte alternatif accessible dans l'inspecteur reste, à nos yeux, un bloc incomplet, quelle que soit la qualité du reste de l'implémentation.

## Notre verdict

`MediaPlaceholder` et `MediaUpload` couvrent, à eux deux, tout le cycle de vie d'une image dans un bloc personnalisé : sélection initiale, remplacement, et accès direct à la médiathèque native de WordPress sans réinventer un composant d'upload maison.
