WooCommerce Porterage Fee

How to force shipping for specific category, add porterage option, and display the lead time?
Update the categories and the lead times:

add_filter( 'woocommerce_checkout_fields', 'wc_add_fields' );
add_action( 'woocommerce_cart_calculate_fees', 'wc_add_checkout_fee' );
add_filter( 'woocommerce_package_rates', 'wc_set_shipping_methods', 10, 2 );
add_action( 'woocommerce_review_order_before_submit', 'wc_add_lead_time' );
add_filter( 'woocommerce_email_order_meta_fields', 'wc_add_email_order_meta_fields', 10, 3 );
add_action( 'woocommerce_thankyou', 'wc_display_order_meta' );
add_action( 'woocommerce_view_order', 'wc_display_order_meta' );
add_action( 'woocommerce_admin_order_data_after_billing_address', 'wc_admin_display_order_meta' );

function wc_add_fields( $fields ) {
	$fields['billing']['billing_floor'] = [
		'label'		=> __( 'Floor', 'woocommerce' ),
		'required'	=> true,
		'priority'	=> $fields['billing']['billing_address_1']['priority'] + 2,
		'type'		=> 'number',
		'class'		=> [ 'update_totals_on_change' ],
		'custom_attributes'	=> [ 'min' => 0 ],
	];
	$fields['billing']['billing_elevator'] = [
		'label'		=> __( 'Elevator', 'woocommerce' ),
		'required'	=> true,
		'priority'	=> $fields['billing']['billing_floor']['priority'] + 2,
		'type'		=> 'select',
		'options'	=> [ 'no' => 'no', 'yes' => 'yes' ],
		'default'	=> 'no',
		'class'		=> [ 'update_totals_on_change' ],
	];
 	$fields['billing']['billing_porterage'] = [
		'label'		=> __( 'Porterage', 'woocommerce' ),
		'required'	=> true,
		'priority'	=> $fields['billing']['billing_elevator']['priority'] + 2,
		'type'		=> 'select',
		'options'	=> [ 'no' => 'without', 'yes' => 'include' ],
		'default'	=> 'no',
		'class'		=> [ 'update_totals_on_change' ],
	]; ?>
	<script type="text/javascript">
	jQuery( function( $ ) {
		$( '#billing_floor' ).on( 'keyup change', function() {
			$( 'body' ).trigger( 'update_checkout' );
		} );
	} );
	</script>
	<?php return $fields;
}

function wc_add_checkout_fee() {
	$elevator_fee = 10;
	$price_per_floor = 20;
	if ( ( ! is_admin() || wp_doing_ajax() ) && false === strpos( WC()->session->get( 'chosen_shipping_methods' )[0], 'local_pickup' ) ) {
		if ( isset( $_POST['post_data'] ) ) {
			parse_str( $_POST['post_data'], $post_data );
		} else {
			$post_data = $_POST;
		}
		if ( ! empty( $post_data['billing_floor'] ) && ! empty( $post_data['billing_elevator'] ) && ! empty ( $post_data['billing_porterage'] ) && 'yes' === $post_data['billing_porterage'] ) {
			WC()->cart->add_fee( __( 'Porterage', 'woocommerce' ), 'yes' === $post_data['billing_elevator'] ? $elevator_fee : $price_per_floor * $post_data['billing_floor'], true );
		}
	}
}

function wc_set_shipping_methods( $rates, $package ) {
	$pickup_only_cat = [ '22' ];
	$cart_cat = [];
	foreach ( WC()->cart->get_cart() as $cart_item ) {
		$cart_cat = array_merge( $cart_cat, wc_get_product_cat_ids( $cart_item['product_id'] ) );
	}
	$cart_cat = array_unique( $cart_cat );
	if ( array_intersect( $cart_cat, $pickup_only_cat ) ) {
		foreach ( $rates as $rate_id => $rate ) {
			if ( 'local_pickup' !== $rate->method_id ) {
				unset( $rates[ $rate_id ] );
			}
		}
	}
	return $rates;
}

function wc_add_lead_time() {
	$cat_14 = [ '45' ];
	$lead_time = '1 business day';
	$cart_cat = [];
	foreach ( WC()->cart->get_cart() as $cart_item ) {
		$cart_cat = array_merge( $cart_cat, wc_get_product_cat_ids( $cart_item['product_id'] ) );
	}
	$cart_cat = array_unique( $cart_cat );
	if ( array_intersect( $cart_cat, $cat_14 ) ) {
		$lead_time = '14 business days';
	} ?>
	<table class="woocommerce-table shop_table gift_info">
		<tbody>
			<tr>
				<th><?php _e( 'Lead time', 'woocommerce' ); ?></th>
				<td><?php echo $lead_time; ?></td>
			</tr>
		</tbody>
	</table>
<?php }

function wc_add_email_order_meta_fields( $fields, $sent_to_admin, $order_obj ) {
	$fields['billing_floor'] = [
		'label'	=> __( 'Floor', 'woocommerce' ),
		'value'	=> get_post_meta( $order_obj->get_order_number(), '_billing_floor', true ),
	];
	$fields['billing_elevator'] = [
		'label'	=> __( 'Elevator', 'woocommerce' ),
		'value'	=> 'yes' === get_post_meta( $order_obj->get_order_number(), '_billing_elevator', true ) ? 'yes' : 'no',
	];
	$fields['billing_porterage'] = [
		'label'	=> __( 'Porterage', 'woocommerce' ),
		'value'	=> 'yes' === get_post_meta( $order_obj->get_order_number(), '_billing_porterage', true ) ? 'include' : 'without',
	];
	return $fields;
}

