This commit is contained in:
Tony Volpe
2024-06-17 14:41:24 -04:00
parent f885e93ca8
commit a00f379f7f
11158 changed files with 0 additions and 1781316 deletions

View File

@@ -1,237 +0,0 @@
<?php
/**
* Nosara Tracks for WooCommerce
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce.
*/
class WC_Site_Tracking {
/**
* Check if tracking is enabled.
*
* @return bool
*/
public static function is_tracking_enabled() {
/**
* Don't track users if a filter has been applied to turn it off.
* `woocommerce_apply_tracking` will be deprecated. Please use
* `woocommerce_apply_user_tracking` instead.
*
* @since 3.6.0
*/
if ( ! apply_filters( 'woocommerce_apply_user_tracking', true ) || ! apply_filters( 'woocommerce_apply_tracking', true ) ) {
return false;
}
// Check if tracking is actively being opted into.
$is_obw_opting_in = isset( $_POST['wc_tracker_checkbox'] ) && 'yes' === sanitize_text_field( $_POST['wc_tracker_checkbox'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput
/**
* Don't track users who haven't opted-in to tracking or aren't in
* the process of opting-in.
*/
if ( 'yes' !== get_option( 'woocommerce_allow_tracking' ) && ! $is_obw_opting_in ) {
return false;
}
if ( ! class_exists( 'WC_Tracks' ) ) {
return false;
}
return true;
}
/**
* Register scripts required to record events from javascript.
*/
public static function register_scripts() {
wp_register_script( 'woo-tracks', 'https://stats.wp.com/w.js', array( 'wp-hooks' ), gmdate( 'YW' ), false );
}
/**
* Add scripts required to record events from javascript.
*/
public static function enqueue_scripts() {
wp_enqueue_script( 'woo-tracks' );
}
/**
* Adds the tracking function to the admin footer.
*/
public static function add_tracking_function() {
$user = wp_get_current_user();
$server_details = WC_Tracks::get_server_details();
$blog_details = WC_Tracks::get_blog_details( $user->ID );
$tracks_identity = WC_Tracks_Client::get_identity( $user->ID );
$client_tracking_properties = array_merge( $server_details, $blog_details );
/**
* Add global tracks event properties.
*
* @since 6.5.0
*/
$filtered_properties = apply_filters( 'woocommerce_tracks_event_properties', $client_tracking_properties, false );
$environment_type = function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production';
?>
<!-- WooCommerce Tracks -->
<script type="text/javascript">
window.wcTracks = window.wcTracks || {};
window.wcTracks.isEnabled = <?php echo self::is_tracking_enabled() ? 'true' : 'false'; ?>;
window._tkq = window._tkq || [];
<?php if ( 'anon' !== $tracks_identity['_ut'] ) { ?>
window._tkq.push( [ 'identifyUser', '<?php echo esc_js( $tracks_identity['_ui'] ); ?>' ] );
<?php } ?>
window.wcTracks.validateEvent = function( eventName, props = {} ) {
let isValid = true;
if ( ! <?php echo esc_js( WC_Tracks_Event::EVENT_NAME_REGEX ); ?>.test( eventName ) ) {
if ( <?php echo $environment_type !== 'production' ? 'true' : 'false'; ?> ) {
/* eslint-disable no-console */
console.error(
`A valid event name must be specified. The event name: "${ eventName }" is not valid.`
);
/* eslint-enable no-console */
}
isValid = false;
}
for ( const prop of Object.keys( props ) ) {
if ( ! <?php echo esc_js( WC_Tracks_Event::PROP_NAME_REGEX ); ?>.test( prop ) ) {
if ( <?php echo $environment_type !== 'production' ? 'true' : 'false'; ?> ) {
/* eslint-disable no-console */
console.error(
`A valid prop name must be specified. The property name: "${ prop }" is not valid.`
);
/* eslint-enable no-console */
}
isValid = false;
}
}
return isValid;
}
window.wcTracks.recordEvent = function( name, properties ) {
if ( ! window.wcTracks.isEnabled ) {
return;
}
const eventName = '<?php echo esc_attr( WC_Tracks::PREFIX ); ?>' + name;
let eventProperties = properties || {};
eventProperties = { ...eventProperties, ...<?php echo json_encode( $filtered_properties ); ?> };
if ( window.wp && window.wp.hooks && window.wp.hooks.applyFilters ) {
eventProperties = window.wp.hooks.applyFilters( 'woocommerce_tracks_client_event_properties', eventProperties, eventName );
delete( eventProperties._ui );
delete( eventProperties._ut );
}
if ( ! window.wcTracks.validateEvent( eventName, eventProperties ) ) {
return;
}
window._tkq.push( [ 'recordEvent', eventName, eventProperties ] );
}
</script>
<?php
}
/**
* Adds a function to load tracking scripts and enable them client-side on the fly.
* Note that this function does not update `woocommerce_allow_tracking` in the database
* and will not persist enabled tracking across page loads.
*/
public static function add_enable_tracking_function() {
global $wp_scripts;
if ( ! isset( $wp_scripts->registered['woo-tracks'] ) ) {
return;
}
$woo_tracks_script = $wp_scripts->registered['woo-tracks']->src;
?>
<script type="text/javascript">
window.wcTracks.enable = function( callback ) {
window.wcTracks.isEnabled = true;
var scriptUrl = '<?php echo esc_url( $woo_tracks_script ); ?>';
var existingScript = document.querySelector( `script[src="${ scriptUrl }"]` );
if ( existingScript ) {
return;
}
var script = document.createElement('script');
script.src = scriptUrl;
document.body.append(script);
// Callback after scripts have loaded.
script.onload = function() {
if ( 'function' === typeof callback ) {
callback( true );
}
}
// Callback triggered if the script fails to load.
script.onerror = function() {
if ( 'function' === typeof callback ) {
callback( false );
}
}
}
</script>
<?php
}
/**
* Init tracking.
*/
public static function init() {
// Define window.wcTracks.recordEvent in case it is enabled client-side.
self::register_scripts();
add_filter( 'admin_footer', array( __CLASS__, 'add_tracking_function' ), 24 );
if ( ! self::is_tracking_enabled() ) {
add_filter( 'admin_footer', array( __CLASS__, 'add_enable_tracking_function' ), 24 );
return;
}
self::enqueue_scripts();
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-admin-setup-wizard-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-extensions-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-importer-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-products-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-orders-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-settings-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-status-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-coupons-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-order-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-coupon-tracking.php';
include_once WC_ABSPATH . 'includes/tracks/events/class-wc-theme-tracking.php';
$tracking_classes = array(
'WC_Extensions_Tracking',
'WC_Importer_Tracking',
'WC_Products_Tracking',
'WC_Orders_Tracking',
'WC_Settings_Tracking',
'WC_Status_Tracking',
'WC_Coupons_Tracking',
'WC_Order_Tracking',
'WC_Coupon_Tracking',
'WC_Theme_Tracking',
);
foreach ( $tracking_classes as $tracking_class ) {
$tracker_instance = new $tracking_class();
$tracker_init_method = array( $tracker_instance, 'init' );
if ( is_callable( $tracker_init_method ) ) {
call_user_func( $tracker_init_method );
}
}
}
}

View File

@@ -1,214 +0,0 @@
<?php
/**
* Send Tracks events on behalf of a user.
*
* @package WooCommerce\Tracks
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Utilities\NumberUtil;
defined( 'ABSPATH' ) || exit;
/**
* WC_Tracks_Client class.
*/
class WC_Tracks_Client {
/**
* Pixel URL.
*/
const PIXEL = 'https://pixel.wp.com/t.gif';
/**
* Browser type.
*/
const BROWSER_TYPE = 'php-agent';
/**
* User agent.
*/
const USER_AGENT_SLUG = 'tracks-client';
/**
* Initialize tracks client class
*
* @return void
*/
public static function init() {
// Use wp hook for setting the identity cookie to avoid headers already sent warnings.
add_action( 'admin_init', array( __CLASS__, 'maybe_set_identity_cookie' ) );
}
/**
* Check if identity cookie is set, if not set it.
*
* @return void
*/
public static function maybe_set_identity_cookie() {
// Do not set on AJAX requests.
if ( Constants::is_true( 'DOING_AJAX' ) ) {
return;
}
// Bail if cookie already set.
if ( isset( $_COOKIE['tk_ai'] ) ) {
return;
}
$user = wp_get_current_user();
// We don't want to track user events during unit tests/CI runs.
if ( $user instanceof WP_User && 'wptests_capabilities' === $user->cap_key ) {
return false;
}
$user_id = $user->ID;
$anon_id = get_user_meta( $user_id, '_woocommerce_tracks_anon_id', true );
// If an id is still not found, create one and save it.
if ( ! $anon_id ) {
$anon_id = self::get_anon_id();
update_user_meta( $user_id, '_woocommerce_tracks_anon_id', $anon_id );
}
// Don't set cookie on API requests.
if ( ! Constants::is_true( 'REST_REQUEST' ) && ! Constants::is_true( 'XMLRPC_REQUEST' ) ) {
wc_setcookie( 'tk_ai', $anon_id );
}
}
/**
* Record a Tracks event
*
* @param array $event Array of event properties.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public static function record_event( $event ) {
if ( ! $event instanceof WC_Tracks_Event ) {
$event = new WC_Tracks_Event( $event );
}
if ( is_wp_error( $event ) ) {
return $event;
}
$pixel = $event->build_pixel_url( $event );
if ( ! $pixel ) {
return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 );
}
return self::record_pixel( $pixel );
}
/**
* Synchronously request the pixel.
*
* @param string $pixel pixel url and query string.
* @return bool Always returns true.
*/
public static function record_pixel( $pixel ) {
// Add the Request Timestamp and URL terminator just before the HTTP request.
$pixel .= '&_rt=' . self::build_timestamp() . '&_=_';
wp_safe_remote_get(
$pixel,
array(
'blocking' => false,
'redirection' => 2,
'httpversion' => '1.1',
'timeout' => 1,
)
);
return true;
}
/**
* Create a timestamp representing milliseconds since 1970-01-01
*
* @return string A string representing a timestamp.
*/
public static function build_timestamp() {
$ts = NumberUtil::round( microtime( true ) * 1000 );
return number_format( $ts, 0, '', '' );
}
/**
* Get a user's identity to send to Tracks. If Jetpack exists, default to its implementation.
*
* @param int $user_id User id.
* @return array Identity properties.
*/
public static function get_identity( $user_id ) {
$jetpack_lib = '/tracks/client.php';
if ( class_exists( 'Jetpack' ) && Constants::is_defined( 'JETPACK__VERSION' ) ) {
if ( version_compare( Constants::get_constant( 'JETPACK__VERSION' ), '7.5', '<' ) ) {
if ( file_exists( jetpack_require_lib_dir() . $jetpack_lib ) ) {
include_once jetpack_require_lib_dir() . $jetpack_lib;
if ( function_exists( 'jetpack_tracks_get_identity' ) ) {
return jetpack_tracks_get_identity( $user_id );
}
}
} else {
$tracking = new Automattic\Jetpack\Tracking();
return $tracking->tracks_get_identity( $user_id );
}
}
// Start with a previously set cookie.
$anon_id = isset( $_COOKIE['tk_ai'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) ) : false;
// If there is no cookie, apply a saved id.
if ( ! $anon_id ) {
$anon_id = get_user_meta( $user_id, '_woocommerce_tracks_anon_id', true );
}
// If an id is still not found, create one and save it.
if ( ! $anon_id ) {
$anon_id = self::get_anon_id();
update_user_meta( $user_id, '_woocommerce_tracks_anon_id', $anon_id );
}
return array(
'_ut' => 'anon',
'_ui' => $anon_id,
);
}
/**
* Grabs the user's anon id from cookies, or generates and sets a new one
*
* @return string An anon id for the user
*/
public static function get_anon_id() {
static $anon_id = null;
if ( ! isset( $anon_id ) ) {
// Did the browser send us a cookie?
if ( isset( $_COOKIE['tk_ai'] ) ) {
$anon_id = sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) );
} else {
$binary = '';
// Generate a new anonId and try to save it in the browser's cookies.
// Note that base64-encoding an 18 character string generates a 24-character anon id.
for ( $i = 0; $i < 18; ++$i ) {
$binary .= chr( wp_rand( 0, 255 ) );
}
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
$anon_id = 'woo:' . base64_encode( $binary );
}
}
return $anon_id;
}
}
WC_Tracks_Client::init();

