Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
86.59% covered (warning)
86.59%
71 / 82
42.86% covered (danger)
42.86%
3 / 7
CRAP
n/a
0 / 0
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\wpcom_nosara_track_admin_page_views
97.37% covered (success)
97.37%
37 / 38
0.00% covered (danger)
0.00%
0 / 1
15
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\wpcom_maybe_track_customizer
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\wpcom_track_customizer_from_frontend
95.00% covered (success)
95.00%
19 / 20
0.00% covered (danger)
0.00%
0 / 1
9
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\do_not_track_a11ns
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
4
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\wpcom_atomic_maybe_is_a11n
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\wpcom_atomic_get_user_types
77.78% covered (warning)
77.78%
7 / 9
0.00% covered (danger)
0.00%
0 / 1
4.18
Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View\get_account_age_in_days
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * WPCom Tracking for WP Admin Page Views.
4 *
5 * @package automattic/jetpack-mu-wpcom
6 */
7
8namespace Automattic\Jetpack\Jetpack_Mu_Wpcom\Wpcom_Wpadmin_Page_View;
9
10use WPCOMSH_Support_Session_Detect;
11
12/**
13 * Bump a Tracks stat for every wp-admin page view not generated by an Automattician.
14 * This is possibly interesting on its own but will also be used as part of an
15 * initiative to understand how much supply we're offering for live chat demand.
16 * See https://nosaraproject.wordpress.com/2015/03/06/live-chat-stats/
17 */
18function wpcom_nosara_track_admin_page_views() {
19    if ( do_not_track_a11ns() ) {
20        return;
21    }
22
23    $is_simple_site = defined( 'IS_WPCOM' ) && IS_WPCOM;
24    $is_atomic_site = ! $is_simple_site;
25
26    global $current_user, $current_blog, $current_screen;
27
28    if (
29        ! $current_user instanceof \WP_User ||
30        ! $current_screen instanceof \WP_Screen
31    ) {
32        return;
33    }
34
35    $blog_id    = null;
36    $user_types = array();
37
38    if ( $is_simple_site ) {
39        if ( ! $current_blog instanceof \WP_Site ) {
40            return;
41        }
42
43        $blog_id    = $current_blog->blog_id;
44        $user_types = \WPCOM_User::get_types();
45    }
46
47    if ( $is_atomic_site ) {
48        $blog_id    = _wpcom_get_current_blog_id();
49        $user_types = wpcom_atomic_get_user_types();
50    }
51
52    $wpcom_user_id   = $is_simple_site
53        ? absint( $current_user->ID )
54        : (int) get_user_meta( absint( $current_user->ID ), 'wpcom_user_id', true );
55    $wpcom_user_data = $is_simple_site ? null : get_user_meta( absint( $current_user->ID ), 'wpcom_user_data', true );
56    $user_login      = (int) ( $wpcom_user_data->ID ?? 0 ) === $wpcom_user_id && ! empty( $wpcom_user_data->login )
57        ? $wpcom_user_data->login
58        : $current_user->user_login;
59    ?>
60    <script type="text/javascript">
61        var _admin_pv_props = {
62            from_page: <?php echo wp_json_encode( $current_screen->id, JSON_HEX_TAG ); ?>,
63            is_block_editor: '<?php echo $current_screen->is_block_editor ? 'true' : 'false'; ?>',
64            source: 'wp-admin',
65            blog_id: <?php echo wp_json_encode( (string) $blog_id, JSON_HEX_TAG ); ?>,
66            user_type: <?php echo wp_json_encode( implode( ',', $user_types ), JSON_HEX_TAG ); ?>,
67            is_local_only_user: <?php echo 0 === $wpcom_user_id ? 'true' : 'false'; ?>
68        };
69        _tkq = window._tkq || [];
70        <?php if ( $wpcom_user_id > 0 ) : ?>
71        _tkq.push( [ 'identifyUser', <?php echo (int) $wpcom_user_id; ?>, <?php echo wp_json_encode( $user_login, JSON_HEX_TAG ); ?> ] );
72        <?php endif; ?>
73        _tkq.push( [ 'recordEvent', 'wpcom_admin_page_view', _admin_pv_props ] );
74    </script>
75    <?php
76}
77add_action( 'admin_footer', __NAMESPACE__ . '\wpcom_nosara_track_admin_page_views' );
78
79/**
80 * Track non-calypso Customizer views if the user is linked from the frontend.
81 */
82function wpcom_maybe_track_customizer() {
83    // not when the Customizer is loaded in Calypso
84    if ( isset( $_GET['calypso'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
85        return;
86    }
87
88    // links from frontend
89    if ( isset( $_GET['url'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
90        return wpcom_track_customizer_from_frontend();
91    }
92
93    // standard wp-admin
94    wpcom_nosara_track_admin_page_views();
95}
96
97/**
98 * Since links to the Customizer from the frontend aren't properly wp-admin (no wp-admin chrome,
99 * you return to the frontend after closing), they shouldn't be counted as wp-admin views.
100 */
101function wpcom_track_customizer_from_frontend() {
102    global $current_user;
103
104    // Since we view so many screens to offer support and do feature dev, I think it's best not to count us.
105    if ( do_not_track_a11ns() ) {
106        return;
107    }
108
109    $is_simple_site  = defined( 'IS_WPCOM' ) && IS_WPCOM;
110    $wpcom_user_id   = $is_simple_site
111        ? absint( $current_user->ID )
112        : (int) get_user_meta( absint( $current_user->ID ), 'wpcom_user_id', true );
113    $wpcom_user_data = $is_simple_site ? null : get_user_meta( absint( $current_user->ID ), 'wpcom_user_data', true );
114    $user_login      = (int) ( $wpcom_user_data->ID ?? 0 ) === $wpcom_user_id && ! empty( $wpcom_user_data->login )
115        ? $wpcom_user_data->login
116        : $current_user->user_login;
117    ?>
118    <script type="text/javascript">
119        _tkq = window._tkq || [];
120        <?php if ( $wpcom_user_id > 0 ) : ?>
121        _tkq.push( [ 'identifyUser', <?php echo (int) $wpcom_user_id; ?>, <?php echo wp_json_encode( $user_login, JSON_HEX_TAG ); ?> ] );
122        <?php endif; ?>
123        _tkq.push( [ 'recordEvent', 'wpcom_customize_loaded_from_frontend', {
124            blog_id: '<?php echo (int) \get_wpcom_blog_id(); ?>',
125            is_local_only_user: <?php echo 0 === $wpcom_user_id ? 'true' : 'false'; ?>
126        } ] );
127    </script>
128    <?php
129}
130add_action( 'customize_controls_print_footer_scripts', __NAMESPACE__ . '\wpcom_maybe_track_customizer' );
131
132/**
133 * Determine if the current user should not be tracked.
134 *
135 * @return bool
136 */
137function do_not_track_a11ns() {
138    $is_simple_site = defined( 'IS_WPCOM' ) && IS_WPCOM;
139
140    if ( $is_simple_site ) {
141        return is_automattician() || is_network_admin();
142    }
143
144    return wpcom_atomic_maybe_is_a11n();
145}
146
147/**
148 * Check if the user might be an a11n on Atomic sites.
149 *
150 * @return bool
151 */
152function wpcom_atomic_maybe_is_a11n() {
153    $is_proxy_atomic    = defined( 'AT_PROXIED_REQUEST' ) && AT_PROXIED_REQUEST;
154    $is_support_session = WPCOMSH_Support_Session_Detect::is_probably_support_session();
155
156    return $is_proxy_atomic && ! $is_support_session;
157}
158
159/**
160 * Retrieves the user types for Atomic sites.
161 *
162 * @return array An array of user types.
163 */
164function wpcom_atomic_get_user_types() {
165    $user_types = array();
166
167    if ( get_account_age_in_days() <= 14 ) {
168        $user_types[] = 'New User';
169    }
170
171    $subscriptions = wpcomsh_get_wpcom_active_subscriptions();
172    if ( count( $subscriptions ) > 0 ) {
173        $user_types[] = 'Paid';
174    }
175
176    if ( wpcom_site_has_feature( \WPCOM_Features::PRIORITY_SUPPORT ) ) {
177        $user_types[] = 'Business';
178    }
179
180    return $user_types;
181}
182
183/**
184 * Calculate the number of days since the current user registered their account.
185 *
186 * @global WP_User $current_user The current user object.
187 *
188 * @return float The age of the account in days.
189 */
190function get_account_age_in_days() {
191    global $current_user;
192
193    return ( time() - strtotime( $current_user->user_registered ) ) / DAY_IN_SECONDS;
194}