function wc_admin_display_order_meta( $order ) {
	echo '<strong>' . __( 'Floor', 'woocommerce' ) . '</strong> ' . get_post_meta( $order->get_id(), '_billing_floor', true ) . '. <strong>' . __( 'Elevator', 'woocommerce' ) . '</strong> ' . ( 'yes' === get_post_meta( $order->get_id(), '_billing__levator', true ) ? 'yes' : 'no' ) . '. <strong>' . __( 'Porterage', 'woocommerce' ) . '</strong> ' . ( 'yes' === get_post_meta( $order->get_id(), '_billing_porterage', true ) ? 'include' : 'without' );
}

function wc_display_order_meta( $order_id ) {
	echo '<strong>' . __( 'Floor', 'woocommerce' ) . '</strong> ' . get_post_meta( $order_id, '_billing_floor', true ) . '. <strong>' . __( 'Elevator', 'woocommerce' ) . '</strong> ' . ( 'yes' === get_post_meta( $order_id, '_billing__levator', true ) ? 'yes' : 'no' ) . '. <strong>' . __( 'Porterage', 'woocommerce' ) . '</strong> ' . ( 'yes' === get_post_meta( $order_id, '_billing_porterage', true ) ? 'include' : 'without' );
}

What if the fields were created using a plugin and multiple packages feature is used?

add_filter( 'woocommerce_form_field', 'remove_optional_fields_label', 10, 4 );
add_filter( 'woocommerce_checkout_fields', 'wc_remove_checkout_fields' );
add_action( 'woocommerce_after_checkout_form', 'wc_hide_porterage' );
add_filter( 'woocommerce_shipping_package_name', 'wc_package_name', 10, 2 );
add_filter( 'woocommerce_package_rates', 'wc_modify_pickup_label', 10, 2 );

function remove_optional_fields_label( $field, $key, $args, $value ) {
	return is_checkout() && in_array( $key, [ 'billing_porterage', 'billing_assembly' ] ) ? str_replace( '&nbsp;<span class="optional">(' . esc_html__( 'optional', 'woocommerce' ) . ')</span>', '', $field ) : $field;
}

function wc_remove_checkout_fields( $fields ) {
	$fields['billing']['billing_floor']['type'] = 'number';
	$fields['billing']['billing_floor']['custom_attributes'] = [ 'min' => '0', 'max' => '50' ];
	$fields['billing']['billing_porterage']['type'] = $fields['billing']['billing_assembly']['type'] = 'checkbox';
	$fields['billing']['billing_assembly']['default'] = '1';
	return $fields;
}

function wc_hide_porterage() {
	$none_porterage_cat = [ '21', '22' ];
	$cart_cat = [];
	foreach ( WC()->cart->get_cart() as $cart_item ) {
		$cart_cat = array_merge( $cart_cat, wc_get_product_cat_ids( $cart_item['product_id'] ) );
	}
	if ( ! array_intersect( $cart_cat, $none_porterage_cat ) ) { ?>
		<script type="text/javascript">
		jQuery( function( $ ) {
			$( 'body' ).on( 'updated_checkout', function() {
				var shipping_method = $( 'input[name^="shipping_method"]' ).attr( 'type' ) == 'hidden' ? $( 'input[name^="shipping_method"]' ).val() : $( 'input[name^="shipping_method"]:checked' ).val();
				if ( shipping_method.match( "^local_pickup" ) ) {
					$( '#billing_porterage_field, #billing_assembly_field' ).hide();
					if ( $( '#billing_porterage' ).is( ':checked' ) || $( '#billing_assembly' ).is( ':checked' ) ) {
						$( '#billing_porterage, #billing_assembly' ).prop( 'checked', false ).trigger( 'change' );
					}
				} else {
					$( '#billing_porterage_field, #billing_assembly_field' ).show();
				}
			} );
		} );
		</script>
	<?php }
}

function wc_package_name( $name, $i ) {
	return ( $i + 1 ) > 1 ? 'Shipping ' . ( $i + 1 ) : $name;
}

function wc_modify_pickup_label( $rates, $package ) {
	$pickup_lead_cat = [ '20' ];
	$long_lead_cat = [ '20', '22' ];
	$cart_cat = [];
	foreach ( $package['contents'] as $cart_item ) {
		$cart_cat = array_merge( $cart_cat, wc_get_product_cat_ids( $cart_item['product_id'] ) );
	}
	$cart_cat = array_unique( $cart_cat );
	if ( array_intersect( $cart_cat, $pickup_lead_cat ) ) {
		foreach ( $rates as $rate_id => $rate ) {
			if ( 'local_pickup' === $rate->method_id ) {
				$rates[ $rate_id ]->label = $rates[ $rate_id ]->label . ' (after 7 business days)';
			}
		}
	}
	if ( ! array_intersect( $cart_cat, $long_lead_cat ) ) {
		foreach ( $rates as $rate_id => $rate ) {
			$rates[ $rate_id ]->label = str_replace( '7', '3', str_replace( '14', '3', $rates[ $rate_id ]->label ) );
		}
	}
	return $rates;
}

Leave a comment

Your email address will not be published. Required fields are marked *