Direkt zum Inhalt
Drupal Commerce: Anpassen des Bestellvorgangs (Checkout)

Der Checkout-Prozess von Drupal Commerce ist mit den meisten E-Commerce-Shops kompatibel. Für einen unserer Kunden müssen wir einen Checkout-Prozess einrichten, der sich deutlich vom Standardprozess unterscheidet. 

Zu den Funktionen gehören: 

  • Möglichkeit zur Registrierung für nicht registrierte Benutzer.
  • Hinzufügen spezifischer Formulare während des Checkout-Prozesses.
  • Ändern des Werts der Schaltflächen zum Absenden

Der Checkout-Prozess umfasst mehrere Schritte. Standardmäßig werden 5 Schritte unterschieden:

  • Anmeldung (Login)
  • Informationen zur Bestellung (order_information)
  • Überprüfen (review)
  • Bezahlen (payment)
  • Abgeschlossen (complete)

Siehe : commerce/modules/checkout/src/Plugin/Commerce/CheckoutFlow/MultistepDefault.php
 

Jeder Schritt besteht aus einem oder mehreren Fenstern (panes). Beispielsweise sind die Kontaktinformationen ein Fenster.

<?php
namespace Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane;
use Drupal\Core\Form\FormStateInterface;
/**
 * Provides the contact information pane.
 *
 * @CommerceCheckoutPane(
 *   id = "contact_information",
 *   label = @Translation("Contact information"),
 *   default_step = "order_information",
 *   wrapper_element = "fieldset",
 * )
 */
class ContactInformation extends CheckoutPaneBase implements CheckoutPaneInterface {
...

Wir erstellen ein Fenster, um den erforderlichen Code hinzuzufügen. Der Basiscode unseres Fensters sieht wie folgt aus:

<?php
namespace Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane;
use Drupal\Core\Form\FormStateInterface;
/**
 * Provides the contact information pane.
 *
 * @CommerceCheckoutPane(
 *   id = "custom_information",
 *   label = @Translation("Custom information"),
 *   default_step = "order_information",
 *   wrapper_element = "fieldset",
 * )
 */
class CustomInformation extends CheckoutPaneBase implements CheckoutPaneInterface {  
  /**
   *
   * {@inheritdoc}
   * @see \Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface::buildPaneForm()
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array $complete_form) {
    return $pane_form;
  }
}

Die Methode buildPaneForm enthält das zusätzliche Formular.
Dadurch wird es im Schritt "order_information"verfügbar sein.
 

Hinzufügen eines Feldes im Checkout-Fenster

Wir können unser Fenster verbessern, indem wir ein Textfeld hinzufügen:

  /**
   *
   * {@inheritdoc}
   * @see \Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface::buildPaneForm()
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form['description_need'] = [
      "#type" => 'text_format',
      '#format' => 'basic_html',
      '#title' => $this->t('Describe your need'),
      '#default_value' => '',
      '#required' => true,
      '#description' => $this->t("Please bring out the necessary characteristics and information.")
    ];
    return $pane_form;
  }
  
 /**
   *
   * {@inheritdoc}
   */
  public function validatePaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    $values = $form_state->getValue($pane_form['#parents']);
    if (!empty($values['description_need']['value']) && \strlen($values['description_need']['value']) < 10) {
      $form_state->setError($pane_form, $this->t('Your description is short'));
    }
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    $values = $form_state->getValue($pane_form['#parents']);
    // $values['description_need']
  }

Wir haben einen Validator (validatePaneForm) und eine Speichermethode (submitPaneForm) hinzugefügt.

Zu diesem Zeitpunkt haben wir bereits ein Ergebnis:



ir möchten diese Informationen in der Bestellung speichern. Dazu fügen wir unserer Bestellung über die Modul-Datei und den hook_entity_base_field_info ein Feld hinzu.
 

/**
 * Implement hook_entity_base_field_info
 *
 * @param EntityTypeInterface $entity_type
 */
function [MODULE_NAME]_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = [];
  if ($entity_type->id() == 'commerce_order') {
    $fields['hbk_description_need'] = BaseFieldDefinition::create('text_long')->setLabel(" Description need ")->setDisplayOptions('form', [])->setDisplayOptions('view',
      [
        'label' => 'hidden',
        'type' => 'text_default',
        'weight' => 0
      ])->setDisplayConfigurable('view', TRUE)->setDisplayConfigurable('form', true);
  }
  return $fields;
}

