Banner

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

My Agile Privacy
This site uses technical and profiling cookies. You can accept, decline or customize cookies by pressing the desired buttons. By closing this policy you will continue without accepting.

Need help?

Choose one of the following options:

Powered by CodingBunny