plugin = $plugin; } /** Whether WooCommerce Analytics has the tables we need. */ public function is_available() { if ( ! class_exists( 'WooCommerce' ) ) { return false; } global $wpdb; $table = $wpdb->prefix . 'wc_order_product_lookup'; // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB $found = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ); return $found === $table; } /** * Aggregate and send. Returns false when there is nothing to say, which * includes the case where Analytics is off. */ public function report_back() { $settings = $this->plugin->settings(); if ( ! $settings->is_traffic_report() ) { return false; } $store_id = $settings->get_store_id(); if ( ! $store_id || ! $this->is_available() ) { return false; } global $wpdb; $lookup = $wpdb->prefix . 'wc_order_product_lookup'; $stats = $wpdb->prefix . 'wc_order_stats'; $since = gmdate( 'Y-m-d 00:00:00', strtotime( '-' . self::REPORT_DAYS . ' days' ) ); // Joined to wc_order_stats for the status filter: the lookup table holds // rows for every status, so counting it alone would report cancelled and // failed orders as revenue. // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB $rows = $wpdb->get_results( $wpdb->prepare( "SELECT DATE(l.date_created) AS day, l.product_id AS product_id, SUM(l.product_qty) AS units, SUM(l.product_net_revenue) AS net, COUNT(DISTINCT l.order_id) AS orders FROM {$lookup} l INNER JOIN {$stats} s ON s.order_id = l.order_id WHERE l.date_created >= %s AND s.status IN ('wc-completed','wc-processing','wc-on-hold') GROUP BY day, l.product_id ORDER BY day ASC, net DESC LIMIT %d", $since, self::MAX_PRODUCTS * self::REPORT_DAYS ) ); if ( empty( $rows ) ) { return false; } $days = array(); foreach ( $rows as $row ) { $day = (string) $row->day; if ( ! isset( $days[ $day ] ) ) { $days[ $day ] = array(); } if ( count( $days[ $day ] ) >= self::MAX_PRODUCTS ) { continue; } $days[ $day ][] = array( 'productId' => (int) $row->product_id, 'units' => (int) $row->units, // Minor units, so the server never has to guess decimal places. 'revenueMinor' => (int) round( (float) $row->net * 100 ), 'orders' => (int) $row->orders, ); } $payload = array(); foreach ( $days as $day => $products ) { $payload[] = array( 'date' => $day, 'products' => $products, ); } $result = $this->plugin->api()->sales_ingest( $store_id, $payload ); return ! is_wp_error( $result ); } }