Anschließend müssen diese Änderungen in der Datenbank übernommen werden. Dies kann auf verschiedene Weise geschehen, wir entscheiden uns jedoch für den Befehl drush entup :

vendor/bin/drush entup

Wir aktualisieren unser Menü:

<?php
namespace Drupal\hbk_souscription_pfna\Plugin\Commerce\CheckoutPane;
use Drupal\Core\Form\FormStateInterface;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneBase;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface;
/**
 * Provides the contact information pane.
 *
 * @CommerceCheckoutPane(
 *   id = "custom_information",
 *   label = @Translation("Custom information"),
 *   default_step = "order_information",
 *   wrapper_element = "fieldset",
 * )
 */
class CustomInformation extends CheckoutPaneBase implements CheckoutPaneInterface {
  
  /**
   *
   * {@inheritdoc}
   * @see \Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface::buildPaneForm()
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form['description_need'] = [
      "#type" => 'text_format',
      '#format' => 'basic_html',
      '#title' => $this->t('Describe your need'),
      '#default_value' => $this->order->get('hbk_description_need')->value,
      '#required' => true,
      '#description' => $this->t("Please bring out the necessary characteristics and information.")
    ];
    return $pane_form;
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function validatePaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    $values = $form_state->getValue($pane_form['#parents']);
    if (!empty($values['description_need']['value']) && \strlen($values['description_need']['value']) < 10) {
      $form_state->setError($pane_form, $this->t('Your description is short'));
    }
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    $values = $form_state->getValue($pane_form['#parents']);
    $this->order->set('hbk_description_need', $values['description_need']['value']);
  }
}

Der oben beschriebene Ansatz eignet sich, wenn Sie nur wenige Felder haben. Bei einer größeren Anzahl von Feldern sollten Sie jedoch ein Profil verwenden.
 

Hinzufügen eines Profils im Checkout-Fenster

Das Hinzufügen eines Profils folgt derselben Logik wie das Hinzufügen eines Feldes, es gibt jedoch wichtige Unterschiede, da zwei Formulare zu verwalten sind: das Standardformular (Checkout) und das Profilformular.

Definition des Bedarfs:
Wir möchten ein zusätzliches Formular unter Verwendung eines Profils hinzufügen. Der Benutzer füllt es einmal aus und kann anschließend seine Daten aktualisieren.
 

/**
 * Implement hook_entity_base_field_info
 *
 * @param EntityTypeInterface $entity_type
 */
function hbk_souscription_pfna_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = [];
  if ($entity_type->id() == 'commerce_order') {
    $fields['hbk_description_need'] = BaseFieldDefinition::create('text_long')->setLabel(" Description need ")->setDisplayOptions('form', [])->setDisplayOptions('view',
      [
        'label' => 'hidden',
        'type' => 'text_default',
        'weight' => 0
      ])->setDisplayConfigurable('view', TRUE)->setDisplayConfigurable('form', true);
    $fields['hbk_custom_profile'] = BaseFieldDefinition::create('entity_reference')->setLabel(t('Custom profile'))->setSetting('target_type', 'profile')->setSetting('handler', 'default')->setDisplayOptions(
      'form', [
        'type' => 'entity_reference_autocomplete',
        'weight' => 5,
        'settings' => [
          'match_operator' => 'CONTAINS',
          'size' => '60',
          'autocomplete_type' => 'tags',
          'placeholder' => ''
        ]
      ])->setDisplayConfigurable('form', TRUE)->setDisplayConfigurable('view', TRUE)->setCardinality(1);
  }
  return $fields;

Wir fügen ein neues Feld „hbk_custom_profile” zur Entität „commerce” hinzu. Dieses Feld enthält die Profil-ID.
 

<?php
namespace Drupal\hbk_souscription_pfna\Plugin\Commerce\InlineForm;
use Drupal\commerce\Plugin\Commerce\InlineForm\EntityInlineFormBase;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\profile\Entity\ProfileInterface;
/**
 * Provides an inline form for managing a customer profile.
 *
 * Allows copying values to and from the customer's address book.
 *
 * Supports two modes, based on the profile type setting:
 * - Single: The customer can have only a single profile of this type.
 * - Multiple: The customer can have multiple profiles of this type.
 *
 * @CommerceInlineForm(
 *   id = "hbk_custom_profile",
 *   label = @Translation("Hbk custom profile"),
 * )
 */
class HbkCustomerProfile extends EntityInlineFormBase {
  
