I'm building some stats for a directory website and I got stuck calculating the average age of listings assigned to a particular listing type.
I figured out calculating listing age in days by ID:
$today = date( 'Y-m-d' );
$listing_date = get_the_date( 'Y-m-d', $id );
$diff = strtotime( $today ) - strtotime( $listing_date );
$age = round( $diff / 86400 );
I figured out how to pull listings assigned to a particular listing type by term ID:
$args = array(
'posts_per_page' => -1,
'fields' => 'ids',
'post_type' => 'listing',
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'listing-type',
'field' => 'id',
'terms' => $id
)
)
);
$ids = get_posts( $args );
This gives me an array of IDs of all listings assigned to a particular listing type.
Now I need to calculate the total age in days for all those listings I retrieved IDs for.
I figured $cnt = count( $ids ); to get the total number of retrieved listings (IDs), but I can't figure out calculating the total age in days for those.
With a foreach loop :
<?php
// Your function to get the diff
function get_diff($id) {
$today = date( 'Y-m-d' );
$listing_date = get_the_date( 'Y-m-d', $id );
$diff = strtotime( $today ) - strtotime( $listing_date );
$age = round( $diff / 86400 );
return $age;
}
// We want to store all the diff
$diffs = [];
foreach($ids as $id) {
$diffs[] = get_diff($id);
}
// Get the average | We filter to remove empty values
$diffs = array_filter($diffs);
if(count($diffs)) {
echo $average = array_sum($diffs)/count($diffs);
}
Related
The code below is said to give the total spent spent over 30 days (if I'm not mistaken). But in my test, it calculates for the current month. How can I not update this code for last 6 months(180 days). The important thing is to be able to easily change the coverage day and make the calculation for the completed orders. Thanks.
Code resource:https://github.com/anaymark/woocommerce-monthly-spent-by-user/blob/master/total-spent-month-by-user.php
function total_spent_for_user_30days( $user_id=null ) {
if ( empty($user_id) ){
$user_id = get_current_user_id();
}
$today_year = date( 'Y' );
$today_month = date( 'm' );
$day = date( 'd' );
if ($today_month == '01') {
$month = '12';
$year = $today_year - 1;
} else{
$month = $today_month - 1;
$month = sprintf("%02d", $month);
$year = $today_year - 1;
}
// ORDERS FOR LAST 30 DAYS (Time calculations)
$now = strtotime('now');
$gap_days = 30;
$gap_days_in_seconds = 60*60*24*$gap_days;
$gap_time = $now - $gap_days_in_seconds;
$args = array(
'post_type' => 'shop_order',
'post_status' => array( 'wc-completed' ),
// all posts
'numberposts' => -1,
// for current user id
'meta_key' => '_customer_user',
'meta_value' => $user_id,
'date_query' => array(
//orders published on last 30 days
'relation' => 'OR',
array(
'year' => $today_year,
'month' => $today_month,
),
array(
'year' => $year,
'month' => $month,
),
),
);
// GET ALL ORDERS
$customer_orders = get_posts( $args );
$count = 0;
$total = 0;
$no_orders_message = __('No orders this month.', 'mytheme');
if (!empty($customer_orders)) {
$customer_orders_date = array();
foreach ( $customer_orders as $customer_order ){
$customer_order_date = strtotime($customer_order->post_date);
// PAST 30 DAYS
if ( $customer_order_date > $gap_time ) {
$customer_order_date;
$order = new WC_Order( $customer_order->ID );
$order_items = $order->get_items();
$total += $order->get_total();
// Going through each current customer items in the order
foreach ( $order_items as $order_item ){
$count++;
}
}
}
$monthly_spent_by_user = floatval( preg_replace( '#[^\d.]#', '', $total, $count ) );
return $monthly_spent_by_user;
} else {
return $no_orders_message;
}
}
add_shortcode( 'spent-last-month', 'total_spent_for_user_30days' );
I have a meta_key called delivered_date, in date format, example 2021-05-13 16:01:26.
If I MUST use wc_get_orders( $args ), how can I get all orders within a date range?
Tried using the meta_compare argument but it returns nothing:
// The 2 variables below will come from a datepicker widget
$start_date = "2021-05-10 0:00:00";
$end_date = "2021-05-30 11:59:59";
$args = array(
'type' => 'shop_order',
'limit' => 100,
'paginate' => true,
'page' => 1,
'orderby' => 'id',
'order' => 'DESC',
'meta_key' => 'delivered_date',
'meta_value' => array($start_date, $end_date),
'meta_compare' => 'BETWEEN',
);
$result = wc_get_orders( $args );
You are close, use date — Format a local time/date
So you get:
// The 2 variables below will come from a datepicker widget
$start_date = date( '2021-05-10 00:00:00' );
$end_date = date( '2021-05-30 11:59:59' );
$args = array(
'orderby' => 'id',
'order' => 'DESC',
'meta_key' => 'delivered_date',
'meta_value' => array( $start_date, $end_date ),
'meta_compare' => 'BETWEEN',
);
$orders = wc_get_orders( $args );
// NOT empty
if ( ! empty ( $orders ) ) {
foreach ( $orders as $order ) {
echo '<p>ID = ' . $order->get_id() . '</p>';
}
}
Result: ID = 2525, ID = 2524, ID = 2523
I'm using ACF pro and need to query posts that have some special ACF fields certain value.
But also I need to get posts that have ANY year, but the date should be between today and + 30 days from today. I cannot use static month number because then if post is made in day 1 it would not find it enough in advance.
Here is my initial query that is not working. It works if only get certain year and month, but that only gets posts from that date.
//$date_month_advance_month = ... month number of today + 30 days
//$date_month_advance_day= ... day number of today + 30 days
// args
$args = array(
'post_type' => 'my_post_type',
'posts_per_page'=> -1,
'meta_key' => 'status',
'meta_value' => 'accepted',
'date_query' => array(
'compare' => 'BETWEEN',
array(
'month' => $date_today_month,
'day' => $date_today_day,
),
array(
'month' => $date_month_advance_month,
'day' => $date_month_advance_day,
),
),
);
You could create a custom query. I made one quickly, tested for the date but not the custom field status as i don't have it. Replace my_post_type with your post type name.
global $wpdb;
$query = "
SELECT * FROM {$wpdb->posts} as p
LEFT JOIN {$wpdb->postmeta} as pm
ON pm.post_id = p.ID
WHERE p.post_type = 'my_post_type'
AND pm.meta_key = 'status'
AND pm.meta_value = 'accepted'
AND REPLACE(SUBSTRING(p.post_date, 6, 10), '-', '') BETWEEN %s AND %s
GROUP BY p.ID
";
// Should replace 0301 and 0331 by variables (date('mO1') and date('m31') for example), I let you handle this.
$prepared_query = $wpdb->prepare($query, array('0301', '0331'));
$result = $wpdb->get_results($prepared_query);
foreach($result as $r) {
$cs_post = get_post($r->ID);
echo '<p>';
echo get_the_title($cs_post->ID) .'<br>';
echo get_the_date('Y-m-d', $cs_post->ID) .'<br>';
echo '</p>';
}
Not sure if it's the proper way but it works.
I am using repeatable meta boxes what i want to achieve is display number of post which have particular meta key such as
Country Pakistan
City Islamabad
Age 12
Age 12
Meta key "Age" is used in 2 posts.
No i want structure like Age in Post 2 , Islamabad in Post 1 , Pakistan in Post 1.
/**
* Display callback for the submenu page.
*/
function iif_register_submenu_form_details_callback() {
$id = get_current_user_id();
$loop = new WP_Query( array(
'post_type' => 'iff-info-forms',
'post_status' => 'publish',
'author' => $id,
'meta_query' => array(
array(
'key' => 'repeatable_fields',
//'value' => $user_data_new,
'compare' => 'LIKE'
))
) );
//print_r($loop);
while ( $loop->have_posts() ) : $loop->the_post();
$info = get_post_meta(get_the_id(), 'repeatable_fields', true);
if ( $info ) {
// echo '<strong>Emergency Contacts:</strong><br />';
foreach ( $info as $emergency_contact_metas ) {
echo '<strong>' . esc_html( $emergency_contact_metas['iif_label'] ) .'</strong> ' . esc_html( $emergency_contact_metas['iif_details'] ) . '<br />';
}
}
endwhile;
}
OUTPUT SHOWING IS Below
Country Pakistan
City Islamabad
Age 12
Age 12
I want to find the time from order processing to order marked as complete for every order. How can I get that? I have read this and it only gives time for last modified.
This will get all the orders and return the number of seconds between the order being placed and if it is currently at a completed status. You haven't specified a format for the time difference so I have just returned it as a string with the corresponding order id.
$query = new WC_Order_Query( array(
'limit' => -1,
'orderby' => 'date',
'order' => 'DESC',
'return' => 'ids',
) );
foreach( $query->get_orders() as $order_id ) {
$order = wc_get_order($order_id);
if( $order->get_status() === 'completed') {
$order_data = $order->get_data();
$timestamp = $order_data['date_modified']->getTimestamp() - $order_data['date_created']->getTimestamp();
$d1 = new DateTime();
$d2 = new DateTime();
$d2->add(new DateInterval('PT'.$timestamp.'S'));
$order_interval = $d2->diff($d1);
echo 'Order ID : ' . $order->get_id() . ' ' . $order_interval->format('%a days, %h hours, %i minutes and %s seconds');
}
}
have you tried this?
$order_id = 1945;
$order = new WC_Order($order_id);
$order_data = $order->get_data();
$date1 = $order_data['date_created']->date( 'Y-m-d G:i:s' );
$date2 = $order_data['date_modified']->date( 'Y-m-d G:i:s' );
$diff = abs(strtotime($date2) - strtotime($date1));
$years = floor($diff / (365*60*60*24));
$months = floor(($diff - $years * 365*60*60*24) / (30*60*60*24));
$days = floor(($diff - $years * 365*60*60*24 - $months*30*60*60*24)/ (60*60*24));
printf("%d years, %d months, %d days\n", $years, $months, $days);
You can improved this by adding a check for the status of the order.