Skip to content

Commit

Permalink
Display "Origin" column in Orders table in Orders Analytics (#46424)
Browse files Browse the repository at this point in the history
* Display channel column in Orders Analytics UI.

* Set $data to false to not use cache.

For development purpose.

* Get channel info from order meta and put into extended_info.

* Set channel in order item level.

* Replace channel with get_origin_label in extended_info.

* Remove unnneeded channel in orders_data.

* Display origin instead of channel in table.

* Fix lint errors.

* Query order meta table based on HPOS.

* Remove code for development purpose.

* Add changelog.

* Fix code comment.

* Guard against null values.

`_wc_order_attribution_utm_source` can be null when the order is created via web admin.

* Set default origin label to "Unknown".

This default is the same as found in `output_origin_column` function in plugins/woocommerce/src/Internal/Orders/OrderAttributionController.php.

* Support server side report download.

This is needed when there are more than 25 records in the Orders Analytics report.

* Fix failed test.

* Fix lint error.

* Simplify code.

We loop through $orders_data instead of $order_attributions data. This is because $order_attributions may not have attributions data for some orders.

By looping through $orders_data, it would automatically cater for "Unknown" data from get_origin_label function call, and we don't need to specify "Unknown" as default value for origin.

* Change "channel" to "attribution" object in controller.

This is because we need more than one piece of information, so we need it to be an object with properties like `origin`, `device` etc.

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>

* Change `origin` string to `attribution` array in Orders DataStore.

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>

* Change origin string to attribution object.

* Fix indexing after changing from origin string to attribution object.

* Change from origin string to attribution object in table.js.

* Simplify code.

To make code shorter and easier to read, instead of long horizontal code.

* Fix lint errors.

* Fix failed test.

* Fix lint error.

* Fix retrieving origin in CSV export.

* Use $wpdb->postmeta; cosmetic change.

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>

* Cosmetic change.

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>

* Sanitize order IDs by using absint.

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>

---------

Co-authored-by: Kader Ibrahim S <kader.ibrahim.s@a8c.com>
  • Loading branch information
2 people authored and nielslange committed Apr 20, 2024
1 parent 854cd48 commit 25be119
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 18 deletions.
11 changes: 11 additions & 0 deletions plugins/woocommerce-admin/client/analytics/report/orders/table.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ class OrdersReportTable extends Component {
isSortable: true,
isNumeric: true,
},
{
label: __( 'Origin', 'woocommerce' ),
screenReaderLabel: __( 'Origin', 'woocommerce' ),
key: 'origin',
required: false,
isSortable: false,
},
];
}

Expand Down Expand Up @@ -241,6 +248,10 @@ class OrdersReportTable extends Component {
display: renderCurrency( netTotal, currency ),
value: netTotal,
},
{
display: extendedInfo.attribution.origin,
value: extendedInfo.attribution.origin,
},
];
} );
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: add

Add origin column in Orders Analytics report.
14 changes: 11 additions & 3 deletions plugins/woocommerce/src/Admin/API/Reports/Orders/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -211,24 +211,30 @@ public function get_item_schema() {
'readonly' => true,
),
'extended_info' => array(
'products' => array(
'products' => array(
'type' => 'array',
'readonly' => true,
'context' => array( 'view', 'edit' ),
'description' => __( 'List of order product IDs, names, quantities.', 'woocommerce' ),
),
'coupons' => array(
'coupons' => array(
'type' => 'array',
'readonly' => true,
'context' => array( 'view', 'edit' ),
'description' => __( 'List of order coupons.', 'woocommerce' ),
),
'customer' => array(
'customer' => array(
'type' => 'object',
'readonly' => true,
'context' => array( 'view', 'edit' ),
'description' => __( 'Order customer information.', 'woocommerce' ),
),
'attribution' => array(
'type' => 'object',
'readonly' => true,
'context' => array( 'view', 'edit' ),
'description' => __( 'Order attribution information.', 'woocommerce' ),
),
),
),
);
Expand Down Expand Up @@ -526,6 +532,7 @@ public function get_export_columns() {
'num_items_sold' => __( 'Items sold', 'woocommerce' ),
'coupons' => __( 'Coupon(s)', 'woocommerce' ),
'net_total' => __( 'N. Revenue', 'woocommerce' ),
'origin' => __( 'Origin', 'woocommerce' ),
);

/**
Expand Down Expand Up @@ -558,6 +565,7 @@ public function prepare_item_for_export( $item ) {
'num_items_sold' => $item['num_items_sold'],
'coupons' => isset( $item['extended_info']['coupons'] ) ? $this->get_coupons( $item['extended_info']['coupons'] ) : null,
'net_total' => $item['net_total'],
'origin' => $item['extended_info']['attribution']['origin'],
);

/**
Expand Down
82 changes: 70 additions & 12 deletions plugins/woocommerce/src/Admin/API/Reports/Orders/DataStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

defined( 'ABSPATH' ) || exit;

use Automattic\WooCommerce\Internal\Traits\OrderAttributionMeta;
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Admin\API\Reports\DataStore as ReportsDataStore;
use Automattic\WooCommerce\Admin\API\Reports\DataStoreInterface;
use Automattic\WooCommerce\Admin\API\Reports\SqlQuery;
Expand All @@ -18,6 +21,7 @@
* API\Reports\Orders\DataStore.
*/
class DataStore extends ReportsDataStore implements DataStoreInterface {
use OrderAttributionMeta;

/**
* Dynamically sets the date column name based on configuration
Expand Down Expand Up @@ -338,13 +342,14 @@ protected function normalize_order_by( $order_by ) {
* @param array $query_args Query parameters.
*/
protected function include_extended_info( &$orders_data, $query_args ) {
$mapped_orders = $this->map_array_by_key( $orders_data, 'order_id' );
$related_orders = $this->get_orders_with_parent_id( $mapped_orders );
$order_ids = array_merge( array_keys( $mapped_orders ), array_keys( $related_orders ) );
$products = $this->get_products_by_order_ids( $order_ids );
$coupons = $this->get_coupons_by_order_ids( array_keys( $mapped_orders ) );
$customers = $this->get_customers_by_orders( $orders_data );
$mapped_customers = $this->map_array_by_key( $customers, 'customer_id' );
$mapped_orders = $this->map_array_by_key( $orders_data, 'order_id' );
$related_orders = $this->get_orders_with_parent_id( $mapped_orders );
$order_ids = array_merge( array_keys( $mapped_orders ), array_keys( $related_orders ) );
$products = $this->get_products_by_order_ids( $order_ids );
$coupons = $this->get_coupons_by_order_ids( array_keys( $mapped_orders ) );
$order_attributions = $this->get_order_attributions_by_order_ids( array_keys( $mapped_orders ) );
$customers = $this->get_customers_by_orders( $orders_data );
$mapped_customers = $this->map_array_by_key( $customers, 'customer_id' );

$mapped_data = array();
foreach ( $products as $product ) {
Expand Down Expand Up @@ -394,15 +399,22 @@ protected function include_extended_info( &$orders_data, $query_args ) {
}

foreach ( $orders_data as $key => $order_data ) {
$defaults = array(
'products' => array(),
'coupons' => array(),
'customer' => array(),
$defaults = array(
'products' => array(),
'coupons' => array(),
'customer' => array(),
'attribution' => array(),
);
$orders_data[ $key ]['extended_info'] = isset( $mapped_data[ $order_data['order_id'] ] ) ? array_merge( $defaults, $mapped_data[ $order_data['order_id'] ] ) : $defaults;
$order_id = $order_data['order_id'];

$orders_data[ $key ]['extended_info'] = isset( $mapped_data[ $order_id ] ) ? array_merge( $defaults, $mapped_data[ $order_id ] ) : $defaults;
if ( $order_data['customer_id'] && isset( $mapped_customers[ $order_data['customer_id'] ] ) ) {
$orders_data[ $key ]['extended_info']['customer'] = $mapped_customers[ $order_data['customer_id'] ];
}

$source_type = $order_attributions[ $order_id ]['_wc_order_attribution_source_type'] ?? '';
$utm_source = $order_attributions[ $order_id ]['_wc_order_attribution_utm_source'] ?? '';
$orders_data[ $key ]['extended_info']['attribution']['origin'] = $this->get_origin_label( $source_type, $utm_source );
}
}

Expand Down Expand Up @@ -534,6 +546,52 @@ protected function get_coupons_by_order_ids( $order_ids ) {
return $coupons;
}

/**
* Get order attributions data from order IDs.
*
* @param array $order_ids Array of order IDs.
* @return array
*/
protected function get_order_attributions_by_order_ids( $order_ids ) {
global $wpdb;
$order_meta_table = OrdersTableDataStore::get_meta_table_name();
$included_order_ids = implode( ',', array_map( 'absint', $order_ids ) );

if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
/* phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared */
$order_attributions_meta = $wpdb->get_results(
"SELECT order_id, meta_key, meta_value
FROM $order_meta_table
WHERE order_id IN ({$included_order_ids})
AND meta_key IN ( '_wc_order_attribution_source_type', '_wc_order_attribution_utm_source' )
",
ARRAY_A
);
/* phpcs:enable */
} else {
/* phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared */
$order_attributions_meta = $wpdb->get_results(
"SELECT post_id as order_id, meta_key, meta_value
FROM $wpdb->postmeta
WHERE post_id IN ({$included_order_ids})
AND meta_key IN ( '_wc_order_attribution_source_type', '_wc_order_attribution_utm_source' )
",
ARRAY_A
);
/* phpcs:enable */
}

$order_attributions = array();
foreach ( $order_attributions_meta as $meta ) {
if ( ! isset( $order_attributions[ $meta['order_id'] ] ) ) {
$order_attributions[ $meta['order_id'] ] = array();
}
$order_attributions[ $meta['order_id'] ][ $meta['meta_key'] ] = $meta['meta_value'];
}

return $order_attributions;
}

/**
* Get all statuses that have been synced.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ public function test_extended_info() {
'date_created_gmt' => $data->data[0]['date_created_gmt'], // Not under test.
'date' => $data->data[0]['date'], // Not under test.
'extended_info' => array(
'products' => array(
'products' => array(
array(
'id' => $variation->get_id(),
'name' => $variation->get_name(),
Expand All @@ -108,8 +108,11 @@ public function test_extended_info() {
'quantity' => 1,
),
),
'coupons' => array(),
'customer' => $data->data[0]['extended_info']['customer'], // Not under test.
'coupons' => array(),
'customer' => $data->data[0]['extended_info']['customer'], // Not under test.
'attribution' => array(
'origin' => 'Unknown',
),
),
),
),
Expand Down

0 comments on commit 25be119

Please sign in to comment.