  /**
   *
   * {@inheritdoc}
   */
  public function defaultConfiguration() {
    return [
      'form_mode' => 'default',
      'skip_save' => FALSE
    ];
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function buildInlineForm(array $inline_form, FormStateInterface $form_state) {
    $inline_form = parent::buildInlineForm($inline_form, $form_state);
    assert($this->entity instanceof ProfileInterface);
    
    $form_display = EntityFormDisplay::collectRenderDisplay($this->entity, $this->configuration['form_mode']);
    $form_display->buildForm($this->entity, $inline_form, $form_state);
    
    return $inline_form;
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function submitInlineForm(array &$inline_form, FormStateInterface $form_state) {
    parent::submitInlineForm($inline_form, $form_state);
    assert($this->entity instanceof ProfileInterface);
    
    $form_display = EntityFormDisplay::collectRenderDisplay($this->entity, $this->configuration['form_mode']);
    $form_display->extractFormValues($this->entity, $inline_form, $form_state);
    
    if (empty($this->configuration['skip_save'])) {
      $this->entity->save();
    }
  }
}

Wir erstellen das Plugin CommerceInlineForm, um das Profil im CheckoutPane darzustellen.

$customProfile = null;
    // On recupere le custom profile, s'il existe.
    $id_profile = $this->order->get("hbk_custom_profile")->target_id;
    if ($id_profile) {
      $this->messenger()->addStatus("Le profile est deja rataché à la commande ");
      $customProfile = $this->entityTypeManager->getStorage("profile")->load($id_profile);
    }
    if (!$customProfile) {
      
      $profile_storage = $this->entityTypeManager->getStorage("profile");
      // On verifie si profile existe deja.
      $customProfiles = $this->entityTypeManager->getStorage("profile")->loadByProperties([
        'uid' => \Drupal::currentUser()->id(),
        'type' => 'informations_personnelles'
      ]);
      if ($customProfiles) {
        $this->messenger()->addStatus("Le profile a deja été creer ");
        $customProfile = reset($customProfiles);
      }
      else {
        $this->messenger()->addStatus(" Creation d'un nouveau profile ");
        $customProfile = $profile_storage->create([
          'type' => 'informations_personnelles',
          'uid' => \Drupal::currentUser()->id()
        ]);
      }
    }
    /**
     *
     * @var \Drupal\hbk_souscription_pfna\Plugin\Commerce\InlineForm\HbkCustomerProfile $inline_form
     */
    $inline_form = $this->inlineFormManager->createInstance('hbk_custom_profile', [
      'form_mode' => 'default',
      'skip_save' => FALSE
    ], $customProfile);
    
    $pane_form['custom_profile'] = [
      '#parents' => array_merge($pane_form['#parents'], [
        'profile'
      ]),
      '#inline_form' => $inline_form
    ];
    $pane_form['custom_profile'] = $inline_form->buildInlineForm($pane_form['custom_profile'], $form_state);
    

Wir fügen dem Formular einen Eintrag hinzu, um das Profil darzustellen.
 

  /**
   *
   * {@inheritdoc}
   */
  public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    /** @var \Drupal\hbk_souscription_pfna\Plugin\Commerce\InlineForm\HbkCustomerProfile $inline_form */
    $inline_form = $pane_form['custom_profile']['#inline_form'];
    // on met à jour l'entité profile.
    $inline_form->submitInlineForm($pane_form['custom_profile'], $form_state);
    /**
     *
     * @var \Drupal\profile\Entity\Profile $profile
     */
    $profile = $inline_form->getEntity();
    //
    $values = $form_state->getValue($pane_form['#parents']);
    $this->order->set('hbk_description_need', $values['description_need']['value']);
    $this->order->set('hbk_custom_profile', $profile->id());
  }

Wir aktualisieren die Sicherung.

Der endgültige Code  für unser CheckoutPane:

<?php
namespace Drupal\hbk_souscription_pfna\Plugin\Commerce\CheckoutPane;
use Drupal\Core\Form\FormStateInterface;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneBase;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\commerce\InlineFormManager;
use Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
/**
 * Provides the contact information pane.
 *
 * @CommerceCheckoutPane(
 *   id = "custom_information",
 *   label = @Translation("Custom information"),
 *   default_step = "order_information",
 *   wrapper_element = "fieldset",
 * )
 */
class CustomInformation extends CheckoutPaneBase implements CheckoutPaneInterface {
  
  /**
   * The inline form manager.
   *
   * @var \Drupal\commerce\InlineFormManager
   */
  protected $inlineFormManager;
  
