namespace Automattic\WooCommerce\Blocks\Shipping;
* Local Pickup Shipping Method.
class PickupLocation extends WC_Shipping_Method {
protected $pickup_locations = [];
public function __construct() {
$this->id = 'pickup_location';
$this->method_title = __( 'Local pickup', 'woocommerce' );
$this->method_description = __( 'Allow customers to choose a local pickup location during checkout.', 'woocommerce' );
$this->enabled = $this->get_option( 'enabled' );
$this->title = $this->get_option( 'title', __( 'Pickup', 'woocommerce' ) );
$this->tax_status = $this->get_option( 'tax_status' );
$this->cost = $this->get_option( 'cost' );
$this->supports = [ 'settings', 'local-pickup' ];
$this->pickup_locations = get_option( $this->id . '_pickup_locations', [] );
add_filter( 'woocommerce_attribute_label', array( $this, 'translate_meta_data' ), 10, 3 );
* Checks if a given address is complete.
* @param array $address Address.
protected function has_valid_pickup_location( $address ) {
$address_fields = wp_parse_args(
// Country is always required.
if ( empty( $address_fields['country'] ) ) {
// If all fields are provided, we can skip further checks.
if ( ! empty( $address_fields['city'] ) && ! empty( $address_fields['postcode'] ) && ! empty( $address_fields['state'] ) ) {
// Check validity based on requirements for the country.
$country_address_fields = wc()->countries->get_address_fields( $address_fields['country'], 'shipping_' );
foreach ( $country_address_fields as $field_name => $field ) {
$key = str_replace( 'shipping_', '', $field_name );
if ( isset( $address_fields[ $key ] ) && true === $field['required'] && empty( $address_fields[ $key ] ) ) {
* @param array $package Package information.
public function calculate_shipping( $package = array() ) {
if ( $this->pickup_locations ) {
foreach ( $this->pickup_locations as $index => $location ) {
if ( ! $location['enabled'] ) {
'id' => $this->id . ':' . $index,
// This is the label shown in shipping rate/method context e.g. London (Local Pickup).
'label' => wp_kses_post( $this->title . ' (' . $location['name'] . ')' ),
'pickup_location' => wp_kses_post( $location['name'] ),
'pickup_address' => $this->has_valid_pickup_location( $location['address'] ) ? wc()->countries->get_formatted_address( $location['address'], ', ' ) : '',
'pickup_details' => wp_kses_post( $location['details'] ),
* See if the method is available.
* @param array $package Package information.
public function is_available( $package ) {
// phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', 'yes' === $this->enabled, $package, $this );
* Translates meta data for the shipping method.
* @param string $label Meta label.
* @param string $name Meta key.
* @param mixed $product Product if applicable.
public function translate_meta_data( $label, $name, $product ) {
return __( 'Pickup location', 'woocommerce' );
return __( 'Pickup address', 'woocommerce' );
return __( 'Pickup details', 'woocommerce' );
* See also WC_Shipping_Method::admin_options().
public function admin_options() {
global $hide_save_button;
$hide_save_button = true;
wp_enqueue_script( 'wc-shipping-method-pickup-location' );
echo '<h2>' . esc_html__( 'Local pickup', 'woocommerce' ) . '</h2>';
echo '<div class="wrap"><div id="wc-shipping-method-pickup-location-settings-container"></div></div>';