ositis ositis - 3 years ago 170
PHP Question

WooCommerce checkout select field: Insert a key/value before calculated options array

I am a total newcomer when it comes to coding and currently I am working on my WordPress website.

How can I add one constant value, which would always be the first value in the drop down list which consists of times (hour:minute)? The constant value at the top should say "As soon as possible"

Here is the code which generates the form itself:

public function time_select( $checkout ) {
echo '<div id="local-pickup-time-select"><h2>' . __( 'Delivery Time', $this->plugin_slug ) . '</h2>';

woocommerce_form_field( 'local_pickup_time_select', array(
'type' => 'select',
'class' => array( 'local-pickup-time-select-field form-row-wide' ),
'label' => __( 'Delivery Time', $this->plugin_slug ),
'required' => true,
'options' => self::create_hour_options()
), $checkout->get_value( 'local_pickup_time_select' ));

self::create_hour_options();

echo '</div>';
}

public function pickup_time_select_translatable( $value ) {
$value = preg_replace('/(\d)_(\d)/','$1:$2', $value);
$value = explode('_', $value);
$return = __( $value[0], $this->plugin_slug ). ' ' .$value[1];
return $return;
}

public function create_hour_options() {
// Make sure we have a time zone set
$offset = get_option( 'gmt_offset' );
$timezone_setting = get_option( 'timezone_string' );

if ( $timezone_setting ) {
date_default_timezone_set( get_option( 'timezone_string', 'America/New_York' ) );
}
else {
$timezone = timezone_name_from_abbr( null, $offset * 3600, true );
if( $timezone === false ) $timezone = timezone_name_from_abbr( null, $offset * 3600, false );
date_default_timezone_set( $timezone );
}

// Get days closed textarea from settings, explode into an array
$closing_days_raw = trim( get_option( 'local_pickup_hours_closings' ) );
$closing_days = explode( "\n", $closing_days_raw );
$closing_days = array_filter( $closing_days, 'trim' );

// Get delay, interval, and number of days ahead settings
$delay_minutes = get_option( 'local_pickup_delay_minutes', 60 );
$interval = get_option( 'local_pickup_hours_interval', 30 );
$num_days_allowed = get_option( 'local_pickup_days_ahead', 1 );

// Setup time variables for calculations
$today_name = strtolower( date( 'l' ) );
$today_date = date( 'm/d/Y' );

// Create an empty array for our dates
$pickup_options = array();

//Translateble days
__( 'Monday', $this->plugin_slug );
__( 'Tuesday', $this->plugin_slug );
__( 'Wednesday', $this->plugin_slug );
__( 'Thursday', $this->plugin_slug );
__( 'Friday', $this->plugin_slug );
__( 'Saturday', $this->plugin_slug );
__( 'Sunday', $this->plugin_slug );

// Add empty option
$pickup_options[''] = __( 'Select time', $this->plugin_slug );

// Loop through all days ahead and add the pickup time options to the array
for ( $i = 0; $i < $num_days_allowed; $i++ ) {

// Get the date of current iteration
$current_day_name = date( 'l', strtotime( "+$i days" ) );
$current_day_name_lower = strtolower( $current_day_name );

// Get the day's opening and closing times
$open_time = get_option( 'local_pickup_hours_' . $current_day_name_lower . '_start', '10:00' );
$close_time = get_option( 'local_pickup_hours_' . $current_day_name_lower . '_end', '19:00' );

// Today
$tStart = strtotime( $open_time );
$tEnd = strtotime( $close_time );
$tNow = $tStart;
$current_time = time();

// Date format based on user settings
$date_format = get_option('time_format');
$date_format_key = preg_replace("/[^\w]+/", "_", $date_format);

// If Closed today or today's pickup times are over, don't allow a pickup option
if ( ( in_array( $today_date, $closing_days ) || ( $current_time >= $tEnd ) ) && $num_days_allowed == 1 ) {

// Set drop down text to let user know store is closed
$pickup_options['closed_today'] = __( 'Closed today, please check back tomorrow!', $this->plugin_slug );

// Hide Order Review so user doesn't order anything today
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_order_review', 10 );
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );

}
else {
// Create array of time options to return to woocommerce_form_field

// Today
if ( $i == 0) {

// Check if it's not too late for pickup
if ( $current_time < $tEnd ) {

// Fix tNow if is pickup possible today
if ( $i == 0 ) {
$todayStart = $tStart;
$delayStart = strtotime("+$delay_minutes minutes", $current_time);
while ( $todayStart <= $delayStart ) {
$todayStart = strtotime("+$interval minutes", $todayStart);
}
$tNow = $todayStart;
}

while ( $tNow <= $tEnd ) {

$day_name = __( 'Today', $this->plugin_slug );

$option_key = $current_day_name . date( $date_format_key, $tNow );
$option_value = $day_name . ' ' . date( $date_format, $tNow );

$pickup_options[$option_key] = $option_value;

$tNow = strtotime( "+$interval minutes", $tNow );
}

}

// Other days
} else {

if ( !empty($open_time) && !empty($close_time )) {
while ( $tNow <= $tEnd ) {

$day_name = __( $current_day_name, $this->plugin_slug );

$option_key = $current_day_name . date( $date_format_key, $tNow );
$option_value = $day_name . ' ' . date( $date_format, $tNow );

$pickup_options[$option_key] = $option_value;

$tNow = strtotime( "+$interval minutes", $tNow );

}

}
}

}

} // end for loop

if ( count($pickup_options) == 1) {
// Set drop down text to let user know store is closed
$pickup_options['closed_today'] = __( 'Closed today, please check back tomorrow!', $this->plugin_slug );

// Hide Order Review so user doesn't order anything today
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_order_review', 10 );
remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 );
}

return $pickup_options;
}


The final result would look something like this:

Drop-down list:

As soon as possible
Tuesday 7:30 pm
Tuesday 8:00 pm
Tuesday 8:30 pm

Answer Source

There is many ways to do it depending if the key value you want for "As soon as possible" choice has to be dynamic. This is done in your first function with array_merge() this way:

public function time_select( $checkout ) { 
    echo '<div id="local-pickup-time-select"><h2>' . __( 'Delivery Time', $this->plugin_slug ) . '</h2>';

    // The default empty value and your translatable sentence to be included
    $array_to_insert = array( 
        ''        => __( 'Select your delivery time', $this->plugin_slug ),
        'as_soon' => __( 'As soon as possible', $this->plugin_slug ) 
    );

    // Getting your calculated hours options array
    $options = self::create_hour_options();

    // Merging both arrays in one
    $options = array_merge( $array_to_insert, $options );

    woocommerce_form_field( 'local_pickup_time_select', array(
        'type'          => 'select',
        'class'         => array( 'local-pickup-time-select-field form-row-wide' ),
        'label'         => __( 'Delivery Time', $this->plugin_slug ),
        'required'      => true,
        'options'       => $options,
    ), $checkout->get_value( 'local_pickup_time_select' ));

    echo '</div>';
}

Code goes in function.php file of your active child theme (or theme) or also in any plugin file.

Tested and works. you will get that:

enter image description here

I have noticed in your code that your //Translateble days (monday to sunday) are not set in individual variables or in an array…

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download