events
6 months ago
class-wc-site-tracking.php
6 months ago
class-wc-tracks-client.php
4 months ago
class-wc-tracks-event.php
4 months ago
class-wc-tracks-footer-pixel.php
1 year ago
class-wc-tracks.php
4 months ago
class-wc-tracks.php
202 lines
| 1 | <?php |
| 2 | /** |
| 3 | * PHP Tracks Client |
| 4 | * |
| 5 | * @package WooCommerce\Tracks |
| 6 | */ |
| 7 | |
| 8 | /** |
| 9 | * WC_Tracks class. |
| 10 | */ |
| 11 | class WC_Tracks { |
| 12 | |
| 13 | /** |
| 14 | * Tracks event name prefix. |
| 15 | */ |
| 16 | const PREFIX = 'wcadmin_'; |
| 17 | |
| 18 | /** |
| 19 | * Get total product counts. |
| 20 | * |
| 21 | * @return int Number of products. |
| 22 | */ |
| 23 | public static function get_products_count() { |
| 24 | $product_counts = WC_Tracker::get_product_counts(); |
| 25 | return $product_counts['total']; |
| 26 | } |
| 27 | |
| 28 | /** |
| 29 | * Gather blog related properties. |
| 30 | * |
| 31 | * @param int $user_id User id. |
| 32 | * @return array Blog details. |
| 33 | */ |
| 34 | public static function get_blog_details( $user_id ) { |
| 35 | $blog_details = get_transient( 'wc_tracks_blog_details' ); |
| 36 | if ( false === $blog_details ) { |
| 37 | // Ensure the store ID is set. |
| 38 | if ( ! class_exists( '\WC_Install' ) ) { |
| 39 | include_once WC_ABSPATH . 'includes/class-wc-install.php'; |
| 40 | } |
| 41 | \WC_Install::maybe_set_store_id(); |
| 42 | |
| 43 | $blog_details = array( |
| 44 | 'url' => home_url(), |
| 45 | 'blog_lang' => get_user_locale( $user_id ), |
| 46 | 'blog_id' => class_exists( 'Jetpack_Options' ) ? Jetpack_Options::get_option( 'id' ) : null, |
| 47 | 'store_id' => get_option( \WC_Install::STORE_ID_OPTION, null ), |
| 48 | 'products_count' => self::get_products_count(), |
| 49 | 'wc_version' => WC()->stable_version(), |
| 50 | ); |
| 51 | set_transient( 'wc_tracks_blog_details', $blog_details, DAY_IN_SECONDS ); |
| 52 | } |
| 53 | return $blog_details; |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Gather details from the request to the server. |
| 58 | * |
| 59 | * @return array Server details. |
| 60 | */ |
| 61 | public static function get_server_details() { |
| 62 | $data = array(); |
| 63 | |
| 64 | $data['_via_ua'] = isset( $_SERVER['HTTP_USER_AGENT'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; |
| 65 | $data['_via_ip'] = isset( $_SERVER['REMOTE_ADDR'] ) ? wc_clean( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : ''; |
| 66 | $data['_lg'] = isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) : ''; |
| 67 | $data['_dr'] = isset( $_SERVER['HTTP_REFERER'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : ''; |
| 68 | |
| 69 | $uri = isset( $_SERVER['REQUEST_URI'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : ''; |
| 70 | $host = isset( $_SERVER['HTTP_HOST'] ) ? wc_clean( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : ''; |
| 71 | $data['_dl'] = isset( $_SERVER['REQUEST_SCHEME'] ) ? wc_clean( wp_unslash( $_SERVER['REQUEST_SCHEME'] ) ) . '://' . $host . $uri : ''; |
| 72 | |
| 73 | return $data; |
| 74 | } |
| 75 | |
| 76 | /** |
| 77 | * Get role-related details. |
| 78 | * |
| 79 | * @param WP_User $user The user object. |
| 80 | * @return array The role details. |
| 81 | */ |
| 82 | public static function get_role_details( $user ) { |
| 83 | return array( |
| 84 | 'role' => ! empty( $user->roles ) ? array_values( $user->roles )[0] : '', |
| 85 | 'can_install_plugins' => $user->has_cap( 'install_plugins' ), |
| 86 | 'can_activate_plugins' => $user->has_cap( 'activate_plugins' ), |
| 87 | 'can_manage_woocommerce' => $user->has_cap( 'manage_woocommerce' ), |
| 88 | ); |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Record an event in Tracks - this is the preferred way to record events from PHP. |
| 93 | * Note: the event request won't be made if $properties has a member called `error`. |
| 94 | * |
| 95 | * Array values in event properties are automatically converted to prevent invalid property names: |
| 96 | * - Indexed arrays (e.g., ['a', 'b', 'c']) become comma-separated strings: 'a,b,c' |
| 97 | * - Associative arrays (e.g., ['key' => 'val']) become JSON strings: '{"key":"val"}' |
| 98 | * - Empty arrays become empty strings |
| 99 | * |
| 100 | * Examples: |
| 101 | * // Indexed array - becomes comma-separated string |
| 102 | * WC_Tracks::record_event( 'checkout_viewed', array( |
| 103 | * 'blocks' => array( 'woocommerce/cart-items', 'woocommerce/checkout-totals' ) |
| 104 | * ) ); |
| 105 | * // Results in: blocks=woocommerce%2Fcart-items%2Cwoocommerce%2Fcheckout-totals |
| 106 | * |
| 107 | * // Associative array - becomes JSON string |
| 108 | * WC_Tracks::record_event( 'settings_changed', array( |
| 109 | * 'options' => array( 'enabled' => true, 'count' => 5 ) |
| 110 | * ) ); |
| 111 | * // Results in: options=%7B%22enabled%22%3Atrue%2C%22count%22%3A5%7D |
| 112 | * |
| 113 | * For complex structures, consider explicitly JSON-encoding before passing to record_event(). |
| 114 | * |
| 115 | * @param string $event_name The name of the event. |
| 116 | * @param array $event_properties Custom properties to send with the event. |
| 117 | * @return bool|WP_Error True for success or WP_Error if the event pixel could not be fired. |
| 118 | */ |
| 119 | public static function record_event( $event_name, $event_properties = array() ) { |
| 120 | /** |
| 121 | * Don't track users who don't have tracking enabled. |
| 122 | */ |
| 123 | if ( ! WC_Site_Tracking::is_tracking_enabled() ) { |
| 124 | return false; |
| 125 | } |
| 126 | |
| 127 | $user = wp_get_current_user(); |
| 128 | |
| 129 | // We don't want to track user events during unit tests/CI runs. |
| 130 | if ( $user instanceof WP_User && 'wptests_capabilities' === $user->cap_key ) { |
| 131 | return false; |
| 132 | } |
| 133 | $prefixed_event_name = self::PREFIX . $event_name; |
| 134 | $properties = self::get_properties( $prefixed_event_name, $event_properties ); |
| 135 | $event_obj = new WC_Tracks_Event( $properties ); |
| 136 | |
| 137 | if ( is_wp_error( $event_obj->error ) ) { |
| 138 | return $event_obj->error; |
| 139 | } |
| 140 | |
| 141 | return $event_obj->record(); |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * Track when the user attempts to toggle |
| 146 | * woocommerce_allow_tracking option. |
| 147 | * |
| 148 | * @since x.x.x |
| 149 | * |
| 150 | * @param string $prev_value The previous value for the setting. 'yes' or 'no'. |
| 151 | * @param string $new_value The new value for the setting. 'yes' or 'no'. |
| 152 | * @param string $context Which avenue the user utilized to toggle. |
| 153 | */ |
| 154 | public static function track_woocommerce_allow_tracking_toggled( $prev_value, $new_value, $context = 'settings' ) { |
| 155 | if ( $new_value !== $prev_value ) { |
| 156 | self::record_event( |
| 157 | 'woocommerce_allow_tracking_toggled', |
| 158 | array( |
| 159 | 'previous_value' => $prev_value, |
| 160 | 'new_value' => $new_value, |
| 161 | 'context' => $context, |
| 162 | ) |
| 163 | ); |
| 164 | } |
| 165 | } |
| 166 | |
| 167 | /** |
| 168 | * Get all properties for the event including filtered and identity properties. |
| 169 | * |
| 170 | * @param string $event_name Event name. |
| 171 | * @param array $event_properties Event specific properties. |
| 172 | * @return array |
| 173 | */ |
| 174 | public static function get_properties( $event_name, $event_properties ) { |
| 175 | /** |
| 176 | * Allow event props to be filtered to enable adding site-wide props. |
| 177 | * |
| 178 | * @since 4.1.0 |
| 179 | */ |
| 180 | $properties = apply_filters( 'woocommerce_tracks_event_properties', $event_properties, $event_name ); |
| 181 | $user = wp_get_current_user(); |
| 182 | $identity = WC_Tracks_Client::get_identity( $user->ID ); |
| 183 | |
| 184 | // Delete _ui and _ut protected properties. |
| 185 | unset( $properties['_ui'] ); |
| 186 | unset( $properties['_ut'] ); |
| 187 | |
| 188 | $data = $event_name |
| 189 | ? array( |
| 190 | '_en' => $event_name, |
| 191 | '_ts' => WC_Tracks_Client::build_timestamp(), |
| 192 | ) |
| 193 | : array(); |
| 194 | |
| 195 | $server_details = self::get_server_details(); |
| 196 | $blog_details = self::get_blog_details( $user->ID ); |
| 197 | $role_details = self::get_role_details( $user ); |
| 198 | |
| 199 | return array_merge( $properties, $data, $server_details, $identity, $blog_details, $role_details ); |
| 200 | } |
| 201 | } |
| 202 |