View File

@@ -1,178 +0,0 @@
<?php
/**
* This class represents an event used to record a Tracks event
*
* @package WooCommerce\Tracks
*/
use Automattic\Jetpack\Constants;
defined( 'ABSPATH' ) || exit;
/**
* WC_Tracks_Event class.
*/
#[AllowDynamicProperties]
class WC_Tracks_Event {
/**
* Event name regex.
*/
public const EVENT_NAME_REGEX = '/^(([a-z0-9]+)_){1}([a-z0-9_]+)$/';
/**
* Property name regex.
*/
public const PROP_NAME_REGEX = '/^[a-z_][a-z0-9_]*$/';
/**
* Error message as WP_Error.
*
* @var WP_Error
*/
public $error;
/**
* WC_Tracks_Event constructor.
*
* @param array $event Event properties.
*/
public function __construct( $event ) {
$_event = self::validate_and_sanitize( $event );
if ( is_wp_error( $_event ) ) {
$this->error = $_event;
return;
}
foreach ( $_event as $key => $value ) {
$this->{$key} = $value;
}
}
/**
* Record Tracks event
*
* @return bool Always returns true.
*/
public function record() {
if ( wp_doing_ajax() || Constants::is_true( 'REST_REQUEST' ) || Constants::is_true( 'WP_CLI' ) || wp_doing_cron() ) {
return WC_Tracks_Client::record_event( $this );
}
return WC_Tracks_Footer_Pixel::record_event( $this );
}
/**
* Annotate the event with all relevant info.
*
* @param array $event Event arguments.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public static function validate_and_sanitize( $event ) {
$event = (object) $event;
// Required.
if ( ! $event->_en ) {
return new WP_Error( 'invalid_event', 'A valid event must be specified via `_en`', 400 );
}
// Delete non-routable addresses otherwise geoip will discard the record entirely.
if ( property_exists( $event, '_via_ip' ) && preg_match( '/^192\.168|^10\./', $event->_via_ip ) ) {
unset( $event->_via_ip );
}
$validated = array(
'browser_type' => WC_Tracks_Client::BROWSER_TYPE,
);
$_event = (object) array_merge( (array) $event, $validated );
// If you want to block property names, do it here.
// Make sure we have an event timestamp.
if ( ! isset( $_event->_ts ) ) {
$_event->_ts = WC_Tracks_Client::build_timestamp();
}
if ( ! self::event_name_is_valid( $_event->_en ) ) {
return new WP_Error( 'invalid_event_name', __( 'A valid event name must be specified.', 'woocommerce' ) );
}
foreach ( array_keys( (array) $_event ) as $key ) {
if ( ! self::prop_name_is_valid( $key ) && '_en' !== $key ) {
return new WP_Error( 'invalid_prop_name', __( 'A valid prop name must be specified', 'woocommerce' ) );
}
}
return $_event;
}
/**
* Build a pixel URL that will send a Tracks event when fired.
* On error, returns an empty string ('').
*
* @return string A pixel URL or empty string ('') if there were invalid args.
*/
public function build_pixel_url() {
if ( $this->error ) {
return '';
}
$args = get_object_vars( $this );
// Request Timestamp and URL Terminator must be added just before the HTTP request or not at all.
unset( $args['_rt'], $args['_'] );
$validated = self::validate_and_sanitize( $args );
if ( is_wp_error( $validated ) ) {
return '';
}
return esc_url_raw( WC_Tracks_Client::PIXEL . '?' . http_build_query( $validated ) );
}
/**
* Check if event name is valid.
*
* @param string $name Event name.
* @return false|int
*/
public static function event_name_is_valid( $name ) {
return preg_match( self::EVENT_NAME_REGEX, $name );
}
/**
* Check if a property name is valid.
*
* @param string $name Event property.
* @return false|int
*/
public static function prop_name_is_valid( $name ) {
return preg_match( self::PROP_NAME_REGEX, $name );
}
/**
* Check event names
*
* @param object $event An event object.
*/
public static function scrutinize_event_names( $event ) {
if ( ! self::event_name_is_valid( $event->_en ) ) {
return;
}
$allowed_key_names = array(
'anonId',
'Browser_Type',
);
foreach ( array_keys( (array) $event ) as $key ) {
if ( in_array( $key, $allowed_key_names, true ) ) {
continue;
}
if ( ! self::prop_name_is_valid( $key ) ) {
return;
}
}
}
}

