diff --git a/formulaires/editer_bloc.html b/formulaires/editer_bloc.html
index 93351fcca8c86c7b41e48ef7518e9abcf9a03c08..41a8c53e37aab4520893b30a3affeb6287381828 100644
--- a/formulaires/editer_bloc.html
+++ b/formulaires/editer_bloc.html
@@ -1,19 +1,32 @@
-<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_bloc,nouveau}'>
+<div id="formulaire_#FORM" class='formulaire_spip formulaire_editer formulaire_#FORM'>
 	[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
 	[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
 
-	[(#ENV{editable})
-	<form method="post" action="#ENV{action}"><div>
-		#ACTION_FORMULAIRE
-		<input type="hidden" name="id_bloc" value="#ENV{id_bloc}" />
-		<div class="editer-groupe">
+	<BOUCLE_editable(CONDITION){si #ENV{editable}}>
 
-			#GENERER_SAISIES{#ENV*{_saisies}}
+	<form method='post' action='[(#ENV{action}|ancre_url{[formulaire_#ENV{form}-(#ENV{id,nouveau})]})]' enctype='multipart/form-data'><div>
+		#ACTION_FORMULAIRE{#ENV{action}}
+		<input type="hidden" name="id_bloc" value="#ID_BLOC">
 
+		<div class="editer-groupe">
+			#SET{saisies, #ENV{_saisies}}
+			[(#ENV{_etape}|oui)
+				[(#ENV{_saisies/options/etapes_ignorer_recapitulatif}|non|et{#ENV{_etape}|=={#ENV{_etapes}}}|oui)
+					<INCLURE{fond=formulaires/inc-saisies-cvt-etapes-recapitulatif,env} />
+				]
+				[(#ENV{_saisies/options/etapes_ignorer_recapitulatif}|non|et{#ENV{_etape}|=={#ENV{_etapes}}}|non)
+					#SET{saisies, #GET{etapes}|table_valeur{etape_#ENV{_etape}/saisies}}
+					#GENERER_SAISIES{#GET{saisies},saisies_par_etapes=#ENV{_saisies_par_etapes}}
+				]
+			]
+			[(#ENV{_etape}|non)
+				#GENERER_SAISIES{#GET{saisies}}
+			]
 		</div>
-		[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
-		<!--extra-->
-		<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer|attribut_html:/>" /></p>
+
+		<INCLURE{fond=formulaires/inc-saisies-cvt-boutons,saisies_texte_submit=<:bouton_valider:>,env} />
+
 	</div></form>
-	]
+
+	</BOUCLE_editable>
 </div>
diff --git a/formulaires/editer_bloc.php b/formulaires/editer_bloc.php
index 2a70058115394539193dc421d643a91b63c4669d..04f04add1b7444a7f9caf0c8d370ba6491bfe242 100644
--- a/formulaires/editer_bloc.php
+++ b/formulaires/editer_bloc.php
@@ -13,53 +13,78 @@ if (!defined('_ECRIRE_INC_VERSION')) {
 	return;
 }
 
+include_spip('blocks_fonctions');
 include_spip('inc/actions');
 include_spip('inc/editer');
 
 /**
  * Déclaration des saisies de bloc
  *
- * @param int|string $id_bloc
- *     Identifiant du bloc. 'new' pour un nouveau bloc.
- * @param int        $id_blocs_type
- *     Identifiant de l'objet parent (si connu)
- * @param string     $retour
- *     URL de redirection après le traitement
- * @param int        $lier_trad
- *     Identifiant éventuel d'un bloc source d'une traduction
- * @param string     $config_fonc
- *     Nom de la fonction ajoutant des configurations particulières au formulaire
- * @param array      $row
- *     Valeurs de la ligne SQL du bloc, si connu
- * @param string     $hidden
- *     Contenu HTML ajouté en même temps que les champs cachés du formulaire.
- * @return array[]
- *     Saisies du formulaire
+ * @param int|string $id_bloc  Identifiant du bloc. 'new' pour un nouveau bloc.
+ * @param null       $objet    Type d'objet à associer (article, rubrique,...)
+ * @param null       $id_objet Id de l'objet à associer
+ * @param null       $retour   URL de redirection après le traitement
+ * @return array               Saisies du formulaire
  */
-function formulaires_editer_bloc_saisies_dist($id_bloc = 'new', $id_blocs_type = 0, $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
+function formulaires_editer_bloc_saisies_dist($id_bloc = 'new', $objet = null, $id_objet = null, $retour = null) {
+	if ((int)$id_bloc) {
+		$id_blocs_type = (int)sql_getfetsel('id_blocs_type', 'spip_blocs', 'id_bloc = ' . $id_bloc);
+	} else {
+		$id_blocs_type = (int)_request('id_blocs_type');
+	}
+
+	$saisies_bloc_type = [];
+	if ($id_blocs_type && ($saisies_json = sql_getfetsel('saisies', 'spip_blocs_types', 'id_blocs_type = ' . $id_blocs_type))) {
+		$saisies_bloc_type = blocks_deserialize($saisies_json);
+	}
+
 	$saisies = [
+		'options' =>
+			[
+				'texte_submit'                    => '',
+				'afficher_si_submit'              => '',
+				'etapes_activer'                  => 'on',
+				'etapes_presentation'             => 'courante',
+				'etapes_suivant'                  => '',
+				'etapes_precedent'                => '',
+				'etapes_precedent_suivant_titrer' => '',
+				'etapes_ignorer_recapitulatif'    => 'on',
+				'verifier_valeurs_acceptables'    => '',
+			],
 		[
-			'saisie'  => 'input',
+			'saisie'  => 'fieldset',
 			'options' => [
-				'nom'         => 'titre',
-				'obligatoire' => 'oui',
-				'label'       => _T('bloc:champ_titre_label'),
-
+				'nom'   => 'bloc_config',
+				'label' => _T('bloc:champ_bloc_config_label'),
+			],
+			'saisies' => [
+				[
+					'saisie'  => 'input',
+					'options' => [
+						'nom'         => 'titre',
+						'obligatoire' => 'oui',
+						'label'       => _T('bloc:champ_titre_label'),
+					],
+				],
+				[
+					'saisie'  => ($id_blocs_type ? 'hidden' : 'blocs_types'),
+					'options' => [
+						'nom'         => 'id_blocs_type',
+						'obligatoire' => 'oui',
+						'label'       => _T('bloc:champ_id_blocs_type_label'),
+					],
+				],
 			],
 		],
-	];
-
-	// on ne peut choisir le type qu'à la création
-	if (!(int)$id_bloc) {
-		$saisies[] = [
-			'saisie'  => 'blocs_types',
+		[
+			'saisie'  => 'fieldset',
 			'options' => [
-				'nom'         => 'id_blocs_type',
-				'obligatoire' => 'oui',
-				'label'       => _T('blocs_type:titre_blocs_type'),
+				'nom'   => 'bloc_contenu',
+				'label' => _T('bloc:champ_bloc_contenu_label'),
 			],
-		];
-	}
+			'saisies' => $saisies_bloc_type,
+		],
+	];
 
 	return $saisies;
 }
@@ -67,25 +92,14 @@ function formulaires_editer_bloc_saisies_dist($id_bloc = 'new', $id_blocs_type =
 /**
  * Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
  *
- * @param int|string $id_bloc
- *     Identifiant du bloc. 'new' pour un nouveau bloc.
- * @param int        $id_blocs_type
- *     Identifiant de l'objet parent (si connu)
- * @param string     $retour
- *     URL de redirection après le traitement
- * @param int        $lier_trad
- *     Identifiant éventuel d'un bloc source d'une traduction
- * @param string     $config_fonc
- *     Nom de la fonction ajoutant des configurations particulières au formulaire
- * @param array      $row
- *     Valeurs de la ligne SQL du bloc, si connu
- * @param string     $hidden
- *     Contenu HTML ajouté en même temps que les champs cachés du formulaire.
- * @return string
- *     Hash du formulaire
+ * @param int|string $id_bloc  Identifiant du bloc. 'new' pour un nouveau bloc.
+ * @param null       $objet    Type d'objet à associer (article, rubrique,...)
+ * @param null       $id_objet Id de l'objet à associer
+ * @param null       $retour   URL de redirection après le traitement
+ * @return string              Hash du formulaire
  */
-function formulaires_editer_bloc_identifier_dist($id_bloc = 'new', $id_blocs_type = 0, $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
-	return serialize([intval($id_bloc)]);
+function formulaires_editer_bloc_identifier_dist($id_bloc = 'new', $objet = null, $id_objet = null, $retour = null) {
+	return serialize([intval($id_bloc), $objet, $id_objet]);
 }
 
 /**
@@ -93,33 +107,39 @@ function formulaires_editer_bloc_identifier_dist($id_bloc = 'new', $id_blocs_typ
  *
  * Déclarer les champs postés et y intégrer les valeurs par défaut
  *
- * @param int|string $id_bloc
- *     Identifiant du bloc. 'new' pour un nouveau bloc.
- * @param int        $id_blocs_type
- *     Identifiant de l'objet parent (si connu)
- * @param string     $retour
- *     URL de redirection après le traitement
- * @param int        $lier_trad
- *     Identifiant éventuel d'un bloc source d'une traduction
- * @param string     $config_fonc
- *     Nom de la fonction ajoutant des configurations particulières au formulaire
- * @param array      $row
- *     Valeurs de la ligne SQL du bloc, si connu
- * @param string     $hidden
- *     Contenu HTML ajouté en même temps que les champs cachés du formulaire.
- * @return array
- *     Environnement du formulaire
+ * @param int|string $id_bloc  Identifiant du bloc. 'new' pour un nouveau bloc.
+ * @param null       $objet    Type d'objet à associer (article, rubrique,...)
+ * @param null       $id_objet Id de l'objet à associer
+ * @param null       $retour   URL de redirection après le traitement
+ * @return array               Environnement du formulaire
  * @uses formulaires_editer_objet_charger()
- *
  */
-function formulaires_editer_bloc_charger_dist($id_bloc = 'new', $id_blocs_type = 0, $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
-	$valeurs = formulaires_editer_objet_charger('bloc', $id_bloc, $id_blocs_type, $lier_trad, $retour, $config_fonc, $row, $hidden);
+function formulaires_editer_bloc_charger_dist($id_bloc = 'new', $objet = null, $id_objet = null, $retour = null) {
+	if ((int)$id_bloc) {
+		$id_blocs_type = (int)sql_getfetsel('id_blocs_type', 'spip_blocs', 'id_bloc = ' . $id_bloc);
+	} else {
+		$id_blocs_type = (int)_request('id_blocs_type');
+	}
+
+	$valeurs = formulaires_editer_objet_charger('bloc', $id_bloc, $id_blocs_type, 0, $retour, '');
 	if (!$valeurs['id_blocs_type']) {
 		$valeurs['id_blocs_type'] = $id_blocs_type;
 	}
-
 	$valeurs['saisies'] = call_user_func_array('formulaires_editer_bloc_saisies_dist', func_get_args());
 
+	// mettre à jour le bloc avec les valeurs saisies
+	$saisies_bloc_type = [];
+	if ($saisies_json = sql_getfetsel('saisies', 'spip_blocs_types', 'id_blocs_type = ' . $id_blocs_type)) {
+		$saisies_bloc_type = blocks_deserialize($saisies_json);
+	}
+	if ($valeurs_saisies = blocks_deserialize($valeurs['valeurs'])) {
+		include_spip('inc/saisies_lister');
+		$saisies_par_nom = saisies_lister_par_nom($saisies_bloc_type);
+		foreach ($saisies_par_nom as $nom => $saisie) {
+			$valeurs[$nom] = $valeurs_saisies[$nom];
+		}
+	}
+
 	return $valeurs;
 }
 
@@ -128,60 +148,69 @@ function formulaires_editer_bloc_charger_dist($id_bloc = 'new', $id_blocs_type =
  *
  * Vérifier les champs postés et signaler d'éventuelles erreurs
  *
- * @param int|string $id_bloc
- *     Identifiant du bloc. 'new' pour un nouveau bloc.
- * @param int        $id_blocs_type
- *     Identifiant de l'objet parent (si connu)
- * @param string     $retour
- *     URL de redirection après le traitement
- * @param int        $lier_trad
- *     Identifiant éventuel d'un bloc source d'une traduction
- * @param string     $config_fonc
- *     Nom de la fonction ajoutant des configurations particulières au formulaire
- * @param array      $row
- *     Valeurs de la ligne SQL du bloc, si connu
- * @param string     $hidden
- *     Contenu HTML ajouté en même temps que les champs cachés du formulaire.
- * @return array
- *     Tableau des erreurs
+ * @param int|string $id_bloc  Identifiant du bloc. 'new' pour un nouveau bloc.
+ * @param string     $retour   URL de redirection après le traitement
+ * @param null       $objet    Type d'objet à associer (article, rubrique,...)
+ * @param null       $id_objet Id de l'objet à associer
+ * @return array                    Tableau des erreurs
  * @uses formulaires_editer_objet_verifier()
- *
  */
-function formulaires_editer_bloc_verifier_dist($id_bloc = 'new', $id_blocs_type = 0, $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
-	$obligatoires = ['titre'];
-
-	// le type est obligatoire à la création
-	if (!(int)$id_bloc) {
-		$obligatoires[] = 'id_blocs_type';
-	}
-
-	return formulaires_editer_objet_verifier('bloc', $id_bloc, $obligatoires);
-}
+//function formulaires_editer_bloc_verifier_dist($id_bloc = 'new', $objet = null, $id_objet = null, $retour = null) {
+//	$erreurs = formulaires_editer_objet_verifier('bloc', $id_bloc, ['titre', 'id_blocs_type']);
+//	return $erreurs;
+//}
 
 /**
  * Traitement du formulaire d'édition de bloc
  *
  * Traiter les champs postés
  *
- * @param int|string $id_bloc
- *     Identifiant du bloc. 'new' pour un nouveau bloc.
- * @param int        $id_blocs_type
- *     Identifiant de l'objet parent (si connu)
- * @param string     $retour
- *     URL de redirection après le traitement
- * @param int        $lier_trad
- *     Identifiant éventuel d'un bloc source d'une traduction
- * @param string     $config_fonc
- *     Nom de la fonction ajoutant des configurations particulières au formulaire
- * @param array      $row
- *     Valeurs de la ligne SQL du bloc, si connu
- * @param string     $hidden
- *     Contenu HTML ajouté en même temps que les champs cachés du formulaire.
- * @return array
- *     Retours des traitements
+ * @param int|string $id_bloc  Identifiant du bloc. 'new' pour un nouveau bloc.
+ * @param string     $retour   URL de redirection après le traitement
+ * @param null       $objet    Type d'objet à associer (article, rubrique,...)
+ * @param null       $id_objet Id de l'objet à associer
+ * @return array               Retours des traitements
  * @uses formulaires_editer_objet_traiter()
- *
  */
-function formulaires_editer_bloc_traiter_dist($id_bloc = 'new', $id_blocs_type = 0, $retour = '', $lier_trad = 0, $config_fonc = '', $row = [], $hidden = '') {
-	return formulaires_editer_objet_traiter('bloc', $id_bloc, $id_blocs_type, $lier_trad, $retour, $config_fonc, $row, $hidden);
+function formulaires_editer_bloc_traiter_dist($id_bloc = 'new', $objet = null, $id_objet = null, $retour = null) {
+	if ((int)$id_bloc) {
+		$id_blocs_type = (int)sql_getfetsel('id_blocs_type', 'spip_blocs', 'id_bloc = ' . $id_bloc);
+	} else {
+		$id_blocs_type = (int)_request('id_blocs_type');
+	}
+
+	$retours = formulaires_editer_objet_traiter('bloc', $id_bloc, $id_blocs_type, 0, $retour, '');
+
+	if ($id_bloc = $retours['id_bloc']) {
+
+		// mettre à jour le bloc avec les valeurs saisies
+		$saisies_bloc_type = [];
+		if ($saisies_json = sql_getfetsel('saisies', 'spip_blocs_types', 'id_blocs_type = ' . $id_blocs_type)) {
+			$saisies_bloc_type = blocks_deserialize($saisies_json);
+		}
+		include_spip('inc/saisies_lister');
+		$valeurs = [];
+		$saisies_par_nom = saisies_lister_par_nom($saisies_bloc_type);
+		foreach ($saisies_par_nom as $nom => $saisie) {
+			$valeurs[$nom] = _request($nom);
+		}
+		sql_updateq('spip_blocs', ['valeurs' => blocks_serialize($valeurs)], 'id_bloc = ' . $id_bloc);
+
+		// associer à l'objet
+		if ($objet
+			&& ($id_objet = (int)$id_objet)
+			&& autoriser('modifier', $objet, $id_objet)
+		) {
+			include_spip('action/editer_liens');
+			objet_associer(['bloc' => $id_bloc], [$objet => $id_objet]);
+
+			if (isset($retours['redirect'])) {
+				$retours['redirect'] = parametre_url($retours['redirect'], 'id_lien_ajoute', $id_bloc, '&');
+			}
+
+		}
+
+	}
+
+	return $retours;
 }