I have created a PHP function that calculates how old a WordPress/WooCommerce order is. If the order is older than 90 days it should be canceled. The function used to work perfectly. However, since the new year 2020, it has stopped working. I would assume it's because the function gets confused about the year since -90 days from today is year 2019. How can I make the calculation work with the past years/2019?
I have tried playing with different date formats from the WordPress codex instead of mdy. However, this doesn't seem to do any difference.
function expire_after_x_days(){
global $wpdb;
// Get current time
$today = date("m/d/y");
// set time to expire
$time_to_expire = "-90 days";
$expiration_date = date("m/d/y", strtotime( $today . $time_to_expire));
// Get orders with processing status
$result = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'shop_order' AND post_status = 'wc-processing'");
if( !empty($result)) foreach ($result as $order){
// Get order's time
$order_time = get_the_time('m/d/y', $order->ID );
// Compare order's time with current time
if ( $order_time < $expiration_date ){
// Update order status
$orders = array();
$orders['ID'] = $order->ID;
$orders['post_status'] = 'wc-cancelled';
wp_update_post( $orders );
}
}
}
add_action( 'admin_footer', 'expire_after_x_days' );
You can simplify this a lot by running an UPDATE query with a WHERE clause, to only fetch those orders that are older than 90 days. No need to fetch them all and loop over the results.
You will need to set the post_created to the actual name of your column.
function expire_after_x_days() {
global $wpdb;
$result = $wpdb->query("UPDATE $wpdb->posts
SET post_status = 'wc-cancelled'
WHERE post_type = 'shop_order'
AND post_status = 'wc-processing'
AND post_created < DATE_SUB(NOW(), INTERVAL 90 DAY)");
}
You are treating those variables as DateTime instances, but they are strings. This $order_time < $expiration_date compares the strings alphabetically, not by their date meaning. Use DateTime class (https://www.php.net/manual/en/class.datetime.php) instead.
Please change date format from m/d/y to Y-m-d. Please see below code.
you can also check manually by modify $order_time = '12/11/18';
function expire_after_x_days(){
global $wpdb;
// Get current time
$today = date("Y-m-d");
// set time to expire
$time_to_expire = "-90 days";
$expiration_date = date("Y-m-d", strtotime( $today . $time_to_expire));
// Get orders with processing status
$result = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'shop_order' AND post_status = 'wc-processing'");
if( !empty($result)){
foreach ($result as $order){
// Get order's time
$order_time = get_the_time('Y-m-d', $order->ID );
// Compare order's time with current time
//$order_time = '12/11/18';
if ( $order_time < $expiration_date ){
//die("olde");
// Update order status
$orders = array();
$orders['ID'] = $order->ID;
$orders['post_status'] = 'wc-cancelled';
wp_update_post( $orders );
}else{
//echo 'not old date';die;
}
}
}
}
add_action( 'admin_footer', 'expire_after_x_days' );
Related
I want to check if a Woocommerce product was created less than 60 days ago. - If true, do something.
I am obtaining the date the product was created in backend/admin using the official Woocmmerce function $product->get_date_created.
My code partially works, but it seems to be checking if $product->get_date_created literally contains the value 60 instead of perfoming the calculation and minusing 60 days from the current DateTime.
I have come to this conclusion because my IF statement runs true and is applied to all products with "60" in the actual DateTime string. (e.g. 12/31/2060)...this is not what I want.
Any help appreciated.
My code:
add_action( 'woocommerce_before_shop_loop_item_title', 'display_new_loop_woocommerce' );
function display_new_loop_woocommerce() {
global $product;
// Get the date for the product published and current date
$start = date( 'n/j/Y', strtotime( $product->get_date_created() ));
$today = date( 'n/j/Y' );
// Get the date for the start of the event and today's date.
$start = new \DateTime( $start );
$end = new \DateTime( $today );
// Now find the difference in days.
$difference = $start->diff( $end );
$days = $difference->d;
// If the difference is less than 60, apply "NEW" label to product archive.
if ( $days = (60 < $days) ) {
echo '<span class="limited">' . __( 'NEW', 'woocommerce' ) . '</span>';
}
}
I have revisited a bit your code using the WC_DateTime methods instead, which will keep the time zone settings from the shop:
add_action( 'woocommerce_before_shop_loop_item_title', 'display_new_loop_woocommerce' );
function display_new_loop_woocommerce() {
global $product;
// Get the date for the product published and current date
$datetime_created = $product->get_date_created(); // Get product created datetime
$timestamp_created = $datetime_created->getTimestamp(); // product created timestamp
$datetime_now = new WC_DateTime(); // Get now datetime (from Woocommerce datetime object)
$timestamp_now = $datetime_now->getTimestamp(); // Get now timestamp
$time_delta = $timestamp_now - $timestamp_created; // Difference in seconds
$sixty_days = 60 * 24 * 60 * 60; // 60 days in seconds
// If the difference is less than 60, apply "NEW" label to product archive.
if ( $time_delta < $sixty_days ) {
echo '<span class="limited">' . __( 'NEW', 'woocommerce' ) . '</span>';
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Ok so I have this code and im not sure exactly how to go about checking if the post modified date was more than a week ago.
So if the post was modified more than a week ago it should echo modified.
The code:
$sticky = get_option( 'sticky_posts' );
if (count($sticky) > 0) {
$stringSticky = implode(",", $sticky);
$postsModifiedCheck = $wpdb->get_results(
"SELECT ID, post_modified
FROM `{$wpdb->prefix}posts`
WHERE post_status = 'publish' AND post_type = 'post'
AND ID IN ($stringSticky)"
);
$now = new DateTime();
$currentDateTime = $now->getTimestamp();
foreach ($postsModifiedCheck as $post) {
if ($currentDateTime > $post->post_modified) {
echo "modified";
}
}
}
So at the moment it will echo "modified", just not sure how to modify the dates to echo "modified" if $post->post_modified more than a week ago.
Cheers
check your formats -
var_dump($currentDateTime .' <- current date - modified date -> '.$post->post_modified );
see if they are the same format,
if they are not the same format, force them to be the same like this
then when you get to that point - just create a variable where you check the difference f.eks
if($currentDateTime - $post->post_modified >= 7){echo 'shiit, It has been modified over a week ago'; }
This should help you on your way
Ok so this is how I solved the problem.
While in the loop use this code:
$weekAgo = strtotime('-1 week');
foreach ($postsModifiedCheck as $post) :
if (intval(strtotime($post->post_modified)) < intval($weekAgo)) unstick_post( $post->ID );
endforeach;
The code will check if the post modified date was more than one week ago and unstick the post.
Hope this helps someone :)
I was looking for a plugin that allowed only paid members to access certain WP pages and to display the content based on their day of the course (the course is 200 days long). I used PaidMembershipsPro, but I had to modify it to my needs and I post it here in case might be useful for someone else.
If someone buys a different "membership level" it extends it instead of overwriting (I had to make 3 levels for 3 payment plans, 1/3/6 months, I named them all the same but if someone buys 3 months and then another month it reset the duration, so there is a filter for it below). I asked on SO already, but I didn't get an answer, so I wrote the functions myself. It might be bit sloppy though.
the table:
tt_subs s_id(int) s_user(int) s_months(int) s_since(timestamp)
This is the function that puts the data into a table (it takes the duration as days, because all my levels were timed in days)
add_action("pmpro_after_checkout", tt_AddToSubs);
function tt_AddToSubs($user_id){
global $wpdb, $current_user;
$days = $current_user->data->membership_level->expiration_number; //get days from current order
$months = ceil($days/30);
$today = date('Y-m-d H:i:s',strtotime('today midnight'));
$result = $wpdb->get_results("SELECT s_user, s_months, s_since FROM tt_subs WHERE s_user = $user_id", ARRAY_A);
$rowCount = $wpdb->num_rows;
if($rowCount == 0)//if it's a new user
{
$wpdb->insert('tt_subs',array('s_user' => $user_id,
's_months' => $months,'s_since' => $today),
array('%s','%d','%s')
);
}
else
{
$sincedays = ($result[0]['s_months']*30); //counted without the new month
$since = strtotime("-$sincedays days", strtotime('today midnight'));
$newsince = (strtotime($result[0]['s_since']) <= $since ? $since : strtotime($result[0]['s_since'])); //if membership has passed, shift s_since so user is back in his day
$newsince = date('Y-m-d H:i:s', $newsince);
$months += $result[0]['s_months']; //add months to the existing ones
$wpdb->update('tt_subs',
array('s_months' => $months,'s_since' => $newsince),
array( 's_user' => $user_id ), //where array(
'%d', // value1
'%s' // value2
),
array( '%d' ) //where format
);
}
}
this is a filter that I found for extending the memberships instead of overwriting them
add_filter("pmpro_checkout_level", "level_extend_memberships");
function level_extend_memberships($level)
{
global $pmpro_msg, $pmpro_msgt, $current_user;
//does this level expire? are they an existing members with an expiration date?
if(!empty($level) && !empty($level->expiration_number) && pmpro_hasMembershipLevel() && !empty($current_user->membership_level->enddate))
{
//get the current enddate of their membership
$expiration_date = $current_user->membership_level->enddate;
//calculate days left
$todays_date = time();
$time_left = $expiration_date - $todays_date;
//time left?
if($time_left > 0)
{
//convert to days and add to the expiration date (assumes expiration was 1 year)
$days_left = floor($time_left/(60*60*24));
//figure out days based on period
if($level->expiration_period == "Day")
$total_days = $days_left + $level->expiration_number;
elseif($level->expiration_period == "Week")
$total_days = $days_left + $level->expiration_number * 7;
elseif($level->expiration_period == "Month")
$total_days = $days_left + $level->expiration_number * 30;
elseif($level->expiration_period == "Year")
$total_days = $days_left + $level->expiration_number * 365;
//update number and period
$level->expiration_number = $total_days;
$level->expiration_period = "Day";
}
}
return $level;
}
and finally a function that returns the day the user is on
function tt_myDay()
{
global $wpdb;
if(current_user_can('add_users'))
{
return 999;
}
else
{
$resultq = $wpdb->get_results("SELECT s_since, s_months FROM tt_subs WHERE s_user = ".get_current_user_id(), ARRAY_A);
$day = ceil((time() - strtotime($resultq[0]['s_since']))/86400);
return ($day > ($resultq[0]['s_months']*30) ? ($resultq[0]['s_months']*30) : $day );
}
}
Using Advanced Custom Fields with the add-on of Date Time Piker, I populate a calendar with the information of Year, Date, Time (am and pm).
On the calendar listing page, I have a query and, for some reason, it skips February and repeats March twice.
Here is the code:
<?php
$today = date('Ymd h:i:s a', time() - 60 * 60 * 24);
#start from current month. Change 2 to however months ahead you want
for ($x=0; $x<=6; $x++) {
$date = new DateTime("$x months");
$date->modify("-" . ($date->format('j')-1) . " days");
#echo $date->format('j, m Y');
$month = $date->format('m');
$year = $date->format('Y');
#echo 'Month= '.$month .' Year= '.$year.' <br>'; #debug
$rows = $wpdb->get_results($wpdb->prepare(
"
SELECT *
FROM wp_postmeta
WHERE meta_key LIKE %s
AND meta_value LIKE %s
ORDER BY meta_value ASC
",
'show_date_time_%_show_date', // meta_name: $ParentName_$RowNumber_$ChildName
#''.$year.''.$month.'%' // meta_value: 20131031 for example
''.$year.''.$month.'%' // meta_value: 20131031 for example
));
// loop through the results
if( $rows ) {
echo '<div class="month">';
echo '<h2>'.$date->format('F').' '.$date->format('Y').'</h2>';
echo '<ul>';
foreach( $rows as $row ) {
// for each result, find the 'repeater row number' and use it to load the sub field!
preg_match('_([0-9]+)_', $row->meta_key, $matches);
$meta_key = 'show_date_time_' . $matches[0] . '_show_date'; // $matches[0] contains the row number!
// today or later
$showDate = $row->meta_value;
$do_current = ($showDate > $today);
if ( $do_current || $continue ) :
$show_title = get_the_title( $row->post_id );
$machine_name = preg_replace('#[^a-z0-9-]+#','-', strtolower($show_title));
$post_type = get_post_type($row->post_id);
if( $post_type === 'pre-post-show' ){
// echo 'pre-post-show matching';
$postID = $row->post_id;
$posts = get_field('pre_post_related_show', $postID);
if( $posts ){
foreach( $posts as $post): // variable must be called $post (IMPORTANT)
setup_postdata($post);
$related_show = get_the_title($post->ID);
$related_show_machine = preg_replace('#[^a-z0-9-]+#','-', strtolower($related_show));
endforeach;
wp_reset_postdata(); // IMPORTANT - reset the $post object so the rest of the page works correctly
}
}// post type define
?>
Any thoughts about why this could be happening?
Well, it's a bit trickier than it seems. In this stackoverflow post you'll find a complete explanation of this "odd" behaviour. To sum up:
+1 month increases the month number (originally 1) by one. This makes the date 2015-02-31.
The second month (February) only has 28 days in 2015, so PHP auto-corrects this by just continuing to count days from February 1st. You then end up at March 3rd.
That's why you're seeing month 3 twice. How to get around this? Well, in the post I showed you there are some ways of getting around this "problem". If you have php 5.3 or higher, I'd suggest this:
$date = new DateTime();// Now.
for ($x=0; $x<=6; $x++) {
($x) ? $date->modify( 'first day of next month' ) : NULL;// It should give you next month from $x=0 onwards. Output: 01,02,03,04,05,06,07
....// Your code comes here
Hope it helps.
UPDATE
There are a lot of documentation relative to dates and PHP. The DateTime class is really handy to deal with dates. Check its modify method to change the date. Lastly, have a look at the different date and time supported formats. Especially to the relative formats if you're interested in modifying dates using strings like '+7 day'.
Lastly, have a look at the wpdb documentation. The class wpdb allows you to interact with the database in wp. You'll have to learn a bit of SQL in order to make queries. There are hundreds of pages on the internet (not to mention books) that will help you to learn.
For instance, if you want to retrieve all posts that are within the next 7 days you could do something like:
$now_date = (new DateTime())->format("Y-m-d");
$next_seven_days = (new DateTime("+7 day"))->format("Y-m-d");
$query = "SELECT * FROM wp_posts WHERE post_date >= '$now_date' AND post_date < '$next_seven_days'";
$rows = $wpdb->get_results( $query, OBJECT );
Note: since there is no input from the users/visitors nor they can't effect the query, I'm not going to use prepare for simplicity's sake. Anyway, I must say it's good practice to use it systematically.
I'm going to create a "future"-blogg (sort of a sci-fi-adventure in blog form) and want to display all dates +100 years. For instance a post published 2012-05-17 should display the date 2112-05-17.
First I thought I could just easily set the date to 2112-05-17, but it seems that wordpress can't handle dates higher than 2049.
So my next idea is to modify how the dates are displayed. I was thinking of modifying get_the_date() in general-template.php, and make it return the later date.
But here my skills are not enough. I don't know anything about how to work with date values in php.
get_the_date() looks like this:
function get_the_date( $d = '' ) {
global $post;
$the_date = '';
if ( '' == $d )
$the_date .= mysql2date(get_option('date_format'), $post->post_date);
else
$the_date .= mysql2date($d, $post->post_date);
return apply_filters('get_the_date', $the_date, $d);
}
Any ideas on how to modify it? So it adds 100 years to the date before returning it?
Any input would be appriciated :)
Looks like you might need to investigate date_modify and also strtotime
http://php.net/manual/en/datetime.modify.php
http://www.php.net/manual/en/function.strtotime.php
http://www.php.net/manual/en/datetime.add.php
Assuming your mysql dates are of the following format: YYYY-MM-DD
function add100yr( $date="2011-03-04" ) {
$timezone=date_timezone_get();
date_default_timezone_set($timezone);
list($year, $month, $day) = split(':', $date);
$timestamp=mktime(0,0,0, $month, $day, $year);
// 100 years, 365.25 days/yr, 24h/day, 60min/h, 60sec/min
$seconds = 100 * 365.25 * 24 * 60 * 60;
$newdate = date("Y-m-d", $timestamp+$seconds );
// $newdate is now formatted YYYY-mm-dd
}
Now you can:
function get_the_date( $d = '' ) {
global $post;
$the_date = '';
if ( '' == $d )
$the_date .= mysql2date(get_option('date_format'), add100yr($post->post_date));
else
$the_date .= mysql2date($d, add100yr($post->post_date));
return apply_filters('get_the_date', $the_date, $d);
}
Try a custom field: http://codex.wordpress.org/Custom_Fields
You will have to enter the +100 year date for each post, but then you're not going to be relying on php or functions to alter the current date.
WordPress provides the filter get_the_date that allows to modify the value before it is handled over to the theme or plugin.
This filter is used everytime get_the_date() is called.
add_filter( 'get_the_date', 'modify_get_the_date', 10, 3 );
function modify_get_the_date( $value, $format, $post ) {
$date = new DateTime( $post->post_date );
$date->modify( "+100 years" );
if ( $format == "" )
$format = get_option( "date_format" );
return( $date->format( $format ) );
}
This function takes the post_date from the post, adds the time and returns it according to the format given to get_the_date() or with the default format configured in the WordPress options.