View File

@@ -1,127 +0,0 @@
<?php
/**
* Send Tracks events on behalf of a user using pixel images in page footer.
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* WC_Tracks_Footer_Pixel class.
*/
class WC_Tracks_Footer_Pixel {
/**
* Singleton instance.
*
* @var WC_Tracks_Footer_Pixel
*/
protected static $instance = null;
/**
* Events to send to Tracks.
*
* @var array
*/
protected $events = array();
/**
* Instantiate the singleton.
*
* @return WC_Tracks_Footer_Pixel
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new WC_Tracks_Footer_Pixel();
}
return self::$instance;
}
/**
* Constructor - attach hooks to the singleton instance.
*/
public function __construct() {
add_action( 'admin_footer', array( $this, 'render_tracking_pixels' ) );
add_action( 'shutdown', array( $this, 'send_tracks_requests' ) );
}
/**
* Record a Tracks event
*
* @param array $event Array of event properties.
* @return bool|WP_Error True on success, WP_Error on failure.
*/
public static function record_event( $event ) {
if ( ! $event instanceof WC_Tracks_Event ) {
$event = new WC_Tracks_Event( $event );
}
if ( is_wp_error( $event ) ) {
return $event;
}
self::instance()->add_event( $event );
return true;
}
/**
* Add a Tracks event to the queue.
*
* @param WC_Tracks_Event $event Event to track.
*/
public function add_event( $event ) {
$this->events[] = $event;
}
/**
* Add events as tracking pixels to page footer.
*/
public function render_tracking_pixels() {
if ( empty( $this->events ) ) {
return;
}
foreach ( $this->events as $event ) {
$pixel = $event->build_pixel_url();
if ( ! $pixel ) {
continue;
}
echo '<img style="position: fixed;" src="', esc_url( $pixel ), '" />';
}
$this->events = array();
}
/**
* Fire off API calls for events that weren't converted to pixels.
*
* This handles wp_redirect().
*/
public function send_tracks_requests() {
if ( empty( $this->events ) ) {
return;
}
foreach ( $this->events as $event ) {
WC_Tracks_Client::record_event( $event );
}
}
/**
* Get all events.
*/
public static function get_events() {
return self::instance()->events;
}
/**
* Clear all queued events.
*/
public static function clear_events() {
self::instance()->events = array();
}
}

View File

