I want to show an estimated delivery time in my shop.
If a customer orders before 4pm, he gets his order the next day.
But if the order is on a friday or on the weekend, he gets the order on the next monday.
That all works fine. But I need to add some holidays like christmas, new year and local holidays based on a state in my country.
I found a solution to identify the fixed and flexible (like easter) holidays in my state.
But I don't know how to work with them in the current function.
If an order is placed before one of these holidays I need to move the future date some days ahead.
Here's the current code (based on this code):
date_default_timezone_set( 'Europe/Berlin' );
$current_year = date('Y');
$next_year = date('Y', strtotime( $current_year." + 1 year" ));
// Holidays
$neujahr = date('d.m.Y',strtotime(date($next_year.'-01-01')));
$ostern = date('d.m.Y', easter_date($current_year));
$karfreitag = date( "l jS F", strtotime( $ostern." - 2 days" ) );
$ostermontag = date( "l jS F", strtotime( $ostern." + 1 days" ) );
$tagderarbeit = date('d.m.Y',strtotime(date('Y-05-01')));
$himmelfahrt = date( "l jS F", strtotime( $ostern." + 39 days" ) );
$pfingstmontag = date( "l jS F", strtotime( $ostern." + 50 days" ) );
$fronleichnam = date( "l jS F", strtotime( $ostern." + 60 days" ) );
$einheit = date('d.m.Y',strtotime(date('Y-10-03')));
$allerheiligen = date('d.m.Y',strtotime(date('Y-11-01')));
$weihnachten1 = date('d.m.Y',strtotime(date('Y-12-25')));
$weihnachten2 = date('d.m.Y',strtotime(date('Y-12-26')));
// if FRI/SAT/SUN delivery will be MON
if ( date( 'N' ) >= 5 ) {
$del_day = date( "l jS F", strtotime( "next monday" ) );
$order_by = "Monday";
}
// if MON/THU after 4PM delivery will be TOMORROW
elseif ( date( 'H' ) >= 16 ) {
$del_day = date( "l jS F", strtotime( "tomorrow" ) );
$order_by = "tomorrow";
}
// if MON/THU before 4PM delivery will be TODAY
else {
$del_day = date( "l jS F", strtotime( "today" ) );
$order_by = "today";
}
$html = "<br><div class='woocommerce-message' style='clear:both'>Order by 4PM {$order_by} for delivery on {$del_day}</div>";
echo $html;
The working method you are currently applying can work with multiple different if / else statements to check all conditions, so I prefer a different approach.
It goes as follows
As of today date 8 possible delivery dates are generated (expl: today = 14/07/2020,
possible dates are 14, 15, 16, 17, 18, 19, 20 & 21/07/2020
If today is already after 4 pm, the date of today expires (14/07/2020)
Less than 4 pm but a Friday, Saturday or Sunday, remove date
Then remove the (other) dates from the weekend: friday, saturday & sunday (17, 18, 19/07/2020)
Then all holidays (if any) are filtered out of the result
In the last step, the first value in the result is used and shown in the output message.
Note: It is easy to test by adjusting $today = date( 'd.m.Y' ); values to any date in the future, like $today = date( '25.12.2024' ); which would return
Delivery on Monday 30th December
25, 26 = holidays. 27, 28 & 29/12/2024 = friday, saturday & sunday
date_default_timezone_set( 'Europe/Berlin' );
// Today
$today = date( 'd.m.Y' );
// Possible delivery dates from today
for ( $i = 0; $i <= 7; $i++) {
$possible_delivery_dates[] = date( 'd.m.Y', strtotime( $today . '+' . $i . 'days' ) );
}
// Today ?
if ( date( 'H', strtotime( $today ) ) >= 16 ) {
// Today NOT possible
unset( $possible_delivery_dates[0] );
} elseif ( date( 'N', strtotime( $today ) ) >= 5 ) {
// Today (weekend) NOT possible
unset( $possible_delivery_dates[0] );
}
// Next Fri, Sat & Sun
$next_friday = date( 'd.m.Y', strtotime( $today . 'next friday' ) );
$next_saturday = date( 'd.m.Y', strtotime( $today . 'next saturday' ) );
$next_sunday = date( 'd.m.Y', strtotime( $today . 'next sunday' ) );
// Remove next fri, sat & sun
$possible_delivery_dates = array_diff( $possible_delivery_dates, [ $next_friday, $next_saturday, $next_sunday ] );
// Current & next year
$current_year = date( 'Y', strtotime( $today ) );
$next_year = date( 'Y', strtotime( $today . '+ 1 year' ));
// Holidays
$neujahr = date( 'd.m.Y', strtotime( date( $next_year . '-01-01' ) ) );
$ostern = date( 'd.m.Y', easter_date( $current_year ) );
$karfreitag = date( 'd.m.Y', strtotime( $ostern . '- 2 days' ) );
$ostermontag = date( 'd.m.Y', strtotime( $ostern . '+ 1 days' ) );
$tagderarbeit = date( 'd.m.Y', strtotime( date( $current_year . '-05-01') ) );
$himmelfahrt = date( 'd.m.Y', strtotime( $ostern . '+ 39 days' ) );
$pfingstmontag = date( 'd.m.Y', strtotime( $ostern . '+ 50 days' ) );
$fronleichnam = date( 'd.m.Y', strtotime( $ostern . '+ 60 days' ) );
$einheit = date( 'd.m.Y', strtotime( date( $current_year . '-10-03' ) ) );
$allerheiligen = date( 'd.m.Y', strtotime( date( $current_year . '-11-01' ) ) );
$weihnachten1 = date( 'd.m.Y', strtotime( date( $current_year . '-12-25' ) ) );
$weihnachten2 = date( 'd.m.Y', strtotime( date( $current_year . '-12-26' ) ) );
// Holidays (array)
$holidays = array( $neujahr, $ostern, $karfreitag, $ostermontag, $tagderarbeit, $himmelfahrt, $pfingstmontag, $fronleichnam, $einheit, $allerheiligen, $weihnachten1, $weihnachten2 );
// Remove holidays
$possible_delivery_dates = array_diff( $possible_delivery_dates, $holidays );
// First value
$first_val = reset( $possible_delivery_dates );
$html = 'Delivery on ' . date( 'l jS F', strtotime( $first_val ) );
echo $html;
Related
I found that code here and I'm wondering how can I add example: if order created time > order created time + 5 minutes?
Now code just check today datetime and order created datetime and make datediff, but I want to make time diff.
If someone can help me, thanks already!
function myplugin_cancel_unpaid_wc_orders() {
global $myplugin_options;
$my_cancel_time = $myplugin_options['myplugin_cancel_time'];
//$date = date( "Y-m-d H:i:s", strtotime( '-' . absint( $myplugin_cancel_time ) . ' MINUTES', current_time( 'timestamp' ) ) );
$query = ( array(
'limit' => 5,
'orderby' => 'date',
'order' => 'DESC',
'status' => array( 'pending' )
) );
$orders = wc_get_orders( $query );
foreach ( $orders as $order ) {
$date = new DateTime( $order->get_date_created() );
$today = new DateTime();
$interval = $date->diff($today);
$datediff = $interval->format('%a');
if ( $datediff >= 4 ) {
$order->update_status('cancelled', 'Cancelled for missing payment');
}
}
}
Convert the order created date to seconds. 5 minutes equal 300 seconds.
$order_created_date = $order->get_date_created(); // Get order date created WC_DateTime Object
$order_created_seconds = $order_created_date->getTimestamp(); // Get order create date in seconds
$end_time = $order_created_seconds+300; // Order created time + 5mins
$current_time = time();
if ($current_time >= $end_time) { // Check if end time
$order->update_status('cancelled', 'Cancelled for missing payment');
}
I have this kind of array of days in a random order (number of days can be 1 until 5) :
$jour_planning[] = "sunday";
$jour_planning[] = "wednesday";
$jour_planning[] = "monday";
I would like to sort them, starting of "today".
I have this code working but only for 7 days in the array, how to adapt it ?
function sort_week_days( $t1, $t2 ) {
$weekdays = array( 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday' );
foreach ( $weekdays as $key => $value ) {
$weekdays[ $key ] = date( 'w', strtotime( $value ) );
}
$t1_time = date( 'w', strtotime( strtolower( $t1 ) ) );
$t2_time = date( 'w', strtotime( strtolower( $t2 ) ) );
return array_search( $t1_time, $weekdays ) - array_search( $t2_time, $weekdays );
}
usort($jour_planning, "sort_week_days");
$today_day = date('w', '-1day');
for ($i=0; $i <= $today_day ; $i++) {
array_push($jour_planning, array_shift($jour_planning));
}
Why can't I retrieve the data from a Woocommerce checkout field to update subscription data as the order processes?
I want to update the next renewal date based on the customers' frequency request on checkout. Here is my code:
1) Set up the checkout field:
add_action( 'woocommerce_after_order_notes', 'hgf_custom_checkout_field' );
function hgf_custom_checkout_field( $checkout ) {
global $woocommerce;
woocommerce_form_field( 'frequency', array(
'type' => 'select',
'required' => true,
'class' => array('form-row-wide'),
'label' => __('Change this any time, just email.'),
'options' => array(
'blank' => __( 'Select frequency preference', 'woocommerce' ),
1 => __( 'Every Week', 'woocommerce' ),
2 => __( 'Every Other Week' , 'woocommerce' ),
3 => __( 'Once Per Month' , 'woocommerce' )
)
), $checkout->get_value( 'frequency' ));
echo '</div>';
}
2) Update the order meta. This creates two custom fields on the customer order, as well as updates the billing interval on the subscription:
add_action( 'woocommerce_checkout_update_order_meta', 'hgf_checkout_field_update_order_meta' );
function hgf_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['frequency'] ) ) {
update_post_meta( $order_id, 'frequency', $_POST['frequency'] );
update_post_meta( $order_id, 'billing_interval', $_POST['frequency'] );
}
}
3) Update the renewal date
For the last part, I can update the renewal date with a dummy date of my choosing (for instance: $renewal date = "2018-12-15", but when I try to get it to read the 'billing_interval' field, it reverts to the else default.
add_action( 'woocommerce_checkout_create_subscription', 'hgf_next_renewal' );
function hgf_next_renewal( $subscription, $timezone='site' ) {
$billing_interval = get_post_meta( get_the_ID(), 'billing_interval', true);
if( $billing_interval == 2 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-10-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+2 weeks" ) ) */ ;
} if( $billing_interval == 4 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-12-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+4 weeks" ) ) */ ;
} else {
$renewal_date = date( 'Y-m-d H:i:s' ) ) /* date( 'Y-m-d H:i:s', strtotime( $renewal_date) ) */ ;
}
$subscription->update_dates( array(
'next_payment' => $renewal_date,
) );
return $subscription;
}
This is all the different ways I have tried:
1) $billing_interval = $subscription->get_billing_interval();
2) $billing_interval = get_post_meta( $subscription->get_ID(), 'billing_interval', true);
3) $billing_interval = get_post_meta( $order_id, 'billing_interval', true);
4) $subscriptions = wcs_get_users_subscriptions( $user_id );
foreach ( $subscriptions as $sub ) {
$billing_interval = get_post_meta( $sub->get_order_number(), '_billing_interval', true);
}
5) $billing_interval = $checkout->get_value( 'frequency' );
Does anyone know why I can't retrieve a value from my checkout field while in the 'woocommerce_checkout_create_subscription' action?
As you are saving your 'billing_interval' custom field in the Order meta data, you can't get this custom field through the subscription object or ID… You need to get first the Parent Order ID.
To get the parent Order ID from the subscription object you need to use the WC_Order method get_parent_id()
add_action( 'woocommerce_checkout_create_subscription', 'hgf_next_renewal' );
function hgf_next_renewal( $subscription, $timezone='site' ) {
// MISSING!: The parent order ID to set below
$order_parent_id = $subscription->get_parent_id();
$billing_interval = get_post_meta( $order_parent_id, 'billing_interval', true);
if( $billing_interval == 2 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-10-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+2 weeks" ) ) */ ;
} elseif( $billing_interval == 4 ) {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-12-01" ) ) /* date( 'Y-m-d H:i:s', strtotime( "+4 weeks" ) ) */ ;
} else {
$renewal_date = date( 'Y-m-d H:i:s', strtotime( "2017-09-01" ) ) /* date( 'Y-m-d H:i:s' ) */ ;
}
$subscription->update_dates( array(
'next_payment' => $renewal_date,
) );
return $subscription;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
I haven't tested your code for real, but it doesn't throw any error and should work for you this time.
I have php functions to get dates from this and next week. All is good except thursday - output from thursday is empty.
Here is my code:
$pondeli1 = date( 'd.m.Y', strtotime( 'monday this week' ) );
$utery1 = date( 'd.m.Y', strtotime( 'tuesday this week' ) );
$streda1 = date( 'd.m.Y', strtotime( 'wednesday this week' ) );
$ctrvtek1 = date( 'd.m.Y', strtotime( 'thursday this week' ) );
$patek1 = date( 'd.m.Y', strtotime( 'friday this week' ) );
$pondeli2 = date( 'd.m.Y', strtotime( 'monday next week' ) );
$utery2 = date( 'd.m.Y', strtotime( 'tuesday next week' ) );
$streda2 = date( 'd.m.Y', strtotime( 'wednesday next week' ) );
$ctrvtek2 = date( 'd.m.Y', strtotime( 'thursday next week' ) );
$patek2 = date( 'd.m.Y', strtotime( 'friday next week' ) );
And lines with "thursday next week" are not returning anything...
Where is problem please?
Try to use
$ctrvtek2 =strtotime("next Thursday",$ctrvtek1);
Was googling this, but couldn't find the answer. Was wondering, if there is a difference in these two scripts?
+3 day:
echo date( 'd.m.Y H:i:s', strtotime( '+3 day' ) );
+3 days:
echo date( 'd.m.Y H:i:s', strtotime( '+3 days' ) );
The output is exactly the same.
So is that implemented to make sure people get less errors or what?
And witch one should be preferred to use?
That is basically same thing, and for usability and pretty purposes:
strtotime( '+1 day' );
strtotime( '+3 day' );
strtotime( '+1 days' );
strtotime( '+3 days' );
strtotime( '+1 weeks' );
strtotime( '+3 week' );
You can use the one you like more, basically the one that defines de number, 1 day, 3 days