Local Pickup Points Selector

Allows customers to select a local pickup location during checkout.

Display estimated delivery date
PHP
/**
 * Snippet Name:     Local Pickup Points Selector
 * Snippet Author:   coding-bunny.com
 * Description:      Allows customers to select a local pickup location during checkout.
 */

/* Add here your pickup points */
function cblpp_get_pickup_points() {
	return array(
		'store_milan' => array(
			'label'   => 'Milan Store',
			'address' => 'Via Roma 1, 20100 Milan (MI)',
		),
		'store_rome' => array(
			'label'   => 'Rome Store',
			'address' => 'Piazza Navona 10, 00186 Rome (RM)',
		),
		'store_turin' => array(
			'label'   => 'Turin Store',
			'address' => 'Corso Francia 100, 10143 Turin (TO)',
		),
	);
}

add_action('woocommerce_after_shipping_rate', function($method, $index){
	if( strpos($method->id, 'local_pickup') !== false ) {
		$pickup_points = cblpp_get_pickup_points();
		$selected = isset($_POST['pickup_point']) ? sanitize_text_field($_POST['pickup_point']) : '';

		echo '
		<style>
		.cblpp-pickup-point-selector {
			margin: 10px 0 0 32px;
			padding: 10px 12px 12px 12px;
			background: #f7fafd;
			border: 1px solid #e2edef;
			border-radius: 8px;
			max-width: 400px;
		}
		.cblpp-pickup-point-selector strong {
			display: block;
			margin-bottom: 8px;
			font-size: 15px;
			font-weight: 700;
			color: #222;
		}
		.cblpp-pickup-radio-label {
			display: flex;
			align-items: flex-start;
			gap: 10px;
			margin-bottom: 7px;
			background: #fcfcfc;
			padding: 8px 10px;
			border-radius: 6px;
			border: 1px solid #e2edef;
			cursor: pointer;
			transition: border-color 0.2s;
		}
		.cblpp-pickup-radio-label input[type="radio"] {
			margin: 2px 12px 0 0;
			width: 20px;
			height: 20px;
			accent-color: #142520;
			flex-shrink: 0;
			cursor: pointer;
		}
		.cblpp-pickup-radio-label span {
			display: flex;
			flex-direction: column;
			gap: 1px;
		}
		.cblpp-pickup-radio-label .label-title {
			font-weight: 700;
			font-size: 15px;
			color: #222;
		}
		.cblpp-pickup-radio-label .label-address {
			font-size: 13px;
			color: #666;
		}
		.cblpp-pickup-radio-label input[type="radio"]:checked + span .label-title {
			color: #142520;
		}
		@media (max-width: 600px) {
			.cblpp-pickup-point-selector { max-width: 100%; }
			.cblpp-pickup-radio-label { flex-direction: column; align-items: flex-start; }
			.cblpp-pickup-radio-label input[type="radio"] { margin-bottom: 8px; }
		}
		</style>
		';

		echo '<div class="cblpp-pickup-point-selector">';
		echo '<strong>Select pickup location:</strong>';
		foreach($pickup_points as $key => $point) {
			$radio_id = 'pickup_point_' . esc_attr($key);
			printf(
				'<label class="cblpp-pickup-radio-label" for="%s">
					<input type="radio" id="%s" name="pickup_point" value="%s" %s required>
					<span>
						<span class="label-title">%s</span>
						<span class="label-address">%s</span>
					</span>
				</label>',
				$radio_id,
				$radio_id,
				esc_attr($key),
				checked($selected, $key, false),
				esc_html($point['label']),
				esc_html($point['address'])
			);
		}
		echo '</div>';
		?>
		<script>
		jQuery(function($){
			function togglePickupPoints() {
				var sel = $('input[name^="shipping_method"]:checked');
				var show = sel.length && sel.val() && sel.val().indexOf('local_pickup') !== -1;
				$('.cblpp-pickup-point-selector').toggle(show);
			}
			$(document).on('change', 'input[name^="shipping_method"]', togglePickupPoints);
			$(document.body).on('updated_checkout', togglePickupPoints);
			togglePickupPoints();
		});
		</script>
		<?php
	}
}, 10, 2);

add_action('woocommerce_checkout_process', function(){
	$chosen_methods = WC()->session->get('chosen_shipping_methods', array());
	if ( is_array($chosen_methods) && array_filter($chosen_methods, function($m){ return strpos($m, 'local_pickup') !== false; }) ) {
		$points = cblpp_get_pickup_points();
		if ( empty($_POST['pickup_point']) || !array_key_exists($_POST['pickup_point'], $points) ) {
			wc_add_notice('Please select a pickup location.', 'error');
		}
	}
});

add_action('woocommerce_checkout_create_order', function($order, $data){
	if ( !empty($_POST['pickup_point']) ) {
		$points = cblpp_get_pickup_points();
		$key = sanitize_text_field($_POST['pickup_point']);
		if ( isset($points[$key]) ) {
			$order->update_meta_data('pickup_point_label', $points[$key]['label']);
			$order->update_meta_data('pickup_point_address', $points[$key]['address']);
		}
	}
}, 10, 2);

add_action('woocommerce_admin_order_data_after_shipping_address', function($order){
	$label = $order->get_meta('pickup_point_label');
	$address = $order->get_meta('pickup_point_address');
	if ($label && $address) {
		echo '<p><strong>Pickup location:</strong> ' . esc_html($label) . '<br><small>' . esc_html($address) . '</small></p>';
	}
});

add_action('woocommerce_order_details_after_customer_details', function($order){
	$label = $order->get_meta('pickup_point_label');
	$address = $order->get_meta('pickup_point_address');
	if ($label && $address) {
		echo '<section class="woocommerce-customer-details">';
		echo '<h2>Pickup location</h2>';
		echo '<p>' . esc_html($label) . '<br><small>' . esc_html($address) . '</small></p>';
		echo '</section>';
	}
});

add_action('woocommerce_email_after_order_table', function($order, $sent_to_admin, $plain_text, $email){
	$label = $order->get_meta('pickup_point_label');
	$address = $order->get_meta('pickup_point_address');
	if ($label && $address) {
		if ($plain_text) {
			echo "\nPickup location: " . $label . " - " . $address . "\n";
		} else {
			echo '<h3>Pickup location</h3>';
			echo '<p>' . esc_html($label) . '<br><small>' . esc_html($address) . '</small></p>';
		}
	}
}, 10, 4);

How To Implement This Solution?

Leave a Reply