web-dev-qa-db-fra.com

Comment accrocher un champ de paiement WooCommerce?

Chaque champ de la validation de formulaire Woocommerce par défaut a cette balise:

<p class="form-row form-row-first validate-required" id="billing_first_name_field" data-priority="10">
     <label for="billing_first_name" class="">Name&nbsp;
           <abbr class="required" title="required">*</abbr>
     </label>
     <span class="woocommerce-input-wrapper">
          <input type="text" class="input-text " name="billing_first_name" id="billing_first_name" placeholder="" value="" autocomplete="given-name">
     </span>
</p>

Maintenant je veux:

  1. Enveloppez chaque champ dans un wrapper comme <div class="single-field-wrapper"><p [...] </div>
  2. Enveloppez les deux premiers champs, 'billing_first_name' et 'billing_last_name' dans un wrapper comme <div class="first-and-second-field-wrapper"> [...] </div>

Pour ce faire, j'ai essayé d'utiliser les crochets de filtre mis à disposition par function woocommerce_form_field( $key, $args, $value = null ) appelé dans le modèle form-billing.php de cette manière:

<?php
        $fields = $checkout->get_checkout_fields( 'billing' );

        foreach ( $fields as $key => $field ) {
            if ( isset( $field['country_field'], $fields[ $field['country_field'] ] ) ) {
                $field['country'] = $checkout->get_value( $field['country_field'] );
            }
            woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
        }
    ?>

Donc, dans functions.php j'ai écrit:

function change_woocommerce_field_markup($field, $key, $args, $value){

  $field = '<div class="single-field-wrapper">'.$field.'</div>';

  if($key === 'billing_first_name') {

      $field = '<div class="first-and-second-field-wrapper">'.$field;
   }
  else if ($key === 'billing_last_name') {

      $field = $field.'</div>';
   }

   else {
      $field = $field;
   }

    return $field;
   } 

  add_filter("woocommerce_form_field","change_woocommerce_field_markup", 10, 4);

De façon inattendue, je reçois ce balisage:

<div class="first-and-second-field-wrapper">
       <div class="single-field-wrapper">
            <div class="single-field-wrapper">
            [here there are all the fields, one under the other ]
            </div>
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div>   
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div> 
       <div class="single-field-wrapper"></div> 
 </div>

Tout le monde peut expliquer pourquoi ce comportement inattendu?

2
AmintaCode

Il n'y a pas de hook woocommerce_form_field, il y a de hook woocommerce_form_field_{$args[type]}(doc) .

$args[type] peut être (regardez ici pour les options disponibles):

  • texte,
  • case à cocher,
  • pays,
  • ...

Le code ci-dessous va envelopper les champs 'billing_first_name' et 'billing_last_name' dans un wrapper comme <div class="first-and-second-field-wrapper"> [...] </div>.

function change_woocommerce_field_markup($field, $key, $args, $value) {

   $field = '<div class="single-field-wrapper">'.$field.'</div>';

   if($key === 'billing_first_name')
      $field = '<div class="first-and-second-field-wrapper">'.$field;
   else if ($key === 'billing_last_name')
      $field = $field.'</div>';

    return $field;
} 

add_filter("woocommerce_form_field_text","change_woocommerce_field_markup", 10, 4);

Il encapsulera également les champs de type text avec <div class="single-field-wrapper">...</div>.
MAIS
Certains champs de texte ayant leur propre type (comme state ou email) nécessitent des points d'ancrage supplémentaires, par exemple:

add_filter("woocommerce_form_field_country","change_woocommerce_field_markup", 10, 4);
add_filter("woocommerce_form_field_email","change_woocommerce_field_markup", 10, 4);

UPDATE # 1

Le code ci-dessus fonctionne dans WC-v3.3.7.

Dans WC-v3.4.xx, vous obtenez ceci:

<div class="first-and-second-field-wrapper">
    <div class="single-field-wrapper">
        <div class="single-field-wrapper">
            [here there are all the fields, one under the other ]
        </div>
    <div class="single-field-wrapper"></div> 
    <div class="single-field-wrapper"></div> 
    <div class="single-field-wrapper"></div> 
    ....
    <div class="single-field-wrapper"></div>
</div>

parce que javascript trie les lignes de formulaire dans .woocommerce-billing-fields__field-wrapper. Regardez le fichier woocommerce/assets/js/frontend/address-i18n.js, à partir de la ligne 99.
JS trouve toutes les balises HTML avec la classe ".form-row" dans le wrapper, prend le parent de first item (balise avec la classe .form-row), trie les éléments par priorité et les insère dans élément parent précédemment sélectionné .

Pour le test, modification dans le fichier address-i18.js, à la ligne 99
var fieldsets = $('.woocommerce-billing-fields__field-wrapper, ...
à
var fieldsets = $('.woocommerce-billing-fields__field-wrapper2, ...
et téléchargez au format address-i18.min.js.

Supprimer le tri JS n'est pas une solution, c'est juste un test. Sans le tri par JS, vous obtiendrez ceci:

<div class="first-and-second-field-wrapper">
    <div class="single-field-wrapper">
        <p class="form-row ..." id="billing_first_name_field"> <label for="billing_first_name"> ... </p>
    </div>
    <div class="single-field-wrapper">
        <p class="form-row ..." id="billing_last_name_field"> <label for="billing_last_name">... </p>
    </div>
</div>
<div class="single-field-wrapper">
   <p class="form-row ..." id="billing_company_field"> <label for="billing_company">...  </p>
</div>
3
nmr