  /**
   * Constructs a new BillingInformation object.
   *
   * @param array $configuration
   *        A configuration array containing information about the plugin
   *        instance.
   * @param string $plugin_id
   *        The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *        The plugin implementation definition.
   * @param \Drupal\commerce_checkout\Plugin\Commerce\CheckoutFlow\CheckoutFlowInterface $checkout_flow
   *        The parent checkout flow.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *        The entity type manager.
   * @param \Drupal\commerce\InlineFormManager $inline_form_manager
   *        The inline form manager.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, CheckoutFlowInterface $checkout_flow, EntityTypeManagerInterface $entity_type_manager, InlineFormManager $inline_form_manager) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $checkout_flow, $entity_type_manager);
    
    $this->inlineFormManager = $inline_form_manager;
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition, CheckoutFlowInterface $checkout_flow = NULL) {
    return new static($configuration, $plugin_id, $plugin_definition, $checkout_flow, $container->get('entity_type.manager'), $container->get('plugin.manager.commerce_inline_form'));
  }
  
  /**
   *
   * {@inheritdoc}
   * @see \Drupal\commerce_checkout\Plugin\Commerce\CheckoutPane\CheckoutPaneInterface::buildPaneForm()
   */
  public function buildPaneForm(array $pane_form, FormStateInterface $form_state, array &$complete_form) {
    $pane_form['description_need'] = [
      "#type" => 'text_format',
      '#format' => 'basic_html',
      '#title' => $this->t('Describe your need'),
      '#default_value' => $this->order->get('hbk_description_need')->value,
      '#required' => true,
      '#description' => $this->t("Please bring out the necessary characteristics and information.")
    ];
    $customProfile = null;
    // On recupere le custom profile, s'il existe.
    $id_profile = $this->order->get("hbk_custom_profile")->target_id;
    if ($id_profile) {
      $customProfile = $this->entityTypeManager->getStorage("profile")->load($id_profile);
    }
    if (!$customProfile) {
      
      $profile_storage = $this->entityTypeManager->getStorage("profile");
      // On verifie si profile existe deja.
      $customProfiles = $this->entityTypeManager->getStorage("profile")->loadByProperties([
        'uid' => \Drupal::currentUser()->id(),
        'type' => 'informations_personnelles'
      ]);
      if ($customProfiles) {
        $customProfile = reset($customProfiles);
      }
      else {
        $customProfile = $profile_storage->create([
          'type' => 'informations_personnelles',
          'uid' => \Drupal::currentUser()->id()
        ]);
      }
    }
    /**
     *
     * @var \Drupal\hbk_souscription_pfna\Plugin\Commerce\InlineForm\HbkCustomerProfile $inline_form
     */
    $inline_form = $this->inlineFormManager->createInstance('hbk_custom_profile', [
      'form_mode' => 'default',
      'skip_save' => FALSE
    ], $customProfile);
    
    $pane_form['custom_profile'] = [
      '#parents' => array_merge($pane_form['#parents'], [
        'profile'
      ]),
      '#inline_form' => $inline_form
    ];
    $pane_form['custom_profile'] = $inline_form->buildInlineForm($pane_form['custom_profile'], $form_state);
    
    return $pane_form;
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function validatePaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    $values = $form_state->getValue($pane_form['#parents']);
    if (!empty($values['description_need']['value']) && \strlen($values['description_need']['value']) < 10) {
      $form_state->setError($pane_form, $this->t('Your description is short'));
    }
  }
  
  /**
   *
   * {@inheritdoc}
   */
  public function submitPaneForm(array &$pane_form, FormStateInterface $form_state, array &$complete_form) {
    /** @var \Drupal\hbk_souscription_pfna\Plugin\Commerce\InlineForm\HbkCustomerProfile $inline_form */
    $inline_form = $pane_form['custom_profile']['#inline_form'];
    // on met à jour l'entité profile.
    $inline_form->submitInlineForm($pane_form['custom_profile'], $form_state);
    /**
     *
     * @var \Drupal\profile\Entity\Profile $profile
     */
    $profile = $inline_form->getEntity();
    //
    $values = $form_state->getValue($pane_form['#parents']);
    $this->order->set('hbk_description_need', $values['description_need']['value']);
    $this->order->set('hbk_custom_profile', $profile->id());
  }
}

Anderswo im Internet:
https://www.adimeo.com/blog-technique/checkout-panes-custom-drupal-commerce

Profile picture for user admin Stephane K

Écrit le

Il y'a 1 Jahr
Modifié
Il y'a 2 Wochen
Lädt...
WhatsApp
Support Habeuk : +237 694 900 622
WhatsApp Send