Gestion des pièces jointes des e-mails Woocommerce

Woocommerce, ajoutez une pièce jointe à vos e-mails de confirmation de commande

Attacher une pièce jointe aux e-mails de commande est une demande de plus en plus fréquente parmi les clients bénéficiant d’une boutique en ligne Woocommerce. Dans cet article je vous montre comment créer un champ de sélection de documents dans l’interface Woocommerce afin de programmer son envoi en pièce jointe avec l’e-mail de confirmation de commande sur votre site e-commerce.

L’idée est ici de donner à l’utilisateur ou au propriétaire de boutique Woocommerce, de sélectionner un ou plusieurs fichiers par produit vendu sur la boutique en ligne, afin qu’ils soient ajoutés en pièce jointe à un e-mail envoyé au client (par exemple, l’e-mail de confirmation de commande).

N.B. Attention, ce tutoriel est conçu pour l’interface classique des produits Woocommerce et non l’interface bêta basée sur les blocs, pour laquelle de futurs articles seront produits.

N.B. Nous considérons que nous développons ici un plugin WordPress.

L’enregistrement de métadonnées d’un produit Woocommerce passe par les onglets de réglage de sa page d’édition. Nous allons donc commercer par créer un onglet dédié à la sélection de fichiers à joindre à notre e-mail, et y intégrer un simple champ texte, que nous utiliserons pour sauvegarder les ID de fichier en métadonnée du produit.

Création d’un onglet de réglage pour un produit Woocommerce

Enregistrement d’un onglet customisé

La création d’onglets personnalisés sur la page des produits Woocommerce nécessite 2 hooks :

  1. Le filtre “woocommerce_product_data_tabs” permet d’ajouter l’onglet ;
  2. L’action “woocommerce_product_data_panels” pour ajouter des “panneaux » à l’onglet créé.

Nous créons d’abord le nouvel onglet de la page produit avec le hook ’woocommerce_product_data_tabs’ :

public function set_hooks(){

            add_filter( ’woocommerce_product_data_tabs’, [ $this, ‘cdw_woo_product_data_tabs’ ] );

}

Le callback prend en arguments le tableau courant des onglets de réglage de la page des produits.

Au sein de cette fonction de rappel, nous définissons une entrée dont la clé correspondra au slug du panneau de réglages, et le contenu un tableau de données définissant a minima le label, la cible (son identifiant HTML) ainsi qu’un niveau de priorité permettant de définir la position de l’onglet dans la page :

/**

 * @param array $tabs the product tabs array

  * @return array the new tabs array

   */

        public function cdw_woo_product_data_tabs( $tabs )

        {

            $tabs[ 'cdw-woo-product-docs-ids' ] = [

                'label'     => __( 'Pièces jointes des e-mails de commande', $this->textDomain ),

                'target'    => 'cdw-woo-product-docs',

                'class'     => '',

                'priority'  => 75

            ];

            return $tabs;

        }

Intégration d’un champ de données (texte)

L’intégration des données passe par l’utilisation d’une structure HTML lisible par l’API Woocommerce. Pour ce faire, nous utiliserons les classes CSS « panel woocommerce_options_panel » et « form-field » de Woocommerce.

public function set_hooks(){

            // …

            add_action( ‘woocommerce_product_data_panels’, [ $this, ‘cdw_woo_product_data_tabs’ ] );

}

Création d’un champ de sélection d’un document sur la page d’édition de produit Woocommerce

N.B. Dans notre function de rappel, nous récupérons la variable globale $post afin de pouvoir accéder aux métadonnées liées au produit.

Nous utiliserons aussi la méthode Woocommerce woocommerce_wp_text_input() permettant d’afficher simplement un champ de texte, son libellé et son tooltip, ainsi que les attributs « id » et « value » de cet input.

public function cdw_woo_product_data_tabs()

{

    global $post;

        ?>

            <div id="cdw-woo-product-docs" class="panel woocommerce_options_panel">

                <div class="options-group">

                    <?php

                        // récupération de la valeur de la métadonnée en base de données

                        $prod_attachment_ids = get_post_meta( $post->ID, 'cdw-woo-product-docs-ids', true);

                        $prod_attachment_ids = ( empty( $prod_attachment_ids ) || ! $prod_attachment_ids ) ? '' : $prod_attachment_ids;

                    ?>

                    <p class="form-field">

                    <?php

                        woocommerce_wp_text_input([

                            'id'                => 'cdw-woo-product-docs-ids',

                            'label'             => 'ID des documents à joindre à la commande du produit',

                            'value'             => $prod_attachment_ids,

                            'wrapper_class'     => '', // utilisée pour les affichages conditionnels

                            'description'       => 'Sélectionnez le ou les fichiers à attacher en pièce jointe de vos confirmations de commande pour ce produit',

                            'desc_tip'          => true

                        ]);

                    ?>

                        <button id="prod_attachment_id-opener" class="button secondary" style="margin-left:.5em;">Ouvrir la librairie médias</button>

                        <button id="prod_attachment_id-deleter" class="button secondary" style="margin-left:.5em;">supprimer le(s) fichier(s)</button>

                    </p>

                </div>

            </div>

        <?php

}
Onglet et champs de de réglages personnalisés d'un produit Woocommerce.

