'afridirect_payment', 'post_status' => 'publish', 'posts_per_page' => 1, 'fields' => 'ids', 'no_found_rows' => false, 'update_post_meta_cache' => false, 'update_post_term_cache' => false, // No non-meta way to count standalone payments by their status. // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_afridirect_status', 'value' => $status, ), ), ) ); $counts[ $status ] = (int) $query->found_posts; } return $counts; } /** * Number of WooCommerce orders in each state handled by the gateway. * * @return int[] Keys: review, pending, approved, rejected. */ public static function woo_counts() { $counts = array( 'review' => 0, 'pending' => 0, 'approved' => 0, 'rejected' => 0, ); if ( ! class_exists( 'WooCommerce' ) || ! function_exists( 'wc_orders_count' ) ) { return $counts; } $counts['review'] = (int) wc_orders_count( 'adp-proof' ); $counts['pending'] = (int) wc_orders_count( 'adp-pending' ); $counts['approved'] = self::woo_review_count( 'approved' ); $counts['rejected'] = self::woo_review_count( 'declined' ); return $counts; } /** * Count gateway orders by the review decision stored on the order. * * @param string $decision approved|declined. * @return int */ private static function woo_review_count( $decision ) { $result = wc_get_orders( array( 'limit' => 1, 'paginate' => true, 'return' => 'ids', 'payment_method' => 'afridirect_payment', // No non-meta way to find orders by their review decision. // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_afridirect_review_status', 'value' => $decision, ), ), ) ); return ( is_object( $result ) && isset( $result->total ) ) ? (int) $result->total : 0; } /** * Combined totals across standalone payments and WooCommerce orders. * * @return int[] Keys: review, pending, approved, rejected. */ public static function get_stats() { $standalone = self::standalone_counts(); $woo = self::woo_counts(); return array( 'review' => $standalone['needs_review'] + $woo['review'], 'pending' => $standalone['pending_proof'] + $woo['pending'], 'approved' => $standalone['approved'] + $woo['approved'], 'rejected' => $standalone['rejected'] + $woo['rejected'], ); } /** * Most recent payments waiting for a decision, newest first. * * @param int $limit Maximum number of items. * @return array[] */ public static function get_review_queue( $limit = 5 ) { $items = array(); $query = new WP_Query( array( 'post_type' => 'afridirect_payment', 'post_status' => 'publish', 'posts_per_page' => $limit, 'orderby' => 'date', 'order' => 'DESC', 'no_found_rows' => true, 'update_post_term_cache' => false, // No non-meta way to list standalone payments by status. // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_afridirect_status', 'value' => 'needs_review', ), ), ) ); foreach ( $query->posts as $post ) { $payment = AfriDirect_Payments::get_payment( $post->ID ); if ( ! $payment ) { continue; } $items[] = array( 'kind' => __( 'Standalone', 'afridirect-payment' ), 'title' => $payment['reference'], 'payer' => $payment['payer_name'] ? $payment['payer_name'] : $payment['payer_email'], 'method' => $payment['method_label'], 'amount_html' => esc_html( number_format_i18n( $payment['amount'], 2 ) . ' ' . strtoupper( $payment['currency'] ) ), 'time' => (int) get_post_time( 'U', true, $post ), 'url' => get_edit_post_link( $post->ID, 'raw' ), ); } if ( class_exists( 'WooCommerce' ) && function_exists( 'wc_get_orders' ) ) { $orders = wc_get_orders( array( 'status' => 'adp-proof', 'limit' => $limit, 'orderby' => 'date', 'order' => 'DESC', ) ); foreach ( $orders as $order ) { $created = $order->get_date_created(); $payer = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ); $items[] = array( 'kind' => __( 'WooCommerce', 'afridirect-payment' ), /* translators: %s: WooCommerce order number. */ 'title' => sprintf( __( 'Order #%s', 'afridirect-payment' ), $order->get_order_number() ), 'payer' => $payer ? $payer : $order->get_billing_email(), 'method' => $order->get_meta( '_afridirect_method_label' ), 'amount_html' => wc_price( $order->get_total(), array( 'currency' => $order->get_currency() ) ), 'time' => $created ? $created->getTimestamp() : 0, 'url' => AfriDirect_Payment_Admin_UI::page_url( 'afridirect-woo-payments' ), ); } } usort( $items, static function ( $a, $b ) { return $b['time'] <=> $a['time']; } ); return array_slice( $items, 0, $limit ); } /** * Published payment forms, for the shortcode helper. * * @param int $limit Maximum number of forms. * @return WP_Post[] */ public static function get_forms( $limit = 5 ) { return get_posts( array( 'post_type' => 'afridirect_form', 'post_status' => 'publish', 'numberposts' => $limit, 'orderby' => 'date', 'order' => 'DESC', 'suppress_filters' => false, ) ); } /** * Whether the WooCommerce gateway is switched on. * * @return bool */ public static function gateway_enabled() { if ( ! class_exists( 'WooCommerce' ) ) { return false; } $settings = get_option( 'woocommerce_afridirect_payment_settings', array() ); return is_array( $settings ) && isset( $settings['enabled'] ) && 'yes' === $settings['enabled']; } /** * Whether a payment form shortcode is already published on a page or post, * or a standalone payment has been received (which proves a form is live). * * @return bool */ private static function shortcode_in_use() { $counts = wp_count_posts( 'afridirect_payment' ); if ( $counts && ! empty( $counts->publish ) ) { return true; } $found = get_posts( array( 'post_type' => array( 'page', 'post' ), 'post_status' => 'publish', 's' => '[afridirect_form', 'posts_per_page' => 1, 'fields' => 'ids', 'no_found_rows' => true, ) ); return ! empty( $found ); } /** * Setup checklist, computed from the site's real configuration. * * @return array[] Each step: title, desc, done, ctas (label/url pairs). */ public static function get_setup_steps() { $has_methods = ! empty( AfriDirect_Payment_Methods::get_all() ); $form_counts = wp_count_posts( 'afridirect_form' ); $has_forms = $form_counts && ! empty( $form_counts->publish ); $woo = class_exists( 'WooCommerce' ); $is_live = self::gateway_enabled() || self::shortcode_in_use(); $live_ctas = array(); if ( $has_forms ) { $live_ctas[] = array( 'label' => __( 'Get the shortcode', 'afridirect-payment' ), 'url' => '#afd-forms', ); } if ( $woo ) { $live_ctas[] = array( 'label' => __( 'Enable at checkout', 'afridirect-payment' ), 'url' => AfriDirect_Payment_Admin_UI::page_url( 'afridirect-settings' ), ); } return array( array( 'title' => __( 'Add a payment method', 'afridirect-payment' ), 'desc' => __( 'Where customers send money: a bank account, Zelle, PayPal, crypto wallet or anything custom.', 'afridirect-payment' ), 'done' => $has_methods, 'ctas' => array( array( 'label' => __( 'Add method', 'afridirect-payment' ), 'url' => AfriDirect_Payment_Admin_UI::page_url( 'afridirect-payment-methods' ), ), ), ), array( 'title' => __( 'Create a payment form', 'afridirect-payment' ), 'desc' => __( 'Choose which methods a form offers, the amount and the time customers have to upload proof.', 'afridirect-payment' ), 'done' => $has_forms, 'ctas' => array( array( 'label' => __( 'Create form', 'afridirect-payment' ), 'url' => admin_url( 'post-new.php?post_type=afridirect_form' ), ), ), ), array( 'title' => __( 'Go live', 'afridirect-payment' ), 'desc' => $woo ? __( 'Paste the form shortcode on any page, or turn on the gateway so customers can pay this way at checkout.', 'afridirect-payment' ) : __( 'Paste the form shortcode on any page of your site.', 'afridirect-payment' ), 'done' => $is_live, 'ctas' => $live_ctas, ), ); } }