@@ -1,136 +0,0 @@
<?php
/**
* PHP Tracks Client
*
* @package WooCommerce\Tracks
*/
/**
* WC_Tracks class.
*/
class WC_Tracks {
/**
* Tracks event name prefix.
*/
const PREFIX = 'wcadmin_';
/**
* Get total product counts.
*
* @return int Number of products.
*/
public static function get_products_count() {
$product_counts = WC_Tracker::get_product_counts();
return $product_counts['total'];
}
/**
* Gather blog related properties.
*
* @param int $user_id User id.
* @return array Blog details.
*/
public static function get_blog_details( $user_id ) {
$blog_details = get_transient( 'wc_tracks_blog_details' );
if ( false === $blog_details ) {
$blog_details = array(
'url' => home_url(),
'blog_lang' => get_user_locale( $user_id ),
'blog_id' => class_exists( 'Jetpack_Options' ) ? Jetpack_Options::get_option( 'id' ) : null,
'store_id' => get_option( \WC_Install::STORE_ID_OPTION, null ),
'products_count' => self::get_products_count(),
'wc_version' => WC()->version,
);
set_transient( 'wc_tracks_blog_details', $blog_details, DAY_IN_SECONDS );
}
return $blog_details;
}
/**
* Gather details from the request to the server.
*
* @return array Server details.
*/
public static function get_server_details() {
$data = array();
$data['_via_ua'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
$data['_via_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? wc_clean( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
$data['_lg'] = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : '';
$data['_dr'] = isset( $_SERVER['HTTP_REFERER'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '';
$uri = isset( $_SERVER['REQUEST_URI'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
$host = isset( $_SERVER['HTTP_HOST'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
$data['_dl'] = isset( $_SERVER['REQUEST_SCHEME'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_SCHEME'] ) ) . '://' . $host . $uri : '';
return $data;
}
/**
* Record an event in Tracks - this is the preferred way to record events from PHP.
* Note: the event request won't be made if $properties has a member called `error`.
*
* @param string $event_name The name of the event.
* @param array $event_properties Custom properties to send with the event.
* @return bool|WP_Error True for success or WP_Error if the event pixel could not be fired.
*/
public static function record_event( $event_name, $event_properties = array() ) {
/**
* Don't track users who don't have tracking enabled.
*/
if ( ! WC_Site_Tracking::is_tracking_enabled() ) {
return false;
}
$user = wp_get_current_user();
// We don't want to track user events during unit tests/CI runs.
if ( $user instanceof WP_User && 'wptests_capabilities' === $user->cap_key ) {
return false;
}
$prefixed_event_name = self::PREFIX . $event_name;
$properties = self::get_properties( $prefixed_event_name, $event_properties );
$event_obj = new WC_Tracks_Event( $properties );
if ( is_wp_error( $event_obj->error ) ) {
return $event_obj->error;
}
return $event_obj->record();
}
/**
* Get all properties for the event including filtered and identity properties.
*
* @param string $event_name Event name.
* @param array $event_properties Event specific properties.
* @return array
*/
public static function get_properties( $event_name, $event_properties ) {
/**
* Allow event props to be filtered to enable adding site-wide props.
*
* @since 4.1.0
*/
$properties = apply_filters( 'woocommerce_tracks_event_properties', $event_properties, $event_name );
$user = wp_get_current_user();
$identity = WC_Tracks_Client::get_identity( $user->ID );
// Delete _ui and _ut protected properties.
unset( $properties['_ui'] );
unset( $properties['_ut'] );
$data = $event_name
? array(
'_en' => $event_name,
'_ts' => WC_Tracks_Client::build_timestamp(),
)
: array();
$server_details = self::get_server_details();
$blog_details = self::get_blog_details( $user->ID );
return array_merge( $properties, $data, $server_details, $identity, $blog_details );
}
}

View File

@@ -1,176 +0,0 @@
<?php
/**
* WooCommerce Admin Setup Wizard Tracking
*
* @package WooCommerce\Tracks
*
* @deprecated 4.6.0
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of the WooCommerce Onboarding Wizard.
*/
class WC_Admin_Setup_Wizard_Tracking {
/**
* Steps for the setup wizard
*
* @var array
*/
private $steps = array();
/**
* Init tracking.
*
* @deprecated 4.6.0
*/
public function init() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Get the name of the current step.
*
* @deprecated 4.6.0
* @return string
*/
public function get_current_step() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
return isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
/**
* Add footer scripts to OBW via woocommerce_setup_footer
*
* @deprecated 4.6.0
*/
public function add_footer_scripts() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Dequeue unwanted scripts from OBW footer.
*
* @deprecated 4.6.0
*/
public function dequeue_non_allowed_scripts() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
global $wp_scripts;
$allowed = array( 'woo-tracks' );
foreach ( $wp_scripts->queue as $script ) {
if ( in_array( $script, $allowed, true ) ) {
continue;
}
wp_dequeue_script( $script );
}
}
/**
* Track when tracking is opted into and OBW has started.
*
* @param string $option Option name.
* @param string $value Option value.
*
* @deprecated 4.6.0
*/
public function track_start( $option, $value ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track the marketing form on submit.
*
* @deprecated 4.6.0
*/
public function track_ready_next_steps() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track various events when a step is saved.
*
* @deprecated 4.6.0
*/
public function add_step_save_events() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track store setup and store properties on save.
*
* @deprecated 4.6.0
*/
public function track_store_setup() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track payment gateways selected.
*
* @deprecated 4.6.0
*/
public function track_payments() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track shipping units and whether or not labels are set.
*
* @deprecated 4.6.0
*/
public function track_shipping() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track recommended plugins selected for install.
*
* @deprecated 4.6.0
*/
public function track_recommended() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Tracks when Jetpack is activated through the OBW.
*
* @deprecated 4.6.0
*/
public function track_jetpack_activate() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Tracks when last next_steps screen is viewed in the OBW.
*
* @deprecated 4.6.0
*/
public function track_next_steps() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Track skipped steps.
*
* @deprecated 4.6.0
*/
public function track_skip_step() {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
}
/**
* Set the OBW steps inside this class instance.
*
* @param array $steps Array of OBW steps.
*
* @deprecated 4.6.0
*/
public function set_obw_steps( $steps ) {
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, '4.6.0', __( 'Onboarding is maintained in WooCommerce Admin.', 'woocommerce' ) );
$this->steps = $steps;
return $steps;
}
}

View File

@@ -1,39 +0,0 @@
<?php
/**
* WooCommerce Coupon Tracking
*
* @package WooCommerce\Tracks
*/
/**
* This class adds actions to track usage of a WooCommerce Coupon.
*/
class WC_Coupon_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'woocommerce_coupon_object_updated_props', array( $this, 'track_coupon_updated' ), 10, 2 );
}
/**
* Send a Tracks event when a coupon is updated.
*
* @param WC_Coupon $coupon The coupon that has been updated.
* @param Array $updated_props The props of the coupon that have been updated.
*/
public function track_coupon_updated( $coupon, $updated_props ) {
$properties = array(
'discount_code' => $coupon->get_code(),
'free_shipping' => $coupon->get_free_shipping(),
'individual_use' => $coupon->get_individual_use(),
'exclude_sale_items' => $coupon->get_exclude_sale_items(),
'usage_limits_applied' => 0 < intval( $coupon->get_usage_limit() )
|| 0 < intval( $coupon->get_usage_limit_per_user() )
|| 0 < intval( $coupon->get_limit_usage_to_x_items() ),
);
WC_Tracks::record_event( 'coupon_updated', $properties );
}
}

View File

@@ -1,73 +0,0 @@
<?php
/**
* WooCommerce Coupons Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce Orders.
*/
class WC_Coupons_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'load-edit.php', array( $this, 'tracks_coupons_events' ), 10 );
}
/**
* Add a listener on the "Apply" button to track bulk actions.
*/
public function tracks_coupons_bulk_actions() {
wc_enqueue_js(
"
function onApplyBulkActions( event ) {
var id = event.data.id;
var action = $( '#' + id ).val();
if ( action && '-1' !== action ) {
window.wcTracks.recordEvent( 'coupons_view_bulk_action', {
action: action
} );
}
}
$( '#doaction' ).on( 'click', { id: 'bulk-action-selector-top' }, onApplyBulkActions );
$( '#doaction2' ).on( 'click', { id: 'bulk-action-selector-bottom' }, onApplyBulkActions );
"
);
}
/**
* Track page view events.
*/
public function tracks_coupons_events() {
if ( isset( $_GET['post_type'] ) && 'shop_coupon' === $_GET['post_type'] ) {
$this->tracks_coupons_bulk_actions();
WC_Tracks::record_event(
'coupons_view',
array(
'status' => isset( $_GET['post_status'] ) ? sanitize_text_field( wp_unslash( $_GET['post_status'] ) ) : 'all',
)
);
if ( isset( $_GET['filter_action'] ) && 'Filter' === sanitize_text_field( wp_unslash( $_GET['filter_action'] ) ) && isset( $_GET['coupon_type'] ) ) {
WC_Tracks::record_event(
'coupons_filter',
array(
'filter' => 'coupon_type',
'value' => sanitize_text_field( wp_unslash( $_GET['coupon_type'] ) ),
)
);
}
if ( isset( $_GET['s'] ) && 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) ) ) {
WC_Tracks::record_event( 'coupons_search' );
}
}
}
}

View File

@@ -1,125 +0,0 @@
<?php
/**
* WooCommerce Extensions Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of the WooCommerce Extensions page.
*/
class WC_Extensions_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'load-woocommerce_page_wc-addons', array( $this, 'track_extensions_page' ) );
add_action( 'woocommerce_helper_connect_start', array( $this, 'track_helper_connection_start' ) );
add_action( 'woocommerce_helper_denied', array( $this, 'track_helper_connection_cancelled' ) );
add_action( 'woocommerce_helper_connected', array( $this, 'track_helper_connection_complete' ) );
add_action( 'woocommerce_helper_disconnected', array( $this, 'track_helper_disconnected' ) );
add_action( 'woocommerce_helper_subscriptions_refresh', array( $this, 'track_helper_subscriptions_refresh' ) );
add_action( 'woocommerce_addon_installed', array( $this, 'track_addon_install' ), 10, 2 );
add_action( 'woocommerce_page_wc-addons_connection_error', array( $this, 'track_extensions_page_connection_error' ), 10, 1 );
}
/**
* Send a Tracks event when an Extensions page is viewed.
*/
public function track_extensions_page() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$properties = array(
'section' => empty( $_REQUEST['section'] ) ? '_featured' : wc_clean( wp_unslash( $_REQUEST['section'] ) ),
);
$event = 'extensions_view';
if ( 'helper' === $properties['section'] ) {
$event = 'subscriptions_view';
}
if ( ! empty( $_REQUEST['search'] ) ) {
$event = 'extensions_view_search';
$properties['search_term'] = wc_clean( wp_unslash( $_REQUEST['search'] ) );
}
// phpcs:enable
WC_Tracks::record_event( $event, $properties );
}
/**
* Send a Tracks event when the Extensions page gets a bad response or no response
* from the WCCOM extensions API.
*
* @param string $error
*/
public function track_extensions_page_connection_error( string $error = '' ) {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$properties = array(
'section' => empty( $_REQUEST['section'] ) ? '_featured' : wc_clean( wp_unslash( $_REQUEST['section'] ) ),
);
if ( ! empty( $_REQUEST['search'] ) ) {
$properties['search_term'] = wc_clean( wp_unslash( $_REQUEST['search'] ) );
}
// phpcs:enable
if ( ! empty( $error ) ) {
$properties['error_data'] = $error;
}
WC_Tracks::record_event( 'extensions_view_connection_error', $properties );
}
/**
* Send a Tracks even when a Helper connection process is initiated.
*/
public function track_helper_connection_start() {
WC_Tracks::record_event( 'extensions_subscriptions_connect' );
}
/**
* Send a Tracks even when a Helper connection process is cancelled.
*/
public function track_helper_connection_cancelled() {
WC_Tracks::record_event( 'extensions_subscriptions_cancelled' );
}
/**
* Send a Tracks even when a Helper connection process completed successfully.
*/
public function track_helper_connection_complete() {
WC_Tracks::record_event( 'extensions_subscriptions_connected' );
}
/**
* Send a Tracks even when a Helper has been disconnected.
*/
public function track_helper_disconnected() {
WC_Tracks::record_event( 'extensions_subscriptions_disconnect' );
}
/**
* Send a Tracks even when Helper subscriptions are refreshed.
*/
public function track_helper_subscriptions_refresh() {
WC_Tracks::record_event( 'extensions_subscriptions_update' );
}
/**
* Send a Tracks event when addon is installed via the Extensions page.
*
* @param string $addon_id Addon slug.
* @param string $section Extensions tab.
*/
public function track_addon_install( $addon_id, $section ) {
$properties = array(
'context' => 'extensions',
'section' => $section,
);
if ( 'woocommerce-payments' === $addon_id ) {
WC_Tracks::record_event( 'woocommerce_payments_install', $properties );
}
}
}

View File

@@ -1,84 +0,0 @@
<?php
/**
* WooCommerce Import Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce Imports.
*/
class WC_Importer_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'product_page_product_importer', array( $this, 'track_product_importer' ) );
}
/**
* Route product importer action to the right callback.
*
* @return void
*/
public function track_product_importer() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! isset( $_REQUEST['step'] ) ) {
return;
}
if ( 'import' === $_REQUEST['step'] ) {
return $this->track_product_importer_start();
}
if ( 'done' === $_REQUEST['step'] ) {
return $this->track_product_importer_complete();
}
// phpcs:enable
}
/**
* Send a Tracks event when the product importer is started.
*
* @return void
*/
public function track_product_importer_start() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! isset( $_REQUEST['file'] ) || ! isset( $_REQUEST['_wpnonce'] ) ) {
return;
}
$properties = array(
'update_existing' => isset( $_REQUEST['update_existing'] ) ? (bool) $_REQUEST['update_existing'] : false,
'delimiter' => empty( $_REQUEST['delimiter'] ) ? ',' : wc_clean( wp_unslash( $_REQUEST['delimiter'] ) ),
);
// phpcs:enable
WC_Tracks::record_event( 'product_import_start', $properties );
}
/**
* Send a Tracks event when the product importer has finished.
*
* @return void
*/
public function track_product_importer_complete() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! isset( $_REQUEST['nonce'] ) ) {
return;
}
$properties = array(
'imported' => isset( $_GET['products-imported'] ) ? absint( $_GET['products-imported'] ) : 0,
'imported_variations' => isset( $_GET['products-imported-variations'] ) ? absint( $_GET['products-imported-variations'] ) : 0,
'updated' => isset( $_GET['products-updated'] ) ? absint( $_GET['products-updated'] ) : 0,
'failed' => isset( $_GET['products-failed'] ) ? absint( $_GET['products-failed'] ) : 0,
'skipped' => isset( $_GET['products-skipped'] ) ? absint( $_GET['products-skipped'] ) : 0,
);
// phpcs:enable
WC_Tracks::record_event( 'product_import_complete', $properties );
}
}