Les deux boutons ajoutés au panel vont maintenant nous permettre d’intégrer l’API wp.media de WordPress afin de permettre aux utilisateurs de sélectionner le ou les fichiers à joindre aux e-mails Woocomerce, ou de récupérer leurs URL afin de proposer un lien de téléchargement au client Woocommerce.  

wp.media, l’API de gestion de fichiers de WordPress

Nous n’allons pas ici passer en revue l’intégralité de l’API wp.media de WordPress, mais plutôt expliquer les éléments principaux permettant de récupérer les informations nécessaires à l’envoi de fichier dans les e-mails de commande de votre boutique en ligne.

La première étape consiste à intégrer un script JavaScript. Nous allons ici écouter les événements de clic sur les deux boutons de notre interface, et instancier l’objet « frame » possédant les méthodes d’ouverture de la bibliothèque média et de sélection de ces mêmes médias.

Intégration du script Javascrit

Le hook « admin_enqueue_scripts » nous permet de nous exempter de vérifier que nous somme bien en back-office avant de d’ajouter nos scripts ou nos styles CSS à la page :

public function set_hooks(){

            //…

            add_action( ‘admin_enqueue_scripts’, [ $this, ‘cdw_enqueue_woo_media_manager_script’ ] ) ;

}

L’autre atout de admin_enqueue_scripts est d’injecter au callback le nom de l’écran d’édition, qui nous permettra de ne récupérer notre script que sur la page d’édition de produit Woocommerce :

public function cdw_enqueue_woo_media_manager_script( $hook ){

            if(.’post.php’ == $hook && ‘product’ == get_post_type() ){

                        wp_enqueue_script(

                                     'cdw-woo-product-docs',

                                     plugin_dir_url( __FILE__ ) . 'assets/js/cdw-woo-product-docs.js',

                                     [ 'jquery'],

                                     null,

                                     true

                         );

            }

}

N.B. Notre script cdw-woo-product-docs.js, utilisera jQuery et sera localisé dans le répertoire « assets/js/ ».

Utilisation de l’API wp.media pour sélectionner les pièces jointes des e-mails Woocommerce

// assets/js/cdw-woo-product-docs.js
(($) => {

    $(document).ready(()=>{

            //Variable contenant l'objet Frame de l'API wp.media

             let customMediaUploadFrame;

            //Identification des éléments d'interface :

            // - bouton d'ouverture de la médiathèque

            // - bouton de suppression des données du champ texte accueillant les ID des fichiers sélectionnés

            // - Champ input texte cité plus haut

            const   $prodAttachmentIdOpener   = $('#prod_attachment_id-opener'),

                $prodAttachmentIdDeleter  = $('#prod_attachment_id-deleter'),

                $docsInput                = ('#cdw-woo-product-docs-ids');

            // Écouteur d'événement click

            $($prodAttachmentIdOpener).click( (e) => {

                        e.preventDefault();

                        // si la Frame est instanciée on l'utilise immédiatement pour ouvrir la bibliothèque média

                        // la méthode .open() est fourni par l'objet Frame de l'API wp.media

                        if( customMediaUploadFrame ){

                                    customMediaUploadFrame.open();

                                    return;

                        }

                        // sinon, on instancie l'objet Frame en définissant a minima :

                        // - un titre pour l'interface

                        // - l'ancre du bouton d'interface

                        // - le type de fichiers acceptés pour nos sélections

                        // - la possibilité de choisir plusieurs

                        customMediaUploadFrame = wp.media({

                                    title: 'Sélectionner le ou les fichiers à joindre aux e-mails de confirmation de commande',

                                    button : {

                                    texte: 'Attacher ce fichier'

                                    },

                                    library : {

                                                "type": "image"

                                    },

                                    multiple: 'add'

                        });

                        // Définition du comportement de l'interface à la sélection

                        customMediaUploadFrame.on( 'select', () => {

                        // Récupération du tableau des éléments sélectionnés

                        const selection = customMediaUploadFrame.state().get( 'selection' );

                         // Itération sur le tableau de sélection et Formatage de sortie

                         let retStr = '', fileCount = 0;

                         selection.map( file => {

                          if( fileCount > 0 ){

                                    retStr += ',';

                        }

                        // ici nous récupérons l'ID de chaque fichier, nous au-rions pu récupérer son URL (file.url)

                                      retStr += file.id;

                                      fileCount ++;

                        } );

                        // Insertion du résultat de la sélection dans le champ texte de l'interface Woocommerce

                                    $($docsInput).val( retStr );

                        } );

                        // maintenant que la Frame est instanciée, ou pouvons ouvrir la bibliothèque au clic sur le bouton

                        customMediaUploadFrame.open();

                                    return false;

                        });

                        // Suppression du contenu du champ texte au clic sur le bouton dédié

                        $($prodAttachmentIdDeleter).click((e) => {

                                    $($docsInput).val('');

                        });

            });

})(jQuery);

