Enregistrement d’une image à partir du Front-End dans la médiathèque WordPress

10. avril 2017 Hook, Wordpress 0
Enregistrement d’une image à partir du Front-End dans la médiathèque WordPress

Nous allons présenter une méthode afin de mettre en ligne un fichier (dans notre cas une image) pour un post (contenu) donné.

Cet article va donner les sources pour le réaliser de manière dite « manuel », sinon vous pouriez très bien utiliser des outils comme :

  • CMB2 — Framework de formulaires
  • Pods — Framework plus orienté sur les objets WordPress (contenu personnalisé ou Custom Post Type, taxonomie, etc.) et la possibilité d’étendre un objet avec des tables spécifiques.
  • ou encore ACF (plus besoin de le citer).

 

Pour notre exemple, nous allons partir du principe :

  • Nous avons un espace personnel pour les membres connectés en front-office,
  • Que nous voulons éditer l’image à la une d’un post (lié bien sur à l’utilisateur),
  • L’image uploadée (téléchargée) remplacera l’image actuelle (s’il y en a une) et la supprimera,
  • L’image n’aura qu’une miniature (medium),
  • L’image sera stockée dans un répertoire spécifique,
  • L’image aura un nom imposée sur le serveur (id du post).

 

Le formulaire

Bien sur, ça commence par un formulaire. Donc là on ne va pas s’embêter, on vas se concentrer sur ce qui nous intéresse : l’image. Pas de champs superflus, par contre je laisse les champs de test comme :

  • les nonces bien sûr,
  • l’information du post a modifier ($post_id),
  • un champ action pour déclencher le processus de sauvegarde,
  • l’identifiant de l’utilisateur (post_author) et le type de post (post_type) pour des raison de sécurité.

Vous noterez que nous passons par admin-post.php pour le script de mise à jour.

Vous pouvez aussi mettre le formulaire dans un shortcode afin de le placer dans le contenu d’une page.

(Code à placer dans le thème)