View File

@@ -1,40 +0,0 @@
<?php
/**
* WooCommerce Order Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of a WooCommerce Order.
*/
class WC_Order_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'woocommerce_admin_order_data_after_order_details', array( $this, 'track_order_viewed' ) );
}
/**
* Send a Tracks event when an order is viewed.
*
* @param WC_Order $order Order.
*/
public function track_order_viewed( $order ) {
if ( ! $order instanceof WC_Order || ! $order->get_id() ) {
return;
}
$properties = array(
'current_status' => $order->get_status(),
'date_created' => $order->get_date_created() ? $order->get_date_created()->format( DateTime::ATOM ) : '',
'payment_method' => $order->get_payment_method(),
);
WC_Tracks::record_event( 'single_order_view', $properties );
}
}

View File

@@ -1,226 +0,0 @@
<?php
/**
* WooCommerce Orders Tracking
*
* @package WooCommerce\Tracks
*/
use Automattic\WooCommerce\Utilities\OrderUtil;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce Orders.
*/
class WC_Orders_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'woocommerce_order_status_changed', array( $this, 'track_order_status_change' ), 10, 3 );
// WC_Meta_Box_Order_Actions::save() hooks in at priority 50.
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'track_order_action' ), 51 );
add_action( 'load-edit.php', array( $this, 'track_orders_view' ), 10 );
add_action( 'load-woocommerce_page_wc-orders', array( $this, 'track_orders_view' ), 999 ); // HPOS.
add_action( 'load-post-new.php', array( $this, 'track_add_order_from_edit' ), 10 );
add_action( 'load-woocommerce_page_wc-orders', array( $this, 'track_add_order_from_edit' ), 999 ); // HPOS.
add_action( 'woocommerce_process_shop_order_meta', array( $this, 'track_created_date_change' ), 10 );
add_action( 'load-edit.php', array( $this, 'track_search_in_orders_list' ) );
add_action( 'load-woocommerce_page_wc-orders', array( $this, 'track_search_in_orders_list' ), 999 ); // HPOS.
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_order_tracking_scripts' ) );
}
/**
* Send a track event when on the Order Listing page, and search results are being displayed.
*
* @deprecated 8.6.0
*
* @param array $order_ids Array of order_ids that are matches for the search.
* @param string $term The string that was used in the search.
* @param array $search_fields Fields that were used in the original search.
*/
public function track_order_search( $order_ids, $term, $search_fields ) {
wc_deprecated_function( __METHOD__, '8.6.0', 'WC_Orders_Tracking::track_search_in_orders_list' );
// Since `woocommerce_shop_order_search_results` can run in the front-end context, exit if get_current_screen isn't defined.
if ( ! function_exists( 'get_current_screen' ) ) {
return $order_ids;
}
$screen = get_current_screen();
// We only want to record this track when the filter is executed on the order listing page.
if ( 'edit-shop_order' === $screen->id ) {
// we are on the order listing page, and query results are being shown.
WC_Tracks::record_event( 'orders_view_search' );
}
return $order_ids;
}
/**
* Send a track event when on the Order Listing page, and search results are being displayed.
*
* @since 8.6.0
*/
public function track_search_in_orders_list() {
if ( ! OrderUtil::is_order_list_table_screen() || empty( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
WC_Tracks::record_event( 'orders_view_search' );
}
/**
* Send a Tracks event when the Orders page is viewed.
*/
public function track_orders_view() {
if ( ! OrderUtil::is_order_list_table_screen() ) {
return;
}
// phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput
$properties = array(
'status' => sanitize_text_field( $_GET['post_status'] ?? ( $_GET['status'] ?? 'all' ) ),
);
// phpcs:enable
WC_Tracks::record_event( 'orders_view', $properties );
}
/**
* Send a Tracks event when an order status is changed.
*
* @param int $id Order id.
* @param string $previous_status the old WooCommerce order status.
* @param string $next_status the new WooCommerce order status.
*/
public function track_order_status_change( $id, $previous_status, $next_status ) {
$order = wc_get_order( $id );
$properties = array(
'order_id' => $id,
'next_status' => $next_status,
'previous_status' => $previous_status,
'date_created' => $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d' ) : '',
'payment_method' => $order->get_payment_method(),
'order_total' => $order->get_total(),
);
WC_Tracks::record_event( 'orders_edit_status_change', $properties );
}
/**
* Send a Tracks event when an order date is changed.
*
* @param int $id Order id.
*/
public function track_created_date_change( $id ) {
if ( ! OrderUtil::is_order( $id ) ) {
return;
}
$order = wc_get_order( $id );
if ( ! $order || 'auto-draft' === $order->get_status() ) {
return;
}
$date_created = $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d H:i:s' ) : '';
// phpcs:disable WordPress.Security.NonceVerification
$new_date = sprintf(
'%s %2d:%02d:%02d',
isset( $_POST['order_date'] ) ? wc_clean( wp_unslash( $_POST['order_date'] ) ) : '',
isset( $_POST['order_date_hour'] ) ? wc_clean( wp_unslash( $_POST['order_date_hour'] ) ) : '',
isset( $_POST['order_date_minute'] ) ? wc_clean( wp_unslash( $_POST['order_date_minute'] ) ) : '',
isset( $_POST['order_date_second'] ) ? wc_clean( wp_unslash( $_POST['order_date_second'] ) ) : ''
);
// phpcs:enable
if ( $new_date !== $date_created ) {
$properties = array(
'order_id' => $id,
'status' => $order->get_status(),
);
WC_Tracks::record_event( 'order_edit_date_created', $properties );
}
}
/**
* Track order actions taken.
*
* @param int $order_id Order ID.
*/
public function track_order_action( $order_id ) {
// phpcs:disable WordPress.Security.NonceVerification
if ( ! empty( $_POST['wc_order_action'] ) ) {
$order = wc_get_order( $order_id );
$action = wc_clean( wp_unslash( $_POST['wc_order_action'] ) );
$properties = array(
'order_id' => $order_id,
'status' => $order->get_status(),
'action' => $action,
);
WC_Tracks::record_event( 'order_edit_order_action', $properties );
}
// phpcs:enable
}
/**
* Track "add order" button on the Edit Order screen.
*/
public function track_add_order_from_edit() {
if ( ! OrderUtil::is_new_order_screen() ) {
return;
}
$referer = wp_get_referer();
if ( ! $referer ) {
return;
}
$referring_page = wp_parse_url( $referer );
if ( empty( $referring_page['query'] ) ) {
// Edit Order screen has query args.
return;
}
parse_str( $referring_page['query'], $referring_args );
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
$post_edit_page = admin_url( 'admin.php?page=wc-orders' );
$order_id = $referring_args['id'] ?? 0;
} else {
$post_edit_page = admin_url( 'post.php' );
$order_id = $referring_args['post'] ?? 0;
}
$post_edit_page = wp_parse_url( $post_edit_page );
if (
( $post_edit_page['path'] === $referring_page['path'] ) &&
( ! isset( $post_edit_page['query'] ) || false !== strpos( $referring_page['query'], $post_edit_page['query'] ) ) &&
( isset( $referring_args['action'] ) && 'edit' === $referring_args['action'] ) &&
'shop_order' === OrderUtil::get_order_type( $order_id )
) {
WC_Tracks::record_event( 'order_edit_add_order' );
}
}
/**
* Adds the tracking scripts for product setting pages.
*/
public function possibly_add_order_tracking_scripts() {
if ( ! OrderUtil::is_new_order_screen() && ! OrderUtil::is_order_edit_screen() && ! OrderUtil::is_order_list_table_screen() ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'order-tracking', false );
}
}

View File

@@ -1,549 +0,0 @@
<?php
/**
* WooCommerce Import Tracking
*
* @package WooCommerce\Tracks
*/
use Automattic\Jetpack\Constants;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
defined( 'ABSPATH' ) || exit;
require_once WC_ABSPATH . 'includes/admin/wc-admin-functions.php';
/**
* This class adds actions to track usage of WooCommerce Products.
*/
class WC_Products_Tracking {
/**
* Tracks source.
*/
const TRACKS_SOURCE = 'product-legacy-editor';
/**
* Init tracking.
*/
public function init() {
add_action( 'load-edit.php', array( $this, 'track_products_view' ), 10 );
add_action( 'load-edit-tags.php', array( $this, 'track_categories_and_tags_view' ), 10, 2 );
add_action( 'edit_post', array( $this, 'track_product_updated' ), 10, 2 );
add_action( 'wp_after_insert_post', array( $this, 'track_product_published' ), 10, 4 );
add_action( 'created_product_cat', array( $this, 'track_product_category_created' ) );
add_action( 'edited_product_cat', array( $this, 'track_product_category_updated' ) );
add_action( 'add_meta_boxes_product', array( $this, 'track_product_updated_client_side' ), 10 );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_product_tracking_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_product_import_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_attribute_tracking_scripts' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_tag_tracking_scripts' ) );
}
/**
* Send a Tracks event when the Products page is viewed.
*/
public function track_products_view() {
// We only record Tracks event when no `_wp_http_referer` query arg is set, since
// when searching, the request gets sent from the browser twice,
// once with the `_wp_http_referer` and once without it.
//
// Otherwise, we would double-record the view and search events.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
isset( $_GET['post_type'] )
&& 'product' === wp_unslash( $_GET['post_type'] )
&& ! isset( $_GET['_wp_http_referer'] )
) {
// phpcs:enable
WC_Tracks::record_event( 'products_view' );
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
isset( $_GET['s'] )
&& 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) )
) {
// phpcs:enable
WC_Tracks::record_event( 'products_search' );
}
}
}
/**
* Send a Tracks event when the Products Categories and Tags page is viewed.
*/
public function track_categories_and_tags_view() {
// We only record Tracks event when no `_wp_http_referer` query arg is set, since
// when searching, the request gets sent from the browser twice,
// once with the `_wp_http_referer` and once without it.
//
// Otherwise, we would double-record the view and search events.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
isset( $_GET['post_type'] )
&& 'product' === wp_unslash( $_GET['post_type'] )
&& isset( $_GET['taxonomy'] )
&& ! isset( $_GET['_wp_http_referer'] )
) {
$taxonomy = wp_unslash( $_GET['taxonomy'] );
// phpcs:enable
if ( 'product_cat' === $taxonomy ) {
WC_Tracks::record_event( 'categories_view' );
} elseif ( 'product_tag' === $taxonomy ) {
WC_Tracks::record_event( 'tags_view' );
}
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
isset( $_GET['s'] )
&& 0 < strlen( sanitize_text_field( wp_unslash( $_GET['s'] ) ) )
) {
// phpcs:enable
if ( 'product_cat' === $taxonomy ) {
WC_Tracks::record_event( 'categories_search' );
} elseif ( 'product_tag' === $taxonomy ) {
WC_Tracks::record_event( 'tags_search' );
}
}
}
}
/**
* Send a Tracks event when a product is updated.
*
* @param int $product_id Product id.
* @param object $post WordPress post.
*/
public function track_product_updated( $product_id, $post ) {
if ( 'product' !== $post->post_type ) {
return;
}
/* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
$source = apply_filters( 'woocommerce_product_source', self::TRACKS_SOURCE );
$properties = array(
'product_id' => $product_id,
'source' => $source,
);
/* phpcs: enable */
WC_Tracks::record_event( 'product_edit', $properties );
}
/**
* Track the Update button being clicked on the client side.
* This is needed because `track_product_updated` (using the `edit_post`
* hook) is called in response to a number of other triggers.
*
* @param WP_Post $post The post, not used.
*/
public function track_product_updated_client_side( $post ) {
wc_enqueue_js(
"
if ( $( 'h1.wp-heading-inline' ).text().trim() === '" . __( 'Edit product', 'woocommerce' ) . "') {
var initialStockValue = $( '#_stock' ).val();
var isBlockEditor = false;
var child_element = '#publish';
if ( $( '.block-editor' ).length !== 0 && $( '.block-editor' )[0] ) {
isBlockEditor = true;
}
if ( isBlockEditor ) {
child_element = '.editor-post-publish-button';
}
$( '#wpwrap' ).on( 'click', child_element, function() {
var description_value = '';
var tagsText = '';
var currentStockValue = $( '#_stock' ).val();
function getProductTypeOptions() {
const productTypeOptionsCheckboxes = $( 'input[type=\"checkbox\"][data-product-type-option-id]' );
const productTypeOptions = productTypeOptionsCheckboxes.map( function() {
return {
id: $( this ).data( 'product-type-option-id' ),
isEnabled: $( this ).is( ':checked' ),
};
} ).get();
return productTypeOptions;
}
function getProductTypeOptionsString( productTypeOptions ) {
return productTypeOptions
.filter( productTypeOption => productTypeOption.isEnabled )
.map( productTypeOption => productTypeOption.id )
.join( ', ' );
}
const productTypeOptions = getProductTypeOptions();
const productTypeOptionsString = getProductTypeOptionsString( productTypeOptions );
if ( ! isBlockEditor ) {
tagsText = $( '[name=\"tax_input[product_tag]\"]' ).val();
if ( $( '#content' ).is( ':visible' ) ) {
description_value = $( '#content' ).val();
} else if ( typeof tinymce === 'object' && tinymce.get( 'content' ) ) {
description_value = tinymce.get( 'content' ).getContent();
}
} else {
description_value = $( '.block-editor-rich-text__editable' ).text();
}
// We can't just check the number of '.woocommerce_attribute' elements because
// there might be empty ones, which get stripped out when saved. So, we'll check
// whether the name and values have been filled out.
var numberOfAttributes = $( '.woocommerce_attribute' ).filter( function () {
var attributeElement = $( this );
var attributeName = attributeElement.find( 'input.attribute_name' ).val();
var attributeValues = attributeElement.find( 'textarea[name^=\"attribute_values\"]' ).val();
return attributeName !== '' && attributeValues !== '';
} ).length;
var properties = {
attributes: numberOfAttributes,
categories: $( '[name=\"tax_input[product_cat][]\"]:checked' ).length,
cross_sells: $( '#crosssell_ids option' ).length ? 'Yes' : 'No',
description: description_value.trim() !== '' ? 'Yes' : 'No',
enable_reviews: $( '#comment_status' ).is( ':checked' ) ? 'Yes' : 'No',
is_virtual: $( '#_virtual' ).is( ':checked' ) ? 'Yes' : 'No',
is_block_editor: isBlockEditor,
is_downloadable: $( '#_downloadable' ).is( ':checked' ) ? 'Yes' : 'No',
manage_stock: $( '#_manage_stock' ).is( ':checked' ) ? 'Yes' : 'No',
menu_order: parseInt( $( '#menu_order' ).val(), 10 ) !== 0 ? 'Yes' : 'No',
product_gallery: $( '#product_images_container .product_images > li' ).length,
product_image: $( '#_thumbnail_id' ).val() > 0 ? 'Yes' : 'No',
product_type: $( '#product-type' ).val(),
product_type_options_string: productTypeOptionsString,
purchase_note: $( '#_purchase_note' ).val().length ? 'yes' : 'no',
sale_price: $( '#_sale_price' ).val() ? 'yes' : 'no',
short_description: $( '#excerpt' ).val().length ? 'yes' : 'no',
stock_quantity_update: ( initialStockValue != currentStockValue ) ? 'Yes' : 'No',
tags: tagsText.length > 0 ? tagsText.split( ',' ).length : 0,
upsells: $( '#upsell_ids option' ).length ? 'Yes' : 'No',
weight: $( '#_weight' ).val() ? 'Yes' : 'No',
};
window.wcTracks.recordEvent( 'product_update', properties );
} );
}
"
);
}
/**
* Get the IDs of the possible product type options.
*
* @return array
*/
private static function get_possible_product_type_options_ids() {
$product_type_options_ids =
array_values(
array_map(
function ( $product_type_option ) {
return $product_type_option['id'];
},
/* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
apply_filters(
'product_type_options',
wc_get_default_product_type_options(),
)
/* phpcs: enable */
)
);
return $product_type_options_ids;
}
/**
* Get the product type options for a product.
*
* @param int $post_id The ID of the product.
*
* @return array
*/
private static function get_product_type_options( $post_id ) {
$possible_product_type_options_ids = self::get_possible_product_type_options_ids();
$post_meta = get_post_meta( $post_id );
$product_type_options = array();
foreach ( $possible_product_type_options_ids as $product_type_option_id ) {
$product_type_options[ $product_type_option_id ] = isset( $post_meta[ $product_type_option_id ] ) ? $post_meta[ $product_type_option_id ][0] : 'no';
}
return $product_type_options;
}
/**
* Get a comma-separated string of the product type options that are enabled.
*
* @param array $product_type_options The product type options.
*
* @return string
*/
private static function get_product_type_options_string( $product_type_options ) {
return implode(
', ',
array_keys(
array_filter(
$product_type_options,
function ( $is_enabled ) {
return 'yes' === $is_enabled;
}
)
)
);
}
/**
* Send a Tracks event when a product is published.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
* @param bool $update Whether this is an existing post being updated.
* @param null|WP_Post $post_before Null for new posts, the WP_Post object prior
* to the update for updated posts.
*/
public function track_product_published( $post_id, $post, $update, $post_before ) {
if (
'product' !== $post->post_type ||
'publish' !== $post->post_status ||
( $post_before && 'publish' === $post_before->post_status )
) {
return;
}
$product = wc_get_product( $post_id );
$product_type_options = self::get_product_type_options( $post_id );
$product_type_options_string = self::get_product_type_options_string( $product_type_options );
$properties = array(
'attributes' => count( $product->get_attributes() ),
'categories' => count( $product->get_category_ids() ),
'cross_sells' => ! empty( $product->get_cross_sell_ids() ) ? 'yes' : 'no',
'description' => $product->get_description() ? 'yes' : 'no',
'dimensions' => wc_format_dimensions( $product->get_dimensions( false ) ) !== 'N/A' ? 'yes' : 'no',
'enable_reviews' => $product->get_reviews_allowed() ? 'yes' : 'no',
'is_downloadable' => $product->is_downloadable() ? 'yes' : 'no',
'is_virtual' => $product->is_virtual() ? 'yes' : 'no',
'manage_stock' => $product->get_manage_stock() ? 'yes' : 'no',
'menu_order' => $product->get_menu_order() ? 'yes' : 'no',
'product_id' => $post_id,
'product_gallery' => count( $product->get_gallery_image_ids() ),
'product_image' => $product->get_image_id() ? 'yes' : 'no',
'product_type' => $product->get_type(),
'product_type_options' => $product_type_options_string,
'purchase_note' => $product->get_purchase_note() ? 'yes' : 'no',
'sale_price' => $product->get_sale_price() ? 'yes' : 'no',
'source' => apply_filters( 'woocommerce_product_source', self::TRACKS_SOURCE ),
'short_description' => $product->get_short_description() ? 'yes' : 'no',
'tags' => count( $product->get_tag_ids() ),
'upsells' => ! empty( $product->get_upsell_ids() ) ? 'yes' : 'no',
'weight' => $product->get_weight() ? 'yes' : 'no',
);
WC_Tracks::record_event( 'product_add_publish', $properties );
}
/**
* Send a Tracks event when a product category is created.
*
* @param int $category_id Category ID.
*/
public function track_product_category_created( $category_id ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// Only track category creation from the edit product screen or the
// category management screen (which both occur via AJAX).
if (
! Constants::is_defined( 'DOING_AJAX' ) ||
empty( $_POST['action'] ) ||
(
// Product Categories screen.
'add-tag' !== $_POST['action'] &&
// Edit Product screen.
'add-product_cat' !== $_POST['action']
)
) {
return;
}
$category = get_term( $category_id, 'product_cat' );
$parent_category = $category->parent > 0 ? 'Other' : 'None';
if ( $category->parent > 0 ) {
$parent = get_term( $category_id, 'product_cat' );
if ( 'uncategorized' === $parent->name ) {
$parent_category = 'Uncategorized';
}
}
$properties = array(
'category_id' => $category_id,
'parent_id' => $category->parent,
'parent_category' => $parent_category,
'page' => ( 'add-tag' === $_POST['action'] ) ? 'categories' : 'product',
'display_type' => isset( $_POST['display_type'] ) ? wp_unslash( $_POST['display_type'] ) : '',
'image' => isset( $_POST['product_cat_thumbnail_id'] ) && '' !== $_POST['product_cat_thumbnail_id'] ? 'Yes' : 'No',
);
// phpcs:enable
WC_Tracks::record_event( 'product_category_add', $properties );
}
/**
* Send a Tracks event when a product category is updated.
*
* @param int $category_id Category ID.
*/
public function track_product_category_updated( $category_id ) {
// phpcs:disable WordPress.Security.NonceVerification.Missing
// Only track category creation from the edit product screen or the
// category management screen (which both occur via AJAX).
if (
empty( $_POST['action'] ) ||
( 'editedtag' !== $_POST['action'] && 'inline-save-tax' !== $_POST['action'] )
) {
return;
}
// phpcs:enable
WC_Tracks::record_event( 'product_category_update' );
}
/**
* Adds the tracking scripts for product filtering actions.
*
* @param string $hook Hook of the current page.
* @return string|boolean
*/
protected function get_product_screen( $hook ) {
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
'edit.php' === $hook &&
isset( $_GET['post_type'] ) &&
'product' === wp_unslash( $_GET['post_type'] )
) {
return 'list';
}
if (
'post-new.php' === $hook &&
isset( $_GET['post_type'] ) &&
'product' === wp_unslash( $_GET['post_type'] )
) {
return 'new';
}
if (
'post.php' === $hook &&
isset( $_GET['post'] ) &&
'product' === get_post_type( intval( $_GET['post'] ) )
) {
return 'edit';
}
if ( 'product_page_product_importer' === $hook ) {
return 'import';
}
// phpcs:enable
return false;
}
/**
* Adds the tracking scripts for product filtering actions.
*
* @param string $hook Page hook.
*/
public function possibly_add_product_tracking_scripts( $hook ) {
$product_screen = $this->get_product_screen( $hook );
if ( ! $product_screen ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'product-tracking', false );
wp_localize_script(
'wc-admin-product-tracking',
'productScreen',
array(
'name' => $product_screen,
)
);
}
/**
* Adds the tracking scripts for product setting pages.
*
* @param string $hook Page hook.
*/
public function possibly_add_product_import_scripts( $hook ) {
$product_screen = $this->get_product_screen( $hook );
if ( 'import' !== $product_screen ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'product-import-tracking', false );
}
/**
* Adds the tracking scripts for product attributes filtering actions.
*
* @param string $hook Page hook.
*/
public function possibly_add_attribute_tracking_scripts( $hook ) {
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
'product_page_product_attributes' !== $hook ||
! isset( $_GET['page'] ) ||
'product_attributes' !== wp_unslash( $_GET['page'] )
) {
return;
}
// phpcs:enable
WCAdminAssets::register_script( 'wp-admin-scripts', 'attributes-tracking', false );
}
/**
* Adds the tracking scripts for tags and categories filtering actions.
*
* @param string $hook Page hook.
*/
public function possibly_add_tag_tracking_scripts( $hook ) {
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
'edit-tags.php' !== $hook ||
! isset( $_GET['post_type'] ) ||
'product' !== wp_unslash( $_GET['post_type'] )
) {
return;
}
// phpcs:enable
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if (
isset( $_GET['taxonomy'] ) &&
'product_tag' === wp_unslash( $_GET['taxonomy'] )
) {
WCAdminAssets::register_script( 'wp-admin-scripts', 'tags-tracking', false );
return;
}
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if (
isset( $_GET['taxonomy'] ) &&
'product_cat' === wp_unslash( $_GET['taxonomy'] )
) {
WCAdminAssets::register_script( 'wp-admin-scripts', 'category-tracking', false );
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'add-term-tracking', false );
}
}

View File

@@ -1,244 +0,0 @@
<?php
/**
* WooCommerce Settings Tracking
*
* @package WooCommerce\Tracks
*/
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce Settings.
*/
class WC_Settings_Tracking {
/**
* List of allowed WooCommerce settings to potentially track updates for.
*
* @var array
*/
protected $allowed_options = array();
/**
* WooCommerce settings that have been updated (and will be tracked).
*
* @var array
*/
protected $updated_options = array();
/**
* List of option names that are dropdown menus.
*
* @var array
*/
protected $dropdown_menu_options = array();
/**
* List of options that have been modified.
*
* @var array
*/
protected $modified_options = array();
/**
* List of options that have been deleted.
*
* @var array
*/
protected $deleted_options = array();
/**
* List of options that have been added.
*
* @var array
*/
protected $added_options = array();
/**
* Toggled options.
*
* @var array
*/
protected $toggled_options = array(
'enabled' => array(),
'disabled' => array(),
);
/**
* Init tracking.
*/
public function init() {
add_action( 'woocommerce_settings_page_init', array( $this, 'track_settings_page_view' ) );
add_action( 'woocommerce_update_option', array( $this, 'add_option_to_list' ) );
add_action( 'woocommerce_update_non_option_setting', array( $this, 'add_option_to_list_and_track_setting_change' ) );
add_action( 'woocommerce_update_options', array( $this, 'send_settings_change_event' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_settings_tracking_scripts' ) );
}
/**
* Adds the option to the allowed and updated options directly.
* Currently used for settings that don't use update_option.
*
* @param array $option WooCommerce option that should be updated.
*/
public function add_option_to_list_and_track_setting_change( $option ) {
if ( ! in_array( $option['id'], $this->allowed_options, true ) ) {
$this->allowed_options[] = $option['id'];
}
if ( isset( $option['action'] ) ) {
if ( 'add' === $option['action'] ) {
$this->added_options[] = $option['id'];
} elseif ( 'delete' === $option['action'] ) {
$this->deleted_options[] = $option['id'];
} elseif ( ! in_array( $option['id'], $this->updated_options, true ) ) {
$this->updated_options[] = $option['id'];
}
} elseif ( isset( $option['value'] ) ) {
if ( 'select' === $option['type'] ) {
$this->modified_options[ $option['id'] ] = $option['value'];
} elseif ( 'checkbox' === $option['type'] ) {
$option_state = 'yes' === $option['value'] ? 'enabled' : 'disabled';
$this->toggled_options[ $option_state ][] = $option['id'];
}
$this->updated_options[] = $option['id'];
}
}
/**
* Add a WooCommerce option name to our allowed options list and attach
* the `update_option` hook. Rather than inspecting every updated
* option and pattern matching for "woocommerce", just build a dynamic
* list for WooCommerce options that might get updated.
*
* See `woocommerce_update_option` hook.
*
* @param array $option WooCommerce option (config) that might get updated.
*/
public function add_option_to_list( $option ) {
$this->allowed_options[] = $option['id'];
if ( isset( $option['options'] ) ) {
$this->dropdown_menu_options[] = $option['id'];
}
// Delay attaching this action since it could get fired a lot.
if ( false === has_action( 'update_option', array( $this, 'track_setting_change' ) ) ) {
add_action( 'update_option', array( $this, 'track_setting_change' ), 10, 3 );
}
}
/**
* Add WooCommerce option to a list of updated options.
*
* @param string $option_name Option being updated.
* @param mixed $old_value Old value of option.
* @param mixed $new_value New value of option.
*/
public function track_setting_change( $option_name, $old_value, $new_value ) {
// Make sure this is a WooCommerce option.
if ( ! in_array( $option_name, $this->allowed_options, true ) ) {
return;
}
// Check to make sure the new value is truly different.
// `woocommerce_price_num_decimals` tends to trigger this
// because form values aren't coerced (e.g. '2' vs. 2).
if (
is_scalar( $old_value ) &&
is_scalar( $new_value ) &&
(string) $old_value === (string) $new_value
) {
return;
}
if ( in_array( $option_name, $this->dropdown_menu_options, true ) ) {
$this->modified_options[ $option_name ] = $new_value;
} elseif ( in_array( $new_value, array( 'yes', 'no' ), true ) && in_array( $old_value, array( 'yes', 'no' ), true ) ) {
// Save toggled options.
$option_state = 'yes' === $new_value ? 'enabled' : 'disabled';
$this->toggled_options[ $option_state ][] = $option_name;
}
$this->updated_options[] = $option_name;
}
/**
* Send a Tracks event for WooCommerce options that changed values.
*/
public function send_settings_change_event() {
global $current_tab, $current_section;
if ( empty( $this->updated_options ) && empty( $this->deleted_options ) && empty( $this->added_options ) ) {
return;
}
$properties = array();
if ( ! empty( $this->updated_options ) ) {
$properties['settings'] = implode( ',', $this->updated_options );
}
if ( ! empty( $this->deleted_options ) ) {
$properties['deleted'] = implode( ',', $this->deleted_options );
}
if ( ! empty( $this->added_options ) ) {
$properties['added'] = implode( ',', $this->added_options );
}
foreach ( $this->toggled_options as $state => $options ) {
if ( ! empty( $options ) ) {
$properties[ $state ] = implode( ',', $options );
}
}
if ( ! empty( $this->modified_options ) ) {
foreach ( $this->modified_options as $option_name => $selected_option ) {
$properties[ $option_name ] = $selected_option ?? '';
}
}
$properties['tab'] = $current_tab ?? '';
$properties['section'] = $current_section ?? '';
WC_Tracks::record_event( 'settings_change', $properties );
}
/**
* Send a Tracks event for WooCommerce settings page views.
*/
public function track_settings_page_view() {
global $current_tab, $current_section;
$properties = array(
'tab' => $current_tab,
'section' => empty( $current_section ) ? null : $current_section,
);
WC_Tracks::record_event( 'settings_view', $properties );
}
/**
* Adds the tracking scripts for product setting pages.
*
* @param string $hook Page hook.
*/
public function possibly_add_settings_tracking_scripts( $hook ) {
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification
if (
! isset( $_GET['page'] ) ||
'wc-settings' !== wp_unslash( $_GET['page'] )
) {
return;
}
// phpcs:enable
WCAdminAssets::register_script( 'wp-admin-scripts', 'settings-tracking', false );
}
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* WooCommerce Status Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of WooCommerce Orders.
*/
class WC_Status_Tracking {
/**
* Init tracking.
*/
public function init() {
add_action( 'admin_init', array( $this, 'track_status_view' ), 10 );
}
/**
* Add Tracks events to the status page.
*/
public function track_status_view() {
if ( isset( $_GET['page'] ) && 'wc-status' === sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) {
$tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'status';
WC_Tracks::record_event(
'status_view',
array(
'tab' => $tab,
'tool_used' => isset( $_GET['action'] ) ? sanitize_text_field( wp_unslash( $_GET['action'] ) ) : null,
)
);
if ( 'status' === $tab ) {
wc_enqueue_js(
"
$( 'a.debug-report' ).on( 'click', function() {
window.wcTracks.recordEvent( 'status_view_reports' );
} );
"
);
}
}
}
}

View File

@@ -1,56 +0,0 @@
<?php
/**
* WooCommerce Theme Tracking
*
* @package WooCommerce\Tracks
*/
defined( 'ABSPATH' ) || exit;
/**
* This class adds actions to track usage of themes on a WooCommerce store.
*/
class WC_Theme_Tracking {
/**
* Init tracking.
*/
public function init() {
$this->track_initial_theme();
add_action( 'switch_theme', array( $this, 'track_activated_theme' ) );
}
/**
* Tracks the sites current theme the first time this code is run, and will only be run once.
*/
public function track_initial_theme() {
$has_been_initially_tracked = get_option( 'wc_has_tracked_default_theme' );
if ( $has_been_initially_tracked ) {
return;
}
$this->track_activated_theme();
add_option( 'wc_has_tracked_default_theme', 1 );
}
/**
* Send a Tracks event when a theme is activated so that we can track active block themes.
*/
public function track_activated_theme() {
$is_block_theme = false;
$theme_object = wp_get_theme();
if ( function_exists( 'wc_current_theme_is_fse_theme' ) ) {
$is_block_theme = wc_current_theme_is_fse_theme();
}
$properties = array(
'block_theme' => $is_block_theme,
'theme_name' => $theme_object->get( 'Name' ),
'theme_version' => $theme_object->get( 'Version' ),
);
WC_Tracks::record_event( 'activated_theme', $properties );
}
}