Sauvegarde de l’ID en métadonnée d’un produit Woocommerce

La sauvegarde des métadonnées de produits Woocommerce est assurée à l’aide du hook « woocommerce_process_product_meta ». celui)-ci fonctionne à l’identique di hook WordPress « save_post » et fournit à sa méthode de rappel l’ID du post (le produit) édité :

Votre devis en 48 H chrono !

Demandez à être rappelé !

Nous préciserons ensemble votre projet
de vive voix 

public function set_hooks(){

            //…

            add_action( ‘woocommerce_product_process_meta’, [ $this, ‘cdw_woo_prodection_process_meta’ ] ) ;

}

Nous allons vérifier que la donnée correspondant à notre champ texte est bien présente dans $_POST, au besoin, la nettoyer, et finalement l’ajouter au post meta, ou la supprimer si nécessaire :

public function cdw_woo_process_product_meta( $post_id ){

            $cdw_woo_product_docs_ids_new = ( isset( $_POST[ 'cdw-woo-product-docs-ids' ] ) )

                ? sanitize_text_field( $_POST[ 'cdw-woo-product-docs-ids' ] )

                : false;

            $cdw_woo_product_docs_ids_old = get_post_meta( $post_id, 'cdw-woo-product-docs-ids', true );

            ( !$cdw_woo_product_docs_ids_new && $cdw_woo_product_docs_ids_old )

                ? delete_post_meta( $post_id, 'cdw-woo-product-docs-ids' )

                : update_post_meta( $post_id, 'cdw-woo-product-docs-ids', $cdw_woo_product_docs_ids_new );

}

Attacher un document en pièce jointe d’un e-mail Woocommerce

Le point d’entrée permettant l’envoi de pièces jointes avec les e-mails woocommerce est le filtre woocommerce_email_attachments.

Le callback recevra 3 arguments :

  1. Le tableau de pièces jointes
  2. L’identifiant de l’e-mail
  3. La commande courante

N.B. L’identifiant de l’e-mail pourra servir à  conditionner l’ajout des pièces jointes au destinataire et au type d’email envoyé. Voici la liste complète des identifiants exploitables :

  • new_order
  • customer_on_hold_order
  • customer_processing_order
  • customer_completed_order
  • customer_refunded_order
  • customer_partially_refunded_order
  • cancelled_order
  • failed_order
  • customer_reset_password
  • customer_invoice
  • customer_new_account
  • customer_note

N.B. la commande courante va nous servir à itérer sur les éléments commandés afin de rechercher l’existence de notre métadonnée pour chaque produit correspondant.

Enfin, nous allons extraire les identifiants des fichiers à joindre à notre e-mail Woocommerce et ajouter leur chemin d’accès (path) au tableau filtré& des pièces jointes :

public function set_hooks(){

            //…

            add_filter(‘woocommerce_email_attachments’, [$this, ‘cdw_wpp_email_attachments’ ],10,3);

}

/**
 * Attaches selected files from product pages to woocommerce emails 
  * 
  * @param array $attachments the current attachments array
  * @param integer $email_id email slug identifier
  * @param Object $order the current order object  
  * 
  * @return array $attachments
  */
  public function cdw_woo_email_attachments( $attachments, $email_id, $order){
            if( 'customer_processing_order' === $email_id )
            {
                /**
                 * récupération de la commande courante
                 */
                $current_order = wc_get_order( $order );

                /**
                 * Items de la commande
                 */
                $items = $order->get_items();

                foreach( $items as $item )
                {
                    if( FALSE !== ( $attchmts_ids_str = get_post_meta( $item->get_product_id(), 'cdw-woo-product-docs-ids', true ) ) )
                    {
                        $attchmts_ids_arr = explode( ',', $attchmts_ids_str );
                        if( !empty( $attchmts_ids_arr ) )
                        {
                            foreach( $attchmts_ids_arr as $k=>$file_id )
                            {
                                if( $file_id && ctype_digit( $file_id ) )
                                {
                                    $attachments[]= \get_attached_file( $file_id );
                                }
                            }
                        }
                    }
                }
            }
            
            return $attachments;
}

Et voilà !!

Désormais, vos e-mails de notification de commandes Woocommerce comporteront les pièces jointes définies sur chaque page de produit.

Amusez-vous bien !

Laisser un commentaire

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