<?php $post_id = {on récupère l'identifiant du post}; ?>
<?php $action = 'edit-moncpt'; ?>
<?php $current_user = wp_get_current_user(); ?>
<form name="post" action="<?php echo admin_url( 'admin-post.php' ); ?>" method="post" id="edit-cpt" enctype="multipart/form-data">

	<?php echo get_the_post_thumbnail( $post_id, 'medium' ); ?>
	
	<input type="file" name="image" id="image" accept="image/png, image/jpeg">
		
	<?php
	/**
	* Autres champs de formulaire à implémenter si besoin
	*/
	?>
	<input name="post_id" id="post_id" type="hidden" value="<?php echo $post_id; ?>">
	<input name="action" id="action" type="hidden" value="<?php echo $action; ?>">
	<input name="post_author" id="post_author" type="hidden" value="<?php echo $current_user->ID;?>">
	<input name="post_type" id="post_type" type="hidden" value="cpt-slug">
	<?php
	wp_nonce_field( $action );
	wp_original_referer_field( true );
	?>
	<input type="submit" accesskey="p" value="Submit" class="button" id="publish" name="publish">
		
</form>
Formulaire

 

Script de mise à jour du formulaire

(Le code PHP qui suit est à placer soit dans un plugin, soit dans le fichier function.php du thème, soit dans un mu-plugin)

admin_post

Tout d’abord il faut enregistrer le hook avec admin_post_{$action} pour le déclenchement du processus de mise à jour.

Il faut savoir que ce hook ne se déclenche que pour les utilisateurs connectés, sinon il faut utiliser admin_post_nopriv_{action}. Je vous renvois donc vers la documentation de admin_post_action et admin_post_nopriv_action pour plus d’infos.

<?php
add_action('admin_post_edit_moncpt', 'ctw_front_edit_moncpt');
?>
admin_post{$action}

 

ctw_front_edit_moncpt

C’est la fonction qui va enregistrer les informations de mise à jour du post.

On commence par les tests de sécurité puis par une mise à jour du post.

Si le la mise à jour fonctionne, on passe au téléchargement de notre image avec la fonction ctw_front_image_upload(). On récupère l’identifiant de l’image en tant que type attachement pour l’affecter au post.

Nous finissons avec la mise à jour du de la méta donnée _edit_last pour tracer qui a fait la modification.

<?php
/**
 * Permet la mise à jour de moncpt à partir du front
 * @return void
 */
function ctw_front_edit_moncpt(){

	if( (defined( 'DOING_AUTOSAVE' )
		&& DOING_AUTOSAVE )
		|| empty($_POST) )
			return;

	$current_user = wp_get_current_user();

	$nonce_security = true;
	$result = false;
	
	global $post;
	$post_id = $_POST['post_id'];
	$post = get_post($post_id);

	if ( !wp_verify_nonce( $_POST['_wpnonce'], 'edit-moncpt' ) )
		$nonce_security = false;

	/**
	* ctw_current_user_can()	Fonction de sécurité maison pour vérifier les droits (ne sera pas développer dans cet article)
	*/ 
	if ('POST' == $_SERVER['REQUEST_METHOD']
			&& $nonce_security
			&& $post->post_type == $_POST['post_type']			// Contrôle post
			&& $current_user->ID == $_POST['post_author']		// Contrôle sécurité maison concernant le post, dépend des projets
			&& ctw_current_user_can( 'edit-moncpt', $post_id )	
			){

			$d = current_time( 'mysql' );

			// Mise à jour du CPT
			$result = wp_update_post( array(
				'ID'				=> $_POST['post_id'],
				'post_modified'		=> $d,
			), true);

	}

	$message_return = array();

	if ( is_wp_error($result) ) {

		$errors = $result->get_error_messages();
		foreach ($errors as $error) {
			echo $error;
		}
		$message_return['save' ] = 'ko';
	}
	else{

		// Affecte comme nom d'image, le nom du post
		// Attention: ne pas déclarer $post_data = null 
		$post_data = array('post_title' => $post->post_title);
		
		// Traitement de l'Image
		$img_id = ctw_front_image_upload( 'image', $post_id, $post_data );

		// If our photo upload was successful, set the featured image
		if ( $img_id && ! is_wp_error( $img_id ) ) {
			$r = set_post_thumbnail( $post_id, $img_id );
		}

		/**
		* Autre champ de formulaire à traiter si besoin
		*/
		
		// Mise à jour identifiant dernière modification
		update_post_meta( $post_id, '_edit_last', $current_user->ID );
		$message_return['save' ] = 'ok';
	}

	$go_to_edit_cpt = add_query_arg( $message_return, $_POST['_wp_http_referer'] );
	wp_redirect( $go_to_edit_cpt );
}

function ctw_current_user_can( $context, $post_id )	{
	/**
	* Contraintes spécifique au projet
	*/
	return true;
}
?>
Update moncpt

 

Upload de l’image et création du post attachement

La fonction va tout d’abord vérifier la variable $_FILES, puis nous allons une série de hook (détail au paragraphe suivant) non exhaustif que nous allons nous servir pour répondre à nos critères.

Et ensuite nous utilisons la fonction media_handle_upload() qui uploader l’image et nous retourner l’identifiant du contenu créé pour l’image.

<?php
/**
 * Handles uploading a file to a WordPress post
 *
 * @param	string	$field_id		Nom du champ dans les données $_POST 
 * @param	int		$post_id		Post ID
 * @param	array	$post_data 		Donnée du post a ajouter à l'image
 */
function ctw_front_image_upload( $field_id, $post_id, $post_data = array() ) {

	// Contrôle sur la variable $_FILES
	if (
		empty( $_FILES )
		|| ! isset( $_FILES[$field_id] )
		|| isset( $_FILES[$field_id]['error'] ) && 0 !== $_FILES[$field_id]['error']
	) {
		return;
	}
	$files = array_filter( $_FILES[$field_id] );
	if ( empty( $files ) ) {
		return;
	}
	
	/**
	 * Suppression du thumbsnail précédent (l'image sera supprimé du serveur)
	 */
	if ( isset( $post_id ) ) {
		wp_delete_attachment( get_post_thumbnail_id( $post_id ), true );
	}

	/**
	 * Filtre executé en premier et comme paramètre les infos du fichiers
	 */
	add_filter( 'wp_handle_upload_prefilter', 'ctw_file_change_default_name', 10,1 );

	/**
	 * Filtre à la création du nom du fichier 
	 */
	add_filter( 'wp_unique_filename', 'ctw_file_unique_filename', 10,4 );
	
	/**
	 * Filtre sur le répertoire de destination
	 */
	add_filter( 'upload_dir', 'ctw_image_resize', 10,1 );
	
	/**
	 * Filtre à la fin de la fonction de chargement de l'image
	 */
	add_filter( 'wp_handle_upload', 'ctw_image_resize', 10,2 );

	/**
	 * Filtre le format des miniatures à réaliser suite au chargement
	 */
	add_filter( 'intermediate_image_sizes', 'ctw_change_image_size', 10,1 );

	// Si jamais ce script n'est pas éxécuté dans admin-post.php, il faut s'assurer que nous avons les bonnes fonctions
	if ( ! function_exists( 'media_handle_upload' ) ) {
		require_once( ABSPATH . 'wp-admin/includes/image.php' );
		require_once( ABSPATH . 'wp-admin/includes/file.php' );
		require_once( ABSPATH . 'wp-admin/includes/media.php' );
	}
	// Upload le fichier et renvoit l'identifiant d'attachement
	return media_handle_upload( $field_id, $post_id, $post_data );
}
?>
Upload de l'image

 

Les fonctions appelées par les hook de configuration

Ces différents hook permettent de configurer le nom, la / les  taille(s) et le dossier de stockage des images.

Vous remarquerez que pour redimensionner une image, nous utilisons la fonction wp_get_image_editor() qui renvoit un objet WP_Image_Editor. Cette classe est très pratique pour la transformation d’image.

 

<?php
/**
 * Change le nom du fichier par le nom générique que nous voulons lui donner
 */
function ctw_file_change_default_name($file){
	global $post;

	switch ($file['type']) {
		case 'image/gif': 	$ext = '.gif'; break;
		case 'image/png': 	$ext = '.png'; break;
		default:			$ext = '.jpg'; break;
	}

	$file['name'] = $post->wp_post_id.$ext;
	return $file;
}

/**
 * Renvois le nom du fichier et le renvois le nom sans chiffres si jamais il y a un doublon de nom
 * Ce filtre n'a pas vraiment d'utilité car le nom nous l'avons déjà changé dans le hook précédent,
 * et nous n'aurons pas de doublons car nous avons supprimé le fichier affecté au post. 
 * Mais il est intéressant de le connaitre si jamais le compteur par défaut ne vous convient pas.
 */
function ctw_file_unique_filename($filename, $ext, $dir, $callback){
	global $post;
	return $post->ID . $ext;
}

/**
 * Redimensione l'image l'original afin qu'elle ne soit pas trop lourde
 */
function ctw_image_resize($file, $action){
	$image = wp_get_image_editor( $file['file'] );
	if ( ! is_wp_error( $image ) ){
		// Nous définissons içi une largeur et hauteur maximale de 800 pixels
		$res = $image->resize( 800, 800 );
	}
	if( $res ){
		$image->save( $file['file'] );
	}

	return $file;
}

/**
 * Change le répertoire par défaut de stockage des images
 */
function ctw_moncpt_image_directory($upload_dir){
	global $post;
	
	$upload_dir['subdir'] = "/repertoire-moncpt/";
	$upload_dir['path'] = $upload_dir['basedir'].$upload_dir['subdir'];
	$upload_dir['url'] = $upload_dir['baseurl'].$upload_dir['subdir'];
	
	return $upload_dir;
}

/**
 * Change intermediate_image_sizes pour ne lister que les types de formats désirés
 * function get_intermediate_image_sizes() in wp-includes/media.php
 */
function ctw_change_image_size($image_sizes){
	// On ne créera que le format 'medium' en plus de l'original
	return array('medium');
}
?>
Hook de personnalisation du upload

Conclusion

J’ai passé pas mal de temps avant de réussir a trouver les bon hook en épluchant la doc et le code WordPress. En définitif lorsque nous avons les bons exemple le travail est plus aisé, d’ou le but de mon article sur ce sujet.


Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *