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( ' <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;
}