Eigene WooCommerce Versandmethode erstellen

Heute soll es mal um ein WooCommerce Thema gehen. WooCommerce hat im Standard drei verschiedene Versandarten: Versandkostenpauschale, Versandkostenfrei, Local Pickup.

Plugins können dies über die Shipping Method API erweitern und eigene Versandarten registrieren. Ein gängiger Anwendungsfall ist z.B. Table Rate Shipping (also Versandkosten die z.B. von Gewicht + PLZ abhängig sind). Sicher gibt es aber noch viele weitere Anwendungsfälle.

In diesem Beitrag werden wir eine Versandart (Same Day Delivery) programmieren die folgende Funktionen besitzt:

  1. Der Shop Admin kann eine Uhrzeit wählen bis zu der die Versandart gewählt werden kann. Nur Bestellungen vor dieser Uhrzeit können diese Versandart wählen.
  2. Die Verandkosten berechnen sich auf Basis des Warenkorbwerts. Der Shop Admin kann die Versandkosten in Prozent festlegen.

Das fertige Plugin findest du auf GitHub:

https://github.com/derweili/Same-Day-Delivery

Versandart erstellen

Um eine Versandart anzulegen, erstellen wir eine eigene PHP Klasse die wir von der WC_Shipping_Method Klasse ableiten.

In der __construct() Methode müssen wir der Versandart initial ein paar Eigenschaften zuweisen. Außerdem müssen wir eine calculate_shipping() Methode für die Berechnung der Versandkosten anlegen. Über $this->add_rate() setzten wir diese aber erstmal auf 0€. Wir werden diese später weiter anpassen. Da die Versandart aber ohne diese Funktion nicht funktioniert müssen wir sie jetzt schon anlegen.

class DerweiliSameDayDelivery extends \WC_Shipping_Method {

	public function __construct(  $instance_id = 0  ) {
		$this->id 			= 'derweili-same-day-delivery'; // die ID der Versandart
		$this->instance_id		= absint( $instance_id ); // die ID der Instanz, da die Versandart mehrfach verwendet werden kann
		$this->method_title		= __('Same Day', 'derweili-same-day-delivery'); // Name der Versandart
		$this->title			= __('Same Day', 'derweili-same-day-delivery'); // Dargestellter Name der Versandart im Frontend und Backend
		$this->method_description 	= __('Same Day delivery', 'derweili-same-day-delivery'); // Beschreibung der Versandart

		$this->supports = array(
			'shipping-zones' // Die Versandart soll die WooCommerce Versandzonen unterstützen
		);
	}

	/**
	 * Die Versandkosten müssen immer angelegt werden, selbst wenn bei 0 liegen.
	 */
	public function calculate_shipping( $package = array() ) {
		$this->add_rate(
			array(
				'label'   => $this->title,
				'cost'    => 0,
				'taxes'   => false,
				'package' => $package,
			),
		);
	}
}
Code-Sprache: PHP (php)

Damit diese Versandart in den WooCommerce Versandeinstellungen auch ausgewählt werden kann muss diese erst registriert werden. Das geht über den woocommerce_shipping_methods Filter.

add_filter( 'woocommerce_shipping_methods', 'register_shipping_method', 10, 4 );

function register_shipping_method( $methods ) {
	$methods['derweili-same-day-delivery'] = 'DerweiliSameDayDelivery';

	return $methods;	
}
Code-Sprache: PHP (php)

Wichtig ist, dass der Array Key (Zeile 4) mit der ID der Versandart übereinstimmt (siehe erstes Code Snippet Zeile 4).

Jetzt wird diese Versandart schon in „Verandart hinzufügen“ Auswahl angezeigt. Wir können die Versandart einer Versandzone hinzufügen.

Weitere Einstellungen hinzufügen

Aktuell können wir zwar die Versandart hinzufügen, jedoch haben wir aktuell keine Möglichkeit irgendwelche Einstellungen vorzunehmen.

Für unser Beispiel brauchen wollen wir folgende Einstellungen vornehmen können:

  1. Die Versandart soll einen eigenen Namen zugewiesen bekommen
  2. Es soll eine Uhrzeit ausgewählt werden können. Same Day Bestellungen sind nur bis zu einer festgelegten Uhrzeit möglich
  3. Es soll ein Eingabefeld für die Versandkosten eingefügt werden. Bei diesem Feld handelt es sich um einen prozentwert, mit dem die Verandkosten auf Basis des Warenkorbwerts berechnet werden.

Um die Einstellungen hinzuzufügen müssen wir erstmal die $supports Property erweitern:

$this->supports = array(
	'shipping-zones',
	'instance-settings',
	'instance-settings-modal',
);
Code-Sprache: PHP (php)

Anschließend erstellen wir eine init() Methode in der wir die wiederum die init_form_fields() und init_settings() Methoden aufrufen.

public function init() {

	// Load the settings.
	$this->init_form_fields();
	$this->init_settings();

	// Define user set variables.
	$this->title      = $this->get_option( 'title' );
	$this->tax_status = $this->get_option( 'tax_status' );

	// Actions.
	add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
Code-Sprache: PHP (php)

Die init()Methode rufen wir im Constructor auf.

Jetzt müssen wir noch noch die init_form_fields() Methode anlegen und die Felder hinzufügen die wir benötigen:

public function init_form_fields() {
	parent::init_form_fields();

	$this->instance_form_fields = array_merge(
		$this->instance_form_fields,
		array(
			'title'      => array(
				'title'       => __( 'Title', 'woocommerce' ),
				'type'        => 'text',
				'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce' ),
				'default'     => __( 'Same Day', 'woocommerce' ),
				'desc_tip'    => true,
			),
			'tax_status' => array(
				'title'   => __( 'Tax status', 'woocommerce' ),
				'type'    => 'select',
				'class'   => 'wc-enhanced-select',
				'default' => 'taxable',
				'options' => array(
					'taxable' => __( 'Taxable', 'woocommerce' ),
					'none'    => _x( 'None', 'Tax status', 'woocommerce' ),
				),
			),
			'latestTimeToOrder' => array(
				'title' => __('Latest Time to Order', 'woo-same-day-delivery'),
				'type' => 'time',
				'description' => 'Latest time to order. Example: 17:00',
				'default' => '12:00'
			),
			'priceInPercent' => array(
				'title' => __('Price in Percent', 'woo-same-day-delivery'),
				'type' => 'number',
				'description' => 'Price in Percent',
				'default' => 7
			),
		)
	);

}
Code-Sprache: PHP (php)

Jetzt können wir die Einstellungen für die Versandkosten aufrufen und bearbeiten. Der Titel wir bereits übernommen und im Checkout angezeigt.

Verfügbarkeit der Versandart auf Basis der Uhrzeit begrenzen

Wir können zwar schon die Uhrzeit einstellen, bisher wird diese aber noch ignoriert. Die Versandart ist also immer verfügbar.

Um die Verfügbarkeit der Versandart zu ändern müssen wir unserer Verandart um die is_available() Methode erweitern.

public function is_available( $package ) {
	$latestTimeToOrder = $this->get_instance_option("latestTimeToOrder");
	
	$latest_time_timestamp = strtotime( $latestTimeToOrder . date( 'd-m-Y', current_time('timestamp') ) );
	$current_time = current_time('timestamp');
	
	if($latestTimeToOrder) {
		if ( $current_time > $latest_time_timestamp ) {
			return false;
		}
	}
	return true;
}
Code-Sprache: PHP (php)

In Zeile 2 rufen wir die in der Versandart hinterlegte Uhrzeit ab. Anschließend konvertieren wir diese zu einem Unix Timestamp und vergleichen diesen mit der aktuellen Timestamp. Zuletzt geben wir true oder false zurück, je nachdem ob die Uhrzeit in der Zukunft oder Vergangenheit liegt.

Natürlich könnten wir hier noch viele weitere Abfragen einbauen, z.B. um die Versandart auf Basis des Gewichts, der Produktkategorie oder der Anzahl an Produkten zu aktivieren/deaktivieren.

Versandkosten berechnen

Wie für die Verfügbarkeit, gibt es auch für die Berechnung der Versandkosten eine eigene Methode. Diese haben wir bereits eingebaut, da diese zwingend erforderlich ist damit die Versandkosten überhaupt funktionieren.

Jetzt berechnen wir auf Basis der Warenkorb Zwischensumme den Preis und übergeben diesen der $this->add_rate() Methode.

public function calculate_shipping( $package = array() ) {
	$cart_totals = \WC()->cart->cart_contents_total;
	$price_in_percent = $this->get_instance_option("priceInPercent");

	$shipping_cost = $cart_totals / 100 * $price_in_percent;

	$this->add_rate(
		array(
			'label'   => $this->title,
			'package' => $package,
			'cost'    => $shipping_cost,
		)
	);
}
Code-Sprache: PHP (php)

Bekannte Probleme

Es kann sein dass Änderungen an den Versandkosten nicht direkt sichtbar sind. Dies liegt daran dass WooCommerce das Ergebnis der `is_available()` Methode in der Cart-Session cached. Um Änderungen direkt zu sehen, reicht es aus einfach die Rechnungs/Versandadresse anzupassen oder die (Anzahl der) Produkte im Warenkorbzu ändern.

Weitere Informationen

Es lohnt sich die in WooCommerce integrierten Verandarten anzusehen und dort nachzuschauen wie diese integriert sind.

https://github.com/woocommerce/woocommerce/tree/master/includes/shipping

Dabei muss aber aber zwischen den „aktuellen“ und den (veralteten) Legacy Versandmethoden unterscheiden. Letztere unterstützen die Versandzonen nicht.

Plugin

Den hier gezeigten Beispielcode habe ich auf GitHub als WordPress Plugin hochgeladen:

https://github.com/derweili/Same-Day-Delivery


Beitrag veröffentlicht

in

, ,

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert