Add HPOS compat queries for tracker. (#38293)
This commit is contained in:
commit
b04376b501
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Add HPOS compat queries for tracker.
|
|
@ -11,15 +11,19 @@
|
|||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
|
||||
use Automattic\WooCommerce\Internal\Utilities\BlocksUtil;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
// phpcs:disable Squiz.Classes.ClassFileName.NoMatch, Squiz.Classes.ValidClassName.NotCamelCaps -- Backwards compatibility.
|
||||
/**
|
||||
* WooCommerce Tracker Class
|
||||
*/
|
||||
class WC_Tracker {
|
||||
|
||||
// phpcs:enable
|
||||
/**
|
||||
* URL to the WooThemes Tracker API endpoint.
|
||||
*
|
||||
|
@ -30,7 +34,7 @@ class WC_Tracker {
|
|||
/**
|
||||
* Hook into cron event.
|
||||
*/
|
||||
public static function init() {
|
||||
public static function init() { // phpcs:ignore WooCommerce.Functions.InternalInjectionMethod.MissingFinal, WooCommerce.Functions.InternalInjectionMethod.MissingInternalTag -- Not an injection.
|
||||
add_action( 'woocommerce_tracker_send_event', array( __CLASS__, 'send_tracking_data' ) );
|
||||
}
|
||||
|
||||
|
@ -45,10 +49,15 @@ class WC_Tracker {
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter whether to send tracking data or not.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
if ( ! apply_filters( 'woocommerce_tracker_send_override', $override ) ) {
|
||||
// Send a maximum of once per week by default.
|
||||
$last_send = self::get_last_send_time();
|
||||
if ( $last_send && $last_send > apply_filters( 'woocommerce_tracker_last_send_interval', strtotime( '-1 week' ) ) ) {
|
||||
if ( $last_send && $last_send > apply_filters( 'woocommerce_tracker_last_send_interval', strtotime( '-1 week' ) ) ) { // phpcs:ignore
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
|
@ -84,6 +93,11 @@ class WC_Tracker {
|
|||
* @return int|bool
|
||||
*/
|
||||
private static function get_last_send_time() {
|
||||
/**
|
||||
* Filter the last time tracking data was sent.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_tracker_last_send_time', get_option( 'woocommerce_tracker_last_send', false ) );
|
||||
}
|
||||
|
||||
|
@ -118,7 +132,12 @@ class WC_Tracker {
|
|||
$data = array();
|
||||
|
||||
// General site info.
|
||||
$data['url'] = home_url();
|
||||
$data['url'] = home_url();
|
||||
/**
|
||||
* Filter the admin email that's sent with data.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
$data['email'] = apply_filters( 'woocommerce_tracker_admin_email', get_option( 'admin_email' ) );
|
||||
$data['theme'] = self::get_theme_info();
|
||||
|
||||
|
@ -172,12 +191,21 @@ class WC_Tracker {
|
|||
$data['mini_cart_block'] = self::get_mini_cart_info();
|
||||
}
|
||||
|
||||
// WooCommerce Admin info.
|
||||
/**
|
||||
* Filter whether to disable admin tracking.
|
||||
*
|
||||
* @since 5.2.0
|
||||
*/
|
||||
$data['wc_admin_disabled'] = apply_filters( 'woocommerce_admin_disabled', false ) ? 'yes' : 'no';
|
||||
|
||||
// Mobile info.
|
||||
$data['wc_mobile_usage'] = self::get_woocommerce_mobile_usage();
|
||||
|
||||
/**
|
||||
* Filter the data that's sent with the tracker.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_tracker_data', $data );
|
||||
}
|
||||
|
||||
|
@ -212,6 +240,7 @@ class WC_Tracker {
|
|||
$memory = wc_let_to_num( WP_MEMORY_LIMIT );
|
||||
|
||||
if ( function_exists( 'memory_get_usage' ) ) {
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- False positive.
|
||||
$system_memory = wc_let_to_num( @ini_get( 'memory_limit' ) );
|
||||
$memory = max( $memory, $system_memory );
|
||||
}
|
||||
|
@ -287,20 +316,20 @@ class WC_Tracker {
|
|||
foreach ( $plugins as $k => $v ) {
|
||||
// Take care of formatting the data how we want it.
|
||||
$formatted = array();
|
||||
$formatted['name'] = strip_tags( $v['Name'] );
|
||||
$formatted['name'] = wp_strip_all_tags( $v['Name'] );
|
||||
if ( isset( $v['Version'] ) ) {
|
||||
$formatted['version'] = strip_tags( $v['Version'] );
|
||||
$formatted['version'] = wp_strip_all_tags( $v['Version'] );
|
||||
}
|
||||
if ( isset( $v['Author'] ) ) {
|
||||
$formatted['author'] = strip_tags( $v['Author'] );
|
||||
$formatted['author'] = wp_strip_all_tags( $v['Author'] );
|
||||
}
|
||||
if ( isset( $v['Network'] ) ) {
|
||||
$formatted['network'] = strip_tags( $v['Network'] );
|
||||
$formatted['network'] = wp_strip_all_tags( $v['Network'] );
|
||||
}
|
||||
if ( isset( $v['PluginURI'] ) ) {
|
||||
$formatted['plugin_uri'] = strip_tags( $v['PluginURI'] );
|
||||
$formatted['plugin_uri'] = wp_strip_all_tags( $v['PluginURI'] );
|
||||
}
|
||||
if ( in_array( $k, $active_plugins_keys ) ) {
|
||||
if ( in_array( $k, $active_plugins_keys, true ) ) {
|
||||
// Remove active plugins from list so we can show active and inactive separately.
|
||||
unset( $plugins[ $k ] );
|
||||
$active_plugins[ $k ] = $formatted;
|
||||
|
@ -381,10 +410,9 @@ class WC_Tracker {
|
|||
* @return array
|
||||
*/
|
||||
private static function get_order_counts() {
|
||||
$order_count = array();
|
||||
$order_count_data = wp_count_posts( 'shop_order' );
|
||||
$order_count = array();
|
||||
foreach ( wc_get_order_statuses() as $status_slug => $status_name ) {
|
||||
$order_count[ $status_slug ] = $order_count_data->{ $status_slug };
|
||||
$order_count[ $status_slug ] = wc_orders_count( $status_slug );
|
||||
}
|
||||
return $order_count;
|
||||
}
|
||||
|
@ -413,33 +441,59 @@ class WC_Tracker {
|
|||
private static function get_order_totals() {
|
||||
global $wpdb;
|
||||
|
||||
$gross_total = $wpdb->get_var(
|
||||
$orders_table = OrdersTableDataStore::get_orders_table_name();
|
||||
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$gross_total = $wpdb->get_var(
|
||||
"
|
||||
SELECT SUM(total_amount) AS 'gross_total'
|
||||
FROM $orders_table
|
||||
WHERE status in ('wc-completed', 'wc-refunded');
|
||||
"
|
||||
SELECT
|
||||
SUM( order_meta.meta_value ) AS 'gross_total'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
|
||||
WHERE order_meta.meta_key = '_order_total'
|
||||
AND orders.post_status in ( 'wc-completed', 'wc-refunded' )
|
||||
GROUP BY order_meta.meta_key
|
||||
"
|
||||
);
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$gross_total = $wpdb->get_var(
|
||||
"
|
||||
SELECT
|
||||
SUM( order_meta.meta_value ) AS 'gross_total'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
|
||||
WHERE order_meta.meta_key = '_order_total'
|
||||
AND orders.post_status in ( 'wc-completed', 'wc-refunded' )
|
||||
GROUP BY order_meta.meta_key
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_null( $gross_total ) ) {
|
||||
$gross_total = 0;
|
||||
}
|
||||
|
||||
$processing_gross_total = $wpdb->get_var(
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$processing_gross_total = $wpdb->get_var(
|
||||
"
|
||||
SELECT SUM(total_amount) AS 'gross_total'
|
||||
FROM $orders_table
|
||||
WHERE status = 'wc-processing';
|
||||
"
|
||||
SELECT
|
||||
SUM( order_meta.meta_value ) AS 'gross_total'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
|
||||
WHERE order_meta.meta_key = '_order_total'
|
||||
AND orders.post_status = 'wc-processing'
|
||||
GROUP BY order_meta.meta_key
|
||||
"
|
||||
);
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$processing_gross_total = $wpdb->get_var(
|
||||
"
|
||||
SELECT
|
||||
SUM( order_meta.meta_value ) AS 'gross_total'
|
||||
FROM {$wpdb->prefix}posts AS orders
|
||||
LEFT JOIN {$wpdb->prefix}postmeta AS order_meta ON order_meta.post_id = orders.ID
|
||||
WHERE order_meta.meta_key = '_order_total'
|
||||
AND orders.post_status = 'wc-processing'
|
||||
GROUP BY order_meta.meta_key
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_null( $processing_gross_total ) ) {
|
||||
$processing_gross_total = 0;
|
||||
|
@ -459,16 +513,31 @@ class WC_Tracker {
|
|||
private static function get_order_dates() {
|
||||
global $wpdb;
|
||||
|
||||
$min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( post_date_gmt ) as 'first', MAX( post_date_gmt ) as 'last'
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE post_type = 'shop_order'
|
||||
AND post_status = 'wc-completed'
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
$orders_table = OrdersTableDataStore::get_orders_table_name();
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( date_created_gmt ) as 'first', MAX( date_created_gmt ) as 'last'
|
||||
FROM $orders_table
|
||||
WHERE status = 'wc-completed';
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( post_date_gmt ) as 'first', MAX( post_date_gmt ) as 'last'
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE post_type = 'shop_order'
|
||||
AND post_status = 'wc-completed'
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_null( $min_max ) ) {
|
||||
$min_max = array(
|
||||
|
@ -477,16 +546,30 @@ class WC_Tracker {
|
|||
);
|
||||
}
|
||||
|
||||
$processing_min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( post_date_gmt ) as 'processing_first', MAX( post_date_gmt ) as 'processing_last'
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE post_type = 'shop_order'
|
||||
AND post_status = 'wc-processing'
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$processing_min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( date_created_gmt ) as 'processing_first', MAX( date_created_gmt ) as 'processing_last'
|
||||
FROM $orders_table
|
||||
WHERE status = 'wc-processing';
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$processing_min_max = $wpdb->get_row(
|
||||
"
|
||||
SELECT
|
||||
MIN( post_date_gmt ) as 'processing_first', MAX( post_date_gmt ) as 'processing_last'
|
||||
FROM {$wpdb->prefix}posts
|
||||
WHERE post_type = 'shop_order'
|
||||
AND post_status = 'wc-processing'
|
||||
",
|
||||
ARRAY_A
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_null( $processing_min_max ) ) {
|
||||
$processing_min_max = array(
|
||||
|
@ -569,28 +652,42 @@ class WC_Tracker {
|
|||
private static function get_orders_by_gateway() {
|
||||
global $wpdb;
|
||||
|
||||
$orders_and_gateway_details = $wpdb->get_results(
|
||||
"
|
||||
SELECT
|
||||
gateway, currency, SUM(total) AS totals, COUNT(order_id) AS counts
|
||||
FROM (
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
$orders_table = OrdersTableDataStore::get_orders_table_name();
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$orders_and_gateway_details = $wpdb->get_results(
|
||||
"
|
||||
SELECT payment_method AS gateway, currency AS currency, SUM( total_amount ) AS totals, count( id ) AS counts
|
||||
FROM $orders_table
|
||||
WHERE status IN ( 'wc-completed', 'wc-processing', 'wc-refunded' )
|
||||
GROUP BY gateway, currency;
|
||||
"
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$orders_and_gateway_details = $wpdb->get_results(
|
||||
"
|
||||
SELECT
|
||||
orders.id AS order_id,
|
||||
MAX(CASE WHEN meta_key = '_payment_method' THEN meta_value END) gateway,
|
||||
MAX(CASE WHEN meta_key = '_order_total' THEN meta_value END) total,
|
||||
MAX(CASE WHEN meta_key = '_order_currency' THEN meta_value END) currency
|
||||
FROM
|
||||
{$wpdb->prefix}posts orders
|
||||
LEFT JOIN
|
||||
{$wpdb->prefix}postmeta order_meta ON order_meta.post_id = orders.id
|
||||
WHERE orders.post_type = 'shop_order'
|
||||
AND orders.post_status in ( 'wc-completed', 'wc-processing', 'wc-refunded' )
|
||||
AND meta_key in( '_payment_method','_order_total','_order_currency')
|
||||
GROUP BY orders.id
|
||||
) order_gateways
|
||||
GROUP BY gateway, currency
|
||||
"
|
||||
);
|
||||
gateway, currency, SUM(total) AS totals, COUNT(order_id) AS counts
|
||||
FROM (
|
||||
SELECT
|
||||
orders.id AS order_id,
|
||||
MAX(CASE WHEN meta_key = '_payment_method' THEN meta_value END) gateway,
|
||||
MAX(CASE WHEN meta_key = '_order_total' THEN meta_value END) total,
|
||||
MAX(CASE WHEN meta_key = '_order_currency' THEN meta_value END) currency
|
||||
FROM
|
||||
{$wpdb->prefix}posts orders
|
||||
LEFT JOIN
|
||||
{$wpdb->prefix}postmeta order_meta ON order_meta.post_id = orders.id
|
||||
WHERE orders.post_type = 'shop_order'
|
||||
AND orders.post_status in ( 'wc-completed', 'wc-processing', 'wc-refunded' )
|
||||
AND meta_key in( '_payment_method','_order_total','_order_currency')
|
||||
GROUP BY orders.id
|
||||
) order_gateways
|
||||
GROUP BY gateway, currency
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
$orders_by_gateway_currency = array();
|
||||
|
||||
|
@ -656,20 +753,33 @@ class WC_Tracker {
|
|||
private static function get_orders_origins() {
|
||||
global $wpdb;
|
||||
|
||||
$orders_origin = $wpdb->get_results(
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
$op_table_name = OrdersTableDataStore::get_operational_data_table_name();
|
||||
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
$orders_origin = $wpdb->get_results(
|
||||
"
|
||||
SELECT created_via as origin, COUNT( order_id ) as count
|
||||
FROM $op_table_name
|
||||
GROUP BY created_via;
|
||||
"
|
||||
);
|
||||
// phpcs:enable
|
||||
} else {
|
||||
$orders_origin = $wpdb->get_results(
|
||||
"
|
||||
SELECT
|
||||
meta_value as origin, COUNT( DISTINCT ( orders.id ) ) as count
|
||||
FROM
|
||||
$wpdb->posts orders
|
||||
LEFT JOIN
|
||||
$wpdb->postmeta order_meta ON order_meta.post_id = orders.id
|
||||
WHERE
|
||||
meta_key = '_created_via'
|
||||
GROUP BY
|
||||
meta_value;
|
||||
"
|
||||
SELECT
|
||||
meta_value as origin, COUNT( DISTINCT ( orders.id ) ) as count
|
||||
FROM
|
||||
$wpdb->posts orders
|
||||
LEFT JOIN
|
||||
$wpdb->postmeta order_meta ON order_meta.post_id = orders.id
|
||||
WHERE
|
||||
meta_key = '_created_via'
|
||||
GROUP BY
|
||||
meta_value;
|
||||
"
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
// The associative array that is created as the result of array_reduce is passed to extract_group_key()
|
||||
// This function has the logic that will remove specific identifiers that may sometimes be part of an origin.
|
||||
|
@ -836,7 +946,12 @@ class WC_Tracker {
|
|||
* @return array
|
||||
*/
|
||||
private static function get_all_template_overrides() {
|
||||
$override_data = array();
|
||||
$override_data = array();
|
||||
/**
|
||||
* Filter the paths to scan for template overrides.
|
||||
*
|
||||
* @since 2.3.0
|
||||
*/
|
||||
$template_paths = apply_filters( 'woocommerce_template_overrides_scan_paths', array( 'WooCommerce' => WC()->plugin_path() . '/templates/' ) );
|
||||
$scanned_files = array();
|
||||
|
||||
|
|
|
@ -5,10 +5,13 @@
|
|||
* @package WooCommerce\Tests\WC_Tracker.
|
||||
*/
|
||||
|
||||
// phpcs:disable Squiz.Classes.ClassFileName.NoMatch, Squiz.Classes.ValidClassName.NotCamelCaps -- Backward compatibility.
|
||||
/**
|
||||
* Class WC_Tracker_Test
|
||||
*/
|
||||
class WC_Tracker_Test extends \WC_Unit_Test_Case {
|
||||
// phpcs:enable
|
||||
|
||||
/**
|
||||
* Test the tracking of wc_admin being disabled via filter.
|
||||
*/
|
||||
|
@ -64,4 +67,55 @@ class WC_Tracker_Test extends \WC_Unit_Test_Case {
|
|||
$this->assertArrayHasKey( 'wc_admin_disabled', $tracking_data );
|
||||
$this->assertEquals( 'no', $tracking_data['wc_admin_disabled'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @testDox Test orders tracking data.
|
||||
*/
|
||||
public function test_get_tracking_data_orders() {
|
||||
$dummy_product = WC_Helper_Product::create_simple_product();
|
||||
$status_entries = array( 'wc-processing', 'wc-completed', 'wc-refunded', 'wc-pending' );
|
||||
$created_via_entries = array( 'api', 'checkout', 'admin' );
|
||||
$payment_method_entries = array( 'paypal', 'stripe', 'cod' );
|
||||
|
||||
$order_count = count( $status_entries ) * count( $created_via_entries ) * count( $payment_method_entries );
|
||||
|
||||
foreach ( $status_entries as $status_entry ) {
|
||||
foreach ( $created_via_entries as $created_via_entry ) {
|
||||
foreach ( $payment_method_entries as $payment_method_entry ) {
|
||||
$order = wc_create_order(
|
||||
array(
|
||||
'status' => $status_entry,
|
||||
'created_via' => $created_via_entry,
|
||||
'payment_method' => $payment_method_entry,
|
||||
)
|
||||
);
|
||||
$order->add_product( $dummy_product );
|
||||
$order->save();
|
||||
$order->calculate_totals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$order_data = WC_Tracker::get_tracking_data()['orders'];
|
||||
|
||||
foreach ( $status_entries as $status_entry ) {
|
||||
$this->assertEquals( $order_count / count( $status_entries ), $order_data[ $status_entry ] );
|
||||
}
|
||||
|
||||
// Gross revenue is for wc-completed and wc-refunded status, so we calculate expected revenue per status, multiply by 2, and then multiply by 10 to account for the 10 USD per status.
|
||||
$this->assertEquals( ( $order_count / count( $status_entries ) ) * 2 * 10, $order_data['gross'] );
|
||||
|
||||
// Gross revenue is for wc-pending status, so we calculate expected revenue per status, multiply by 1, and then multiply by 10 to account for the 10 USD per status.
|
||||
$this->assertEquals( ( $order_count / count( $status_entries ) ) * 1 * 10, $order_data['processing_gross'] );
|
||||
|
||||
// Order count per gateway is calculated for three status (completed, processing and refunded) so we multiply order count by 3 and then divide by the number of status entries.
|
||||
$this->assertEquals( ( $order_count * 3 / count( $status_entries ) ), $order_data['gateway__USD_count'] );
|
||||
|
||||
// Order revenue per gateway is calculated for three status (completed, processing and refunded) so we multiply order count by 3, then by 10 to account for 10 USD per order and then divide by the number of status entries.
|
||||
$this->assertEquals( ( $order_count * 3 * 10 / count( $status_entries ) ), $order_data['gateway__USD_total'] );
|
||||
|
||||
foreach ( $created_via_entries as $created_via_entry ) {
|
||||
$this->assertEquals( ( $order_count / count( $created_via_entries ) ), $order_data['created_via'][ $created_via_entry ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue