array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 100, ), 'inactive_since' => Schema::date(), ), array( 'min_orders', 'inactive_since' ) ); } /** * Runs the data function. * * @param array $args Validated arguments. * @return array * @throws \InvalidArgumentException When arguments are invalid. */ public function run( array $args ): array { $since = DateTimeImmutable::createFromFormat( '!Y-m-d', (string) $args['inactive_since'], wp_timezone() ); if ( ! $since || $since->format( 'Y-m-d' ) !== $args['inactive_since'] ) { throw new InvalidArgumentException( 'inactive_since must be a real date in YYYY-MM-DD format.' ); } $min_orders = (int) $args['min_orders']; // Analytics' orders_count_min is exclusive ("more than"), and last_order_before // is inclusive, so ask for more than (min - 1) orders and a last order no later // than the second before inactive_since. $more_than = max( 0, $min_orders - 1 ); $lapsed = self::stats( array( 'match' => 'all', 'orders_count_min' => $more_than, 'last_order_before' => $since->modify( '-1 second' )->format( 'Y-m-d\TH:i:s' ), ) ); $repeat = self::stats( array( 'orders_count_min' => $more_than, ) ); return array( 'min_orders' => $min_orders, 'inactive_since' => $since->format( 'Y-m-d' ), 'lapsed' => $lapsed, 'all_with_min_orders' => $repeat, 'lapsed_share_pct' => $repeat['customers'] > 0 ? round( $lapsed['customers'] / $repeat['customers'] * 100, 1 ) : null, 'rows_read' => $repeat['customers'], 'notes' => array( 'Counts and averages only. Askshelf never returns customer names or contact details.' ), ); } /** * Customer stats for a filter. * * @param array $filter Analytics customer filters. * @return array{customers: int, avg_orders: float, avg_total_spend: float, avg_order_value: float} */ private static function stats( array $filter ): array { $response = Analytics::get( '/reports/customers/stats', $filter ); $totals = is_array( $response['data'] ) && is_array( $response['data']['totals'] ?? null ) ? $response['data']['totals'] : array(); return array( 'customers' => (int) ( $totals['customers_count'] ?? 0 ), 'avg_orders' => round( (float) ( $totals['avg_orders_count'] ?? 0 ), 2 ), 'avg_total_spend' => Analytics::money( $totals['avg_total_spend'] ?? 0 ), 'avg_order_value' => Analytics::money( $totals['avg_avg_order_value'] ?? 0 ), ); } }