PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 11.4.1
Jetpack – WP Security, Backup, Speed, & Growth v11.4.1
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 All 500 releases
← All changes | modules/stats.php +561 -553 12.4.211.4.1 View file →
@@ -1,7 +1,7 @@
1 1 <?php
2 2 /**
3 - * Module Name: Jetpack Stats
3 + * Module Name: Site Stats
4 4 * Module Description: Collect valuable traffic stats and insights.
5 5 * Sort Order: 1
6 6 * Recommendation Order: 2
7 7 * First Introduced: 1.1
@@ -6,9 +6,9 @@
6 6 * Recommendation Order: 2
7 7 * First Introduced: 1.1
8 8 * Requires Connection: Yes
9 9 * Auto Activate: Yes
10 - * Module Tags: Jetpack Stats, Site Stats, Recommended
10 + * Module Tags: Site Stats, Recommended
11 11 * Feature: Engagement
12 12 * Additional Search Queries: statistics, tracking, analytics, views, traffic, stats
13 13 *
14 14 * @package automattic/jetpack
@@ -17,31 +17,18 @@
17 17 use Automattic\Jetpack\Connection\Client;
18 18 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
19 19 use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
20 20 use Automattic\Jetpack\Redirect;
21 -use Automattic\Jetpack\Stats\Main as Stats;
22 -use Automattic\Jetpack\Stats\Options as Stats_Options;
23 -use Automattic\Jetpack\Stats\Tracking_Pixel as Stats_Tracking_Pixel;
24 -use Automattic\Jetpack\Stats\XMLRPC_Provider as Stats_XMLRPC;
25 -use Automattic\Jetpack\Stats_Admin\Dashboard as Stats_Dashboard;
26 -use Automattic\Jetpack\Stats_Admin\Main as Stats_Main;
27 -use Automattic\Jetpack\Stats_Admin\Notices as Stats_Notices;
28 -use Automattic\Jetpack\Status\Host;
21 +use Automattic\Jetpack\Status;
29 22 use Automattic\Jetpack\Tracking;
30 23
31 -if ( defined( 'STATS_DASHBOARD_SERVER' ) ) {
24 +if ( defined( 'STATS_VERSION' ) ) {
32 25 return;
33 26 }
34 27
35 -define( 'STATS_DASHBOARD_SERVER', 'dashboard.wordpress.com' );
28 +define( 'STATS_VERSION', '9' );
29 +defined( 'STATS_DASHBOARD_SERVER' ) || define( 'STATS_DASHBOARD_SERVER', 'dashboard.wordpress.com' );
36 30
37 -/**
38 - * Stats content markers.
39 - * Used to test for content vs script when parsing server-generated HTML.
40 - */
41 -const STATS_BODY_MARKER = '<div id="statchart"';
42 -const STATS_CONTENT_MARKER = '<div class="gotonewdash">';
43 -
44 31 add_action( 'jetpack_modules_loaded', 'stats_load' );
45 32
46 33 /**
47 34 * Load Stats.
@@ -51,12 +38,25 @@
51 38 */
52 39 function stats_load() {
53 40 Jetpack::enable_module_configurable( __FILE__ );
54 41
42 + // Generate the tracking code after wp() has queried for posts.
43 + add_action( 'template_redirect', 'stats_template_redirect', 1 );
44 +
55 45 add_action( 'wp_head', 'stats_admin_bar_head', 100 );
56 46
47 + add_action( 'wp_head', 'stats_hide_smile_css' );
48 + add_action( 'embed_head', 'stats_hide_smile_css' );
49 +
57 50 add_action( 'jetpack_admin_menu', 'stats_admin_menu' );
58 51
52 + // Map stats caps.
53 + add_filter( 'map_meta_cap', 'stats_map_meta_caps', 10, 3 );
54 +
55 + add_action( 'admin_init', 'stats_merged_widget_admin_init' );
56 +
57 + add_filter( 'jetpack_xmlrpc_unauthenticated_methods', 'stats_xmlrpc_methods' );
58 +
59 59 add_filter( 'pre_option_db_version', 'stats_ignore_db_version' );
60 60
61 61 // Add an icon to see stats in WordPress.com for a particular post.
62 62 add_action( 'admin_print_styles-edit.php', 'jetpack_stats_load_admin_css' );
@@ -63,10 +63,8 @@
63 63 add_filter( 'manage_posts_columns', 'jetpack_stats_post_table' );
64 64 add_filter( 'manage_pages_columns', 'jetpack_stats_post_table' );
65 65 add_action( 'manage_posts_custom_column', 'jetpack_stats_post_table_cell', 10, 2 );
66 66 add_action( 'manage_pages_custom_column', 'jetpack_stats_post_table_cell', 10, 2 );
67 - // Filter for adding the Jetpack plugin version to tracking stats.
68 - add_filter( 'stats_array', 'filter_stats_array_add_jp_version' );
69 67
70 68 require_once __DIR__ . '/stats/class-jetpack-stats-upgrade-nudges.php';
71 69 add_action( 'updating_jetpack_version', array( 'Jetpack_Stats_Upgrade_Nudges', 'unset_nudges_setting' ) );
72 70 }
@@ -71,16 +69,55 @@
71 69 add_action( 'updating_jetpack_version', array( 'Jetpack_Stats_Upgrade_Nudges', 'unset_nudges_setting' ) );
72 70 }
73 71
74 72 /**
73 + * Delay conditional for current_user_can to after init.
74 + *
75 + * @access public
76 + * @return void
77 + */
78 +function stats_merged_widget_admin_init() {
79 + if ( current_user_can( 'view_stats' ) ) {
80 + add_action( 'load-index.php', 'stats_enqueue_dashboard_head' );
81 + add_action( 'jetpack_dashboard_widget', 'stats_jetpack_dashboard_widget' );
82 + }
83 +}
84 +
85 +/**
86 + * Enqueue Stats Dashboard
87 + *
88 + * @access public
89 + * @return void
90 + */
91 +function stats_enqueue_dashboard_head() {
92 + add_action( 'admin_head', 'stats_dashboard_head' );
93 +}
94 +
95 +/**
75 96 * Checks if filter is set and dnt is enabled.
76 97 *
77 - * @deprecated 11.5
78 98 * @return bool
79 99 */
80 100 function jetpack_is_dnt_enabled() {
81 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Main::jetpack_is_dnt_enabled' );
82 - return Stats::jetpack_is_dnt_enabled();
101 + /**
102 + * Filter the option which decides honor DNT or not.
103 + *
104 + * @module stats
105 + * @since 6.1.0
106 + *
107 + * @param bool false Honors DNT for clients who don't want to be tracked. Defaults to false. Set to true to enable.
108 + */
109 + if ( false === apply_filters( 'jetpack_honor_dnt_header_for_stats', false ) ) {
110 + return false;
111 + }
112 +
113 + foreach ( $_SERVER as $name => $value ) {
114 + if ( 'http_dnt' === strtolower( $name ) && 1 === (int) $value ) {
115 + return true;
116 + }
117 + }
118 +
119 + return false;
83 120 }
84 121
85 122 /**
86 123 * Prevent sparkline img requests being redirected to upgrade.php.
@@ -104,10 +141,8 @@
104 141
105 142 /**
106 143 * Maps view_stats cap to read cap as needed.
107 144 *
108 - * @deprecated 11.5
109 - *
110 145 * @access public
111 146 * @param mixed $caps Caps.
112 147 * @param mixed $cap Cap.
113 148 * @param mixed $user_id User ID.
@@ -113,68 +148,242 @@
113 148 * @param mixed $user_id User ID.
114 149 * @return array Possibly mapped capabilities for meta capability.
115 150 */
116 151 function stats_map_meta_caps( $caps, $cap, $user_id ) {
117 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Main::map_meta_caps' );
118 - return Stats::map_meta_caps( $caps, $cap, $user_id );
152 + // Map view_stats to exists.
153 + if ( 'view_stats' === $cap ) {
154 + $user = new WP_User( $user_id );
155 + $user_role = array_shift( $user->roles );
156 + $stats_roles = stats_get_option( 'roles' );
157 +
158 + // Is the users role in the available stats roles?
159 + if ( is_array( $stats_roles ) && in_array( $user_role, $stats_roles, true ) ) {
160 + $caps = array( 'read' );
161 + }
162 + }
163 +
164 + return $caps;
119 165 }
120 166
121 167 /**
122 168 * Stats Template Redirect.
123 169 *
124 - * @deprecated 11.5
125 170 * @access public
126 171 * @return void
127 172 */
128 173 function stats_template_redirect() {
129 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Main::template_redirect' );
130 - Stats::template_redirect();
174 + global $current_user;
175 +
176 + if (
177 + is_feed()
178 + || is_robots()
179 + || is_embed()
180 + || is_trackback()
181 + || is_preview()
182 + || jetpack_is_dnt_enabled()
183 + ) {
184 + return;
185 + }
186 +
187 + // Staging Sites should not generate tracking stats.
188 + $status = new Status();
189 + if ( $status->is_staging_site() ) {
190 + return;
191 + }
192 +
193 + // Should we be counting this user's views?
194 + if ( ! empty( $current_user->ID ) ) {
195 + $count_roles = stats_get_option( 'count_roles' );
196 + if ( ! is_array( $count_roles ) || ! array_intersect( $current_user->roles, $count_roles ) ) {
197 + return;
198 + }
199 + }
200 +
201 + /**
202 + * Allow excluding specific IP addresses from being tracked in Stats.
203 + * Note: for this to work well, visitors' IP addresses must:
204 + * - be stored and returned properly in IP address headers;
205 + * - not be impacted by any caching setup on your site.
206 + *
207 + * @module stats
208 + *
209 + * @since 10.6
210 + *
211 + * @param array $excluded_ips An array of IP address strings to exclude from tracking.
212 + */
213 + $excluded_ips = (array) apply_filters( 'jetpack_stats_excluded_ips', array() );
214 +
215 + // Should we be counting views for this IP address?
216 + if (
217 + ! empty( $excluded_ips )
218 + && in_array( Jetpack::current_user_ip( true ), $excluded_ips, true )
219 + ) {
220 + return;
221 + }
222 +
223 + add_action( 'wp_footer', 'stats_footer', 101 );
224 + add_action( 'web_stories_print_analytics', 'stats_footer' );
225 +
131 226 }
132 227
133 228 /**
134 229 * Stats Build View Data.
135 230 *
136 - * @deprecated 11.5
137 231 * @access public
138 232 * @return array.
139 233 */
140 234 function stats_build_view_data() {
141 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Tracking_Pixel::build_view_data' );
142 - return Stats_Tracking_Pixel::build_view_data();
235 + global $wp_the_query;
236 +
237 + $blog = Jetpack_Options::get_option( 'id' );
238 + $tz = get_option( 'gmt_offset' );
239 + $v = 'ext';
240 + $blog_url = wp_parse_url( site_url() );
241 + $srv = $blog_url['host'];
242 + $j = sprintf( '%s:%s', JETPACK__API_VERSION, JETPACK__VERSION );
243 + if ( $wp_the_query->is_single || $wp_the_query->is_page || $wp_the_query->is_posts_page ) {
244 + // Store and reset the queried_object and queried_object_id
245 + // Otherwise, redirect_canonical() will redirect to home_url( '/' ) for show_on_front = page sites where home_url() is not all lowercase.
246 + // Repro:
247 + // 1. Set home_url = https://ExamPle.com/
248 + // 2. Set show_on_front = page
249 + // 3. Set page_on_front = something
250 + // 4. Visit https://example.com/ !
251 + $queried_object = isset( $wp_the_query->queried_object ) ? $wp_the_query->queried_object : null;
252 + $queried_object_id = isset( $wp_the_query->queried_object_id ) ? $wp_the_query->queried_object_id : null;
253 + try {
254 + $post_obj = $wp_the_query->get_queried_object();
255 + $post = $post_obj instanceof WP_Post ? $post_obj->ID : '0';
256 + } finally {
257 + $wp_the_query->queried_object = $queried_object;
258 + $wp_the_query->queried_object_id = $queried_object_id;
259 + }
260 + } else {
261 + $post = '0';
262 + }
263 +
264 + return compact( 'v', 'j', 'blog', 'post', 'tz', 'srv' );
143 265 }
144 266
145 267 /**
268 + * Stats Footer.
269 + *
270 + * @access public
271 + * @return void
272 + */
273 +function stats_footer() {
274 + $data = stats_build_view_data();
275 + if ( Jetpack_AMP_Support::is_amp_request() ) {
276 +
277 + /**
278 + * Filter the parameters added to the AMP pixel tracking code.
279 + *
280 + * @module stats
281 + *
282 + * @since 10.9
283 + *
284 + * @param array $data Array of options about the site and page you're on.
285 + */
286 + $data = (array) apply_filters( 'jetpack_stats_footer_amp_data', $data );
287 + stats_render_amp_footer( $data );
288 + } else {
289 +
290 + /**
291 + * Filter the parameters added to the JavaScript stats tracking code.
292 + *
293 + * @module stats
294 + *
295 + * @since 10.9
296 + *
297 + * @param array $data Array of options about the site and page you're on.
298 + */
299 + $data = (array) apply_filters( 'jetpack_stats_footer_js_data', $data );
300 + stats_render_footer( $data );
301 + }
302 +
303 +}
304 +
305 +/**
306 + * Render the stats footer
307 + *
308 + * @param array $data Array of data for the JS stats tracker.
309 + */
310 +function stats_render_footer( $data ) {
311 + // phpcs:disable WordPress.WP.EnqueuedResources.NonEnqueuedScript
312 + // When there is a way to use defer with enqueue, we can move to it and inline the custom data.
313 + $script = 'https://stats.wp.com/e-' . gmdate( 'YW' ) . '.js';
314 + $data_stats_array = stats_array( $data );
315 +
316 + $stats_footer = <<<END
317 +<script src='{$script}' defer></script>
318 +<script>
319 + _stq = window._stq || [];
320 + _stq.push([ 'view', {{$data_stats_array}} ]);
321 + _stq.push([ 'clickTrackerInit', '{$data['blog']}', '{$data['post']}' ]);
322 +</script>
323 +
324 +END;
325 + // phpcs:enable
326 + print $stats_footer; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
327 +}
328 +
329 +/**
330 + * Render the stats footer for AMP output.
331 + *
332 + * @param array $data Array of data for the AMP pixel tracker.
333 + */
334 +function stats_render_amp_footer( $data ) {
335 + $data['host'] = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : ''; // input var ok.
336 + $data['rand'] = 'RANDOM'; // AMP placeholder.
337 + $data['ref'] = 'DOCUMENT_REFERRER'; // AMP placeholder.
338 + $data = array_map( 'rawurlencode', $data );
339 + $pixel_url = add_query_arg( $data, 'https://pixel.wp.com/g.gif' );
340 +
341 + ?>
342 + <amp-pixel src="<?php echo esc_url( $pixel_url ); ?>"></amp-pixel>
343 + <?php
344 +}
345 +
346 +/**
146 347 * Stats Get Options.
147 348 *
148 - * @deprecated 11.5
149 - *
150 349 * @access public
151 350 * @return array.
152 351 */
153 352 function stats_get_options() {
154 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::get_options' );
155 - return Stats_Options::get_options();
353 + $options = get_option( 'stats_options' );
354 +
355 + if ( ! isset( $options['version'] ) || $options['version'] < STATS_VERSION ) {
356 + $options = stats_upgrade_options( $options );
357 + }
358 +
359 + return $options;
156 360 }
157 361
158 362 /**
159 363 * Get Stats Options.
160 364 *
161 - * @deprecated 11.5
162 - *
163 365 * @access public
164 366 * @param mixed $option Option.
165 367 * @return mixed|null.
166 368 */
167 369 function stats_get_option( $option ) {
168 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::get_option' );
169 - return Stats_Options::get_option( $option );
370 + $options = stats_get_options();
371 +
372 + if ( 'blog_id' === $option ) {
373 + return Jetpack_Options::get_option( 'id' );
374 + }
375 +
376 + if ( isset( $options[ $option ] ) ) {
377 + return $options[ $option ];
378 + }
379 +
380 + return null;
170 381 }
171 382
172 383 /**
173 384 * Stats Set Options.
174 385 *
175 - * @deprecated 11.5
176 - *
177 386 * @access public
178 387 * @param mixed $option Option.
179 388 * @param mixed $value Value.
180 389 * @return bool.
@@ -179,41 +388,94 @@
179 388 * @param mixed $value Value.
180 389 * @return bool.
181 390 */
182 391 function stats_set_option( $option, $value ) {
183 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::set_option' );
184 - return Stats_Options::set_option( $option, $value );
392 + $options = stats_get_options();
393 +
394 + $options[ $option ] = $value;
395 +
396 + return stats_set_options( $options );
185 397 }
186 398
187 399 /**
188 400 * Stats Set Options.
189 401 *
190 - * @deprecated 11.5
191 - *
192 402 * @access public
193 403 * @param mixed $options Options.
194 404 * @return bool
195 405 */
196 406 function stats_set_options( $options ) {
197 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::set_options' );
198 - return Stats_Options::set_options( $options );
407 + return update_option( 'stats_options', $options );
199 408 }
200 409
201 410 /**
202 411 * Stats Upgrade Options.
203 412 *
204 - * @deprecated 11.5
205 - *
206 413 * @access public
207 414 * @param mixed $options Options.
208 415 * @return array|bool
209 416 */
210 417 function stats_upgrade_options( $options ) {
211 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::upgrade_options' );
212 - return Stats_Options::upgrade_options( $options );
418 + $defaults = array(
419 + 'admin_bar' => true,
420 + 'roles' => array( 'administrator' ),
421 + 'count_roles' => array(),
422 + 'blog_id' => Jetpack_Options::get_option( 'id' ),
423 + 'do_not_track' => true, // @todo
424 + );
425 +
426 + if ( isset( $options['reg_users'] ) ) {
427 + if ( ! function_exists( 'get_editable_roles' ) ) {
428 + require_once ABSPATH . 'wp-admin/includes/user.php';
429 + }
430 + if ( $options['reg_users'] ) {
431 + $options['count_roles'] = array_keys( get_editable_roles() );
432 + }
433 + unset( $options['reg_users'] );
434 + }
435 +
436 + if ( is_array( $options ) && ! empty( $options ) ) {
437 + $new_options = array_merge( $defaults, $options );
438 + } else {
439 + $new_options = $defaults;
440 + }
441 +
442 + $new_options['version'] = STATS_VERSION;
443 +
444 + if ( ! stats_set_options( $new_options ) ) {
445 + return false;
446 + }
447 +
448 + return $new_options;
213 449 }
214 450
215 451 /**
452 + * Creates the "array" string used as part of the JS tracker.
453 + *
454 + * @access public
455 + * @param array $kvs KVS.
456 + * @return string
457 + */
458 +function stats_array( $kvs ) {
459 + /**
460 + * Filter the options added to the JavaScript Stats tracking code.
461 + *
462 + * @module stats
463 + *
464 + * @since 1.1.0
465 + *
466 + * @param array $kvs Array of options about the site and page you're on.
467 + */
468 + $kvs = (array) apply_filters( 'stats_array', $kvs );
469 + $kvs = array_map( 'addslashes', $kvs );
470 + $jskvs = array();
471 + foreach ( $kvs as $k => $v ) {
472 + $jskvs[] = "$k:'$v'";
473 + }
474 + return join( ',', $jskvs );
475 +}
476 +
477 +/**
216 478 * Admin Pages.
217 479 *
218 480 * @access public
219 481 * @return void
@@ -231,29 +493,10 @@
231 493 exit;
232 494 }
233 495 }
234 496
235 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
236 - if ( ! ( new Host() )->is_woa_site() && isset( $_GET['enable_new_stats'] ) && '1' === $_GET['enable_new_stats'] ) {
237 - // Passing true enables Odyssey Stats.
238 - // We're ignorning the return value for now.
239 - Stats_Main::update_new_stats_status( true );
240 - }
241 -
242 - // phpcs:ignore WordPress.Security.NonceVerification.Recommended
243 - if ( ( new Host() )->is_woa_site() || ! Stats_Options::get_option( 'enable_odyssey_stats' ) || isset( $_GET['noheader'] ) ) {
244 - // Show old Jetpack Stats interface for:
245 - // - Atomic sites.
246 - // - When the "enable_odyssey_stats" option is disabled.
247 - // - When being shown in the adminbar outside of wp-admin.
248 - $hook = add_submenu_page( 'jetpack', __( 'Stats', 'jetpack' ), __( 'Stats', 'jetpack' ), 'view_stats', 'stats', 'jetpack_admin_ui_stats_report_page_wrapper' );
249 - add_action( "load-$hook", 'stats_reports_load' );
250 - } else {
251 - // Enable the new Odyssey Stats experience.
252 - $stats_dashboard = new Stats_Dashboard();
253 - $hook = add_submenu_page( 'jetpack', __( 'Stats', 'jetpack' ), __( 'Stats', 'jetpack' ), 'view_stats', 'stats', array( $stats_dashboard, 'render' ) );
254 - add_action( "load-$hook", array( $stats_dashboard, 'admin_init' ) );
255 - }
497 + $hook = add_submenu_page( 'jetpack', __( 'Site Stats', 'jetpack' ), __( 'Site Stats', 'jetpack' ), 'view_stats', 'stats', 'jetpack_admin_ui_stats_report_page_wrapper' );
498 + add_action( "load-$hook", 'stats_reports_load' );
256 499 }
257 500
258 501 /**
259 502 * Stats Admin Path.
@@ -293,46 +536,12 @@
293 536 add_action( 'admin_print_footer_scripts', 'stats_js_remove_stnojs_cookie' );
294 537 } elseif ( ! isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
295 538 // Normal page load. Load page content via JS.
296 539 add_action( 'admin_print_footer_scripts', 'stats_js_load_page_via_ajax' );
297 - add_action( 'admin_print_footer_scripts', 'stats_script_dismiss_nudge_handler' );
298 540 }
299 541 }
300 542
301 543 /**
302 - * JavaScript to dismiss the Odyssey nudge.
303 - *
304 - * @access public
305 - * @return void
306 - */
307 -function stats_script_dismiss_nudge_handler() {
308 - ?>
309 - <script type="text/javascript">
310 - function stats_odyssey_dismiss_nudge() {
311 - // Hide the nudge UI, effectively dismissing it.
312 - var element = document.getElementById( "stats-odyssey-nudge-main" );
313 - element.classList.toggle( "is-hidden" );
314 - // Send an AJAX request.
315 - // Note we can provide a 'postponed_for' parameter to set the delay.
316 - // Without a parameter it defaults to 30 days which is what we want here.
317 - let nonce = <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ) ); ?>;
318 - let url = <?php echo wp_json_encode( rest_url( '/jetpack/v4/stats-app/stats/notices' ) ); ?>;
319 - let data = {
320 - id: 'opt_in_new_stats',
321 - status: 'postponed',
322 - };
323 - jQuery.ajax({
324 - type: "POST",
325 - url: url,
326 - data: data,
327 - headers: { "x-wp-nonce": nonce },
328 - });
329 - }
330 - </script>
331 - <?php
332 -}
333 -
334 -/**
335 544 * Stats Reports CSS.
336 545 *
337 546 * @access public
338 547 * @return void
@@ -348,9 +557,9 @@
348 557
349 558 #stats-loading-wrap p {
350 559 text-align: center;
351 560 font-size: 2em;
352 - margin-bottom: 3em;
561 + margin: 7.5em 15px 0 0;
353 562 height: 64px;
354 563 line-height: 64px;
355 564 }
356 565 </style>
@@ -385,11 +594,9 @@
385 594 <script type="text/javascript">
386 595 /* <![CDATA[ */
387 596 if ( -1 == document.location.href.indexOf( 'noheader' ) ) {
388 597 jQuery( function( $ ) {
389 - const loadStatsUrl = new URL( document.location.href );
390 - loadStatsUrl.searchParams.append( 'noheader', 1 );
391 - $.get( loadStatsUrl.toString(), function( responseText ) {
598 + $.get( document.location.href + '&noheader', function( responseText ) {
392 599 $( '#stats-loading-wrap' ).replaceWith( responseText );
393 600 $( '#jp-stats-wrap' )[0].dispatchEvent( new Event( 'stats-loaded' ) );
394 601 } );
395 602 } );
@@ -407,8 +614,9 @@
407 614 Jetpack_Admin_Page::wrap_ui( 'stats_reports_page', array( 'is-wide' => true ) );
408 615 } else {
409 616 stats_reports_page();
410 617 }
618 +
411 619 }
412 620
413 621 /**
414 622 * Stats Report Page.
@@ -416,13 +624,15 @@
416 624 * @access public
417 625 * @param bool $main_chart_only (default: false) Main Chart Only.
418 626 */
419 627 function stats_reports_page( $main_chart_only = false ) {
628 +
420 629 if ( isset( $_GET['dashboard'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
421 630 return stats_dashboard_widget_content();
422 631 }
423 632
424 - $blog_id = Stats_Options::get_option( 'blog_id' );
633 + $blog_id = stats_get_option( 'blog_id' );
634 + $stats_url = Redirect::get_url( 'calypso-stats' );
425 635
426 636 if ( ! $main_chart_only && ! isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) && empty( $_COOKIE['stnojs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
427 637 $nojs_url = add_query_arg( 'nojs', '1' );
428 638 $http = is_ssl() ? 'https' : 'http';
@@ -430,9 +640,9 @@
430 640 ?>
431 641
432 642 <div id="jp-stats-wrap">
433 643 <div class="wrap">
434 - <h1><?php esc_html_e( 'Jetpack Stats', 'jetpack' ); ?>
644 + <h1><?php esc_html_e( 'Site Stats', 'jetpack' ); ?>
435 645 <?php
436 646 if ( current_user_can( 'jetpack_manage_modules' ) ) :
437 647 $i18n_headers = jetpack_get_module_i18n( 'stats' );
438 648 ?>
@@ -460,10 +670,11 @@
460 670 </h2>
461 671 </div>
462 672 <div id="stats-loading-wrap" class="wrap">
463 673 <p class="hide-if-no-js"><img width="32" height="32" alt="<?php esc_attr_e( 'Loading&hellip;', 'jetpack' ); ?>" src="<?php echo esc_url( $static_url ); ?>" /></p>
464 - <p class="hide-if-js"><?php esc_html_e( 'Jetpack Stats work better with JavaScript enabled.', 'jetpack' ); ?><br />
465 - <a href="<?php echo esc_url( $nojs_url ); ?>"><?php esc_html_e( 'View Jetpack Stats without JavaScript', 'jetpack' ); ?></a>.</p>
674 + <p style="font-size: 11pt; margin: 0;"><a href="<?php echo esc_url( $stats_url ); ?>" rel="noopener noreferrer" target="_blank"><?php esc_html_e( 'View stats on WordPress.com right now', 'jetpack' ); ?></a></p>
675 + <p class="hide-if-js"><?php esc_html_e( 'Your Site Stats work better with JavaScript enabled.', 'jetpack' ); ?><br />
676 + <a href="<?php echo esc_url( $nojs_url ); ?>"><?php esc_html_e( 'View Site Stats without JavaScript', 'jetpack' ); ?></a>.</p>
466 677 </div>
467 678 </div>
468 679 <?php
469 680 return;
@@ -560,17 +771,9 @@
560 771 $body = stats_convert_post_titles( $get['body'] );
561 772 $body = stats_convert_chart_urls( $body );
562 773 $body = stats_convert_image_urls( $body );
563 774 $body = stats_convert_admin_urls( $body );
564 -
565 - // The response can contain either the content to display OR
566 - // the scripts for the chart UI. The following calls inspect the
567 - // response, insert the Odyssey nudge as needed, and make sure
568 - // everything is output correctly.
569 - stats_print_header_section( $body );
570 - stats_print_odyssey_nudge( $body );
571 - stats_print_content_section( $body );
572 - stats_print_chart_scripts( $body );
775 + echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
573 776 }
574 777
575 778 if ( isset( $_GET['page'] ) && 'stats' === $_GET['page'] && ! isset( $_GET['chart'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
576 779 $tracking = new Tracking();
@@ -582,230 +785,8 @@
582 785 }
583 786 }
584 787
585 788 /**
586 - * Legacy Stats: Print Header Section
587 - *
588 - * @access public
589 - * @param mixed $html HTML.
590 - * @return void
591 - */
592 -function stats_print_header_section( $html ) {
593 - $header = stats_parse_header_section( $html );
594 - if ( $header !== '' ) {
595 - echo $header; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
596 - }
597 -}
598 -
599 -/**
600 - * Legacy Stats: Print Content Section
601 - *
602 - * @access public
603 - * @param mixed $html HTML.
604 - * @return void
605 - */
606 -function stats_print_content_section( $html ) {
607 - $content = stats_parse_content_section( $html );
608 - if ( $content !== '' ) {
609 - echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
610 - }
611 -}
612 -
613 -/**
614 - * Legacy Stats: Print Chart Scripts
615 - *
616 - * @access public
617 - * @param mixed $html HTML.
618 - * @return void
619 - */
620 -function stats_print_chart_scripts( $html ) {
621 - if ( is_chart_scripts( $html ) ) {
622 - echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
623 - }
624 -}
625 -
626 -/**
627 - * Legacy Stats: Test for presence of chart scripts
628 - *
629 - * @access public
630 - * @param mixed $html Input HTML that may or may not include the chart scripts.
631 - * @return bool
632 - */
633 -function is_chart_scripts( $html ) {
634 - $pos = strpos( $html, STATS_CONTENT_MARKER );
635 - return $pos === false;
636 -}
637 -
638 -/**
639 - * Legacy Stats: Parse Header Section
640 - *
641 - * Returns the section of the content up to and including the date header.
642 - *
643 - * @access public
644 - * @param mixed $html HTML.
645 - * @return string
646 - */
647 -function stats_parse_header_section( $html ) {
648 - $head = strstr( $html, STATS_CONTENT_MARKER, true );
649 - // Enforce a string result instead of string|false.
650 - if ( $head === false ) {
651 - return '';
652 - }
653 - return $head;
654 -}
655 -
656 -/**
657 - * Legacy Stats: Print Content Section
658 - *
659 - * Returns the section of the content excluding the date header.
660 - *
661 - * @access public
662 - * @param mixed $html HTML.
663 - * @return string
664 - */
665 -function stats_parse_content_section( $html ) {
666 - $body = strstr( $html, STATS_BODY_MARKER );
667 - // Enforce a string result instead of string|false.
668 - if ( $body === false ) {
669 - return '';
670 - }
671 - return $body;
672 -}
673 -
674 -/**
675 - * Legacy Stats: Determine if we need to show the Odyssey upgrade nudge.
676 - *
677 - * @access public
678 - * @return boolean
679 - */
680 -function stats_should_show_odyssey_nudge() {
681 - $stats_notices = ( new Stats_Notices() )->get_notices_to_show();
682 - return isset( $stats_notices[ Stats_Notices::OPT_IN_NEW_STATS_NOTICE_ID ] )
683 - && $stats_notices[ Stats_Notices::OPT_IN_NEW_STATS_NOTICE_ID ];
684 -}
685 -
686 -/**
687 - * Legacy Stats: Print the Odyssey upgrade nudge.
688 - *
689 - * @access public
690 - * @param mixed $html HTML.
691 - * @return void
692 - */
693 -function stats_print_odyssey_nudge( $html ) {
694 - if ( ! stats_should_show_odyssey_nudge() ) {
695 - return;
696 - }
697 - $pos = strpos( $html, STATS_CONTENT_MARKER );
698 - if ( $pos === false ) {
699 - return;
700 - }
701 - $learn_url = Redirect::get_url( 'jetpack-stats-learn-more' );
702 - $redirect_url = admin_url( 'admin.php?page=stats&enable_new_stats=1' );
703 - ?>
704 - <style>
705 - .stats-odyssey-notice {
706 - display: flex;
707 - font-size: var( --font-body );
708 -
709 - border: 1px solid var( --jp-gray-5 );
710 - border-left-color: var( --jp-black );
711 - border-left-width: 6px;
712 - border-radius: 4px;
713 -
714 - margin-top: 24px;
715 - background: white;
716 - position: relative;
717 - }
718 - .stats-odyssey-notice--content {
719 - padding: 24px 0 24px 30px;
720 - font-size: 2em;
721 - width: 100%;
722 - }
723 - .stats-odyssey-notice--content-header {
724 - font-size: 24px;
725 - line-height: 32px;
726 - margin: 0;
727 - margin-bottom: 8px;
728 - }
729 - .stats-odyssey-notice--content-text {
730 - font-size: 16px;
731 - margin: 0;
732 - }
733 - .stats-odyssey-notice--image-container {
734 - background-image: url("/wp-content/plugins/jetpack/images/odyssey-upgrade/background.png"), url("/wp-content/plugins/jetpack/images/odyssey-upgrade/gradient.png");
735 - background-size: cover;
736 - padding-right: 28px;
737 - width: 100%;
738 - }
739 - .stats-odyssey-notice--close-button {
740 - position: absolute;
741 - top: 1rem;
742 - right: 1rem;
743 - background-color: transparent;
744 - border: none;
745 - cursor: pointer;
746 - }
747 - .stats-odyssey-notice--action-bar {
748 - display: flex;
749 - align-items: center;
750 - margin-top: 24px;
751 - }
752 - .stats-odyssey-notice--primary-button {
753 - margin-right: 18px;
754 - padding-left: 20px;
755 - padding-right: 20px;
756 - font-size: 16px;
757 - border-color: black;
758 - background-color: black;
759 - }
760 - .stats-odyssey-notice--primary-button:hover {
761 - border-color: #3c434a;
762 - background-color: #3c434a;
763 - }
764 - .is-primary-link {
765 - color: white;
766 - text-decoration: none;
767 - }
768 - .is-primary-link:active {
769 - color: white;
770 - }
771 - .is-primary-link:focus {
772 - color: white;
773 - box-shadow: none;
774 - outline: none;
775 - }
776 - .is-primary-link:hover {
777 - color: white;
778 - }
779 - .is-secondary-link {
780 - color: black;
781 - font-size: var( --font-body );
782 - }
783 - .is-secondary-link:hover {
784 - color: black;
785 - }
786 - .is-hidden {
787 - display: none;
788 - }
789 - </style>
790 - <div id="stats-odyssey-nudge-main" class="stats-odyssey-notice">
791 - <div class="stats-odyssey-notice--content">
792 - <h2 class="stats-odyssey-notice--content-header"><?php esc_html_e( 'Explore the new Jetpack Stats', 'jetpack' ); ?></h2>
793 - <p class="stats-odyssey-notice--content-text"><?php esc_html_e( "We've added new stats and insights in a more modern and mobile friendly experience to help you grow your site.", 'jetpack' ); ?></p>
794 - <div class="stats-odyssey-notice--action-bar">
795 - <button class="dops-button stats-odyssey-notice--primary-button">
796 - <a class="is-primary-link" href="<?php echo esc_url( $redirect_url ); ?>"><?php esc_html_e( 'Switch to new Stats', 'jetpack' ); ?></a>
797 - </button>
798 - <a class="is-secondary-link" href="<?php echo esc_url( $learn_url ); ?>" rel="noopener noreferrer" target="_blank"><?php esc_html_e( 'Learn about Stats', 'jetpack' ); ?> <svg xmlns="http://www.w3.org/2000/svg" style="vertical-align: middle;" viewBox="0 0 24 24" width="16" height="16" aria-hidden="true" focusable="false"><path d="M18.2 17c0 .7-.6 1.2-1.2 1.2H7c-.7 0-1.2-.6-1.2-1.2V7c0-.7.6-1.2 1.2-1.2h3.2V4.2H7C5.5 4.2 4.2 5.5 4.2 7v10c0 1.5 1.2 2.8 2.8 2.8h10c1.5 0 2.8-1.2 2.8-2.8v-3.6h-1.5V17zM14.9 3v1.5h3.7l-6.4 6.4 1.1 1.1 6.4-6.4v3.7h1.5V3h-6.3z"></path></svg></a>
799 - </div>
800 - </div>
801 - <div class="stats-odyssey-notice--image-container"></div>
802 - <button class="stats-odyssey-notice--close-button" onclick="stats_odyssey_dismiss_nudge()"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" aria-hidden="true" focusable="false"><path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z"></path></svg></button>
803 - </div>
804 - <?php
805 -}
806 -
807 -/**
808 789 * Stats Convert Admin Urls.
809 790 *
810 791 * @access public
811 792 * @param mixed $html HTML.
@@ -921,9 +902,9 @@
921 902 * @access public
922 903 * @return void
923 904 */
924 905 function stats_admin_bar_head() {
925 - if ( ! Stats_Options::get_option( 'admin_bar' ) ) {
906 + if ( ! stats_get_option( 'admin_bar' ) ) {
926 907 return;
927 908 }
928 909
929 910 if ( ! current_user_can( 'view_stats' ) ) {
@@ -998,9 +979,9 @@
998 979 function stats_admin_bar_menu( &$wp_admin_bar ) {
999 980 $img_src = esc_attr( stats_get_image_chart_src( 'admin-bar-hours-scale' ) );
1000 981 $img_src_2x = esc_attr( stats_get_image_chart_src( 'admin-bar-hours-scale-2x' ) );
1001 982 $alt = esc_attr( __( 'Stats', 'jetpack' ) );
1002 - $title = esc_attr( __( 'Views over 48 hours. Click for more Jetpack Stats.', 'jetpack' ) );
983 + $title = esc_attr( __( 'Views over 48 hours. Click for more Site Stats.', 'jetpack' ) );
1003 984
1004 985 $menu = array(
1005 986 'id' => 'stats',
1006 987 'href' => add_query_arg( 'page', 'stats', admin_url( 'admin.php' ) ), // no menu_page_url() blog-side.
@@ -1021,9 +1002,9 @@
1021 1002 *
1022 1003 * @deprecated since 10.3.
1023 1004 */
1024 1005 function stats_update_blog() {
1025 - _deprecated_function( __METHOD__, 'jetpack-10.3' );
1006 + deprecated_function( __METHOD__, 'jetpack-10.3' );
1026 1007 XMLRPC_Async_Call::add_call( 'jetpack.updateBlog', 0, stats_get_blog() );
1027 1008 }
1028 1009
1029 1010 /**
@@ -1028,23 +1009,73 @@
1028 1009
1029 1010 /**
1030 1011 * Stats Get Blog.
1031 1012 *
1032 - * @deprecated 11.5
1013 + * @access public
1014 + * @return string
1015 + */
1016 +function stats_get_blog() {
1017 + $home = wp_parse_url( trailingslashit( get_option( 'home' ) ) );
1018 + $blog = array(
1019 + 'host' => $home['host'],
1020 + 'path' => $home['path'],
1021 + 'blogname' => get_option( 'blogname' ),
1022 + 'blogdescription' => get_option( 'blogdescription' ),
1023 + 'siteurl' => get_option( 'siteurl' ),
1024 + 'gmt_offset' => get_option( 'gmt_offset' ),
1025 + 'timezone_string' => get_option( 'timezone_string' ),
1026 + 'stats_version' => STATS_VERSION,
1027 + 'stats_api' => 'jetpack',
1028 + 'page_on_front' => get_option( 'page_on_front' ),
1029 + 'permalink_structure' => get_option( 'permalink_structure' ),
1030 + 'category_base' => get_option( 'category_base' ),
1031 + 'tag_base' => get_option( 'tag_base' ),
1032 + );
1033 + $blog = array_merge( stats_get_options(), $blog );
1034 + unset( $blog['roles'], $blog['blog_id'] );
1035 + return stats_esc_html_deep( $blog );
1036 +}
1037 +
1038 +/**
1039 + * Modified from stripslashes_deep()
1033 1040 *
1034 1041 * @access public
1042 + * @param mixed $value Value.
1035 1043 * @return string
1036 1044 */
1037 -function stats_get_blog() {
1038 - _deprecated_function( __METHOD__, 'jetpack-11.5' );
1039 - return Stats_XMLRPC::init()->get_blog();
1045 +function stats_esc_html_deep( $value ) {
1046 + if ( is_array( $value ) ) {
1047 + $value = array_map( 'stats_esc_html_deep', $value );
1048 + } elseif ( is_object( $value ) ) {
1049 + $vars = get_object_vars( $value );
1050 + foreach ( $vars as $key => $data ) {
1051 + $value->{$key} = stats_esc_html_deep( $data );
1052 + }
1053 + } elseif ( is_string( $value ) ) {
1054 + $value = esc_html( $value );
1055 + }
1056 +
1057 + return $value;
1040 1058 }
1041 1059
1042 1060 /**
1061 + * Stats xmlrpc_methods function.
1062 + *
1063 + * @access public
1064 + * @param mixed $methods Methods.
1065 + * @return array
1066 + */
1067 +function stats_xmlrpc_methods( $methods ) {
1068 + $my_methods = array(
1069 + 'jetpack.getBlog' => 'stats_get_blog',
1070 + );
1071 +
1072 + return array_merge( $methods, $my_methods );
1073 +}
1074 +
1075 +/**
1043 1076 * Stats Dashboard Widget Options.
1044 1077 *
1045 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1046 - *
1047 1078 * @access public
1048 1079 * @return array
1049 1080 */
1050 1081 function stats_dashboard_widget_options() {
@@ -1065,21 +1096,18 @@
1065 1096 unset( $options[ $key ] );
1066 1097 }
1067 1098 }
1068 1099
1069 - return array_merge( $defaults, $options );
1100 + return array_merge( $defaults, $options );
1070 1101 }
1071 1102
1072 1103 /**
1073 1104 * Stats Dashboard Widget Control.
1074 1105 *
1075 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1076 - *
1077 1106 * @access public
1078 1107 * @return void
1079 1108 */
1080 1109 function stats_dashboard_widget_control() {
1081 - stats_dashboard_widget_controls_handle_submission();
1082 1110 $periods = array(
1083 1111 '1' => __( 'day', 'jetpack' ),
1084 1112 '7' => __( 'week', 'jetpack' ),
1085 1113 '31' => __( 'month', 'jetpack' ),
@@ -1090,56 +1118,28 @@
1090 1118 '31' => __( 'the past month', 'jetpack' ),
1091 1119 '90' => __( 'the past quarter', 'jetpack' ),
1092 1120 '365' => __( 'the past year', 'jetpack' ),
1093 1121 );
1094 - stats_dashboard_widget_controls_html( $intervals, $periods, stats_dashboard_widget_options() );
1095 -}
1096 -
1097 -/**
1098 - * Handle widget controls form submission.
1099 - *
1100 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1101 - *
1102 - * @access public
1103 - * @return void
1104 - */
1105 -function stats_dashboard_widget_controls_handle_submission() {
1106 - $options = stats_dashboard_widget_options();
1107 - $defaults = array(
1122 + $defaults = array(
1108 1123 'top' => 1,
1109 1124 'search' => 7,
1110 1125 );
1111 1126
1112 - // Check if the correct form was submitted.
1113 - if ( isset( $_POST['stats_id'] ) && 'dashboard_stats' === $_POST['stats_id'] ) {
1114 - // Perform nonce verification.
1115 - if (
1116 - isset( $_POST['dashboard-widget-nonce'] ) &&
1117 - wp_verify_nonce( filter_var( wp_unslash( $_POST['dashboard-widget-nonce'] ) ), 'edit-dashboard-widget_dashboard_stats' )
1118 - ) {
1119 - // Update options.
1120 - $options['chart'] = isset( $_POST['chart'] ) ? (int) $_POST['chart'] : 1;
1121 - foreach ( array( 'top', 'search' ) as $key ) {
1122 - $options[ $key ] = isset( $_POST[ $key ] ) ? (int) $_POST[ $key ] : $defaults[ $key ];
1127 + $options = stats_dashboard_widget_options();
1128 +
1129 + if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'post' === strtolower( filter_var( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) ) && isset( $_POST['stats_id'] ) && 'dashboard_stats' === $_POST['stats_id'] ) { // phpcs:ignore WordPress.Security.NonceVerification
1130 + if ( isset( $periods[ $_POST['chart'] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1131 + $options['chart'] = filter_var( wp_unslash( $_POST['chart'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1132 + }
1133 + foreach ( array( 'top', 'search' ) as $key ) {
1134 + if ( isset( $intervals[ $_POST[ $key ] ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
1135 + $options[ $key ] = filter_var( wp_unslash( $_POST[ $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification
1136 + } else {
1137 + $options[ $key ] = $defaults[ $key ];
1123 1138 }
1124 - update_option( 'stats_dashboard_widget', $options );
1125 1139 }
1140 + update_option( 'stats_dashboard_widget', $options );
1126 1141 }
1127 -}
1128 -
1129 -/**
1130 - * Output HTML for widget controls.
1131 - *
1132 - * @param array $intervals Array of intervals.
1133 - * @param array $periods Array of periods.
1134 - * @param array $options Array of options.
1135 - *
1136 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1137 - *
1138 - * @access public
1139 - * @return void
1140 - */
1141 -function stats_dashboard_widget_controls_html( $intervals, $periods, $options ) {
1142 1142 ?>
1143 1143 <p>
1144 1144 <label for="chart"><?php esc_html_e( 'Chart stats by', 'jetpack' ); ?></label>
1145 1145 <select id="chart" name="chart">
@@ -1183,10 +1183,8 @@
1183 1183
1184 1184 /**
1185 1185 * Jetpack Stats Dashboard Widget.
1186 1186 *
1187 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1188 - *
1189 1187 * @access public
1190 1188 * @return void
1191 1189 */
1192 1190 function stats_jetpack_dashboard_widget() {
@@ -1200,9 +1198,9 @@
1200 1198 <button type="button" class="handlediv js-toggle-stats_dashboard_widget_control" aria-expanded="true">
1201 1199 <span class="screen-reader-text"><?php esc_html_e( 'Configure', 'jetpack' ); ?></span>
1202 1200 <span class="toggle-indicator" aria-hidden="true"></span>
1203 1201 </button>
1204 - <div id="dashboard_stats" class="is-loading">
1202 + <div id="dashboard_stats">
1205 1203 <div class="inside">
1206 1204 <div style="height: 250px;"></div>
1207 1205 </div>
1208 1206 </div>
@@ -1209,12 +1207,67 @@
1209 1207 <?php
1210 1208 }
1211 1209
1212 1210 /**
1211 + * JavaScript and CSS for dashboard widget.
1212 + *
1213 + * @access public
1214 + * @return void
1215 + */
1216 +function stats_dashboard_head() {
1217 + ?>
1218 +<script type="text/javascript">
1219 +/* <![CDATA[ */
1220 +jQuery( function($) {
1221 + var dashStats = jQuery( '#dashboard_stats div.inside' );
1222 +
1223 + if ( dashStats.find( '.dashboard-widget-control-form' ).length ) {
1224 + return;
1225 + }
1226 +
1227 + if ( ! dashStats.length ) {
1228 + dashStats = jQuery( '#dashboard_stats div.dashboard-widget-content' );
1229 + var h = parseInt( dashStats.parent().height() ) - parseInt( dashStats.prev().height() );
1230 + var args = 'width=' + dashStats.width() + '&height=' + h.toString();
1231 + } else {
1232 + if ( jQuery('#dashboard_stats' ).hasClass('postbox') ) {
1233 + var args = 'width=' + ( dashStats.prev().width() * 2 ).toString();
1234 + } else {
1235 + var args = 'width=' + ( dashStats.width() * 2 ).toString();
1236 + }
1237 + }
1238 +
1239 + dashStats
1240 + .not( '.dashboard-widget-control' )
1241 + .load( 'admin.php?page=stats&noheader&dashboard&' + args );
1242 +
1243 + jQuery( window ).one( 'resize', function() {
1244 + jQuery( '#stat-chart' ).css( 'width', 'auto' );
1245 + } );
1246 +
1247 +
1248 + // Widget settings toggle container.
1249 + var toggle = $( '.js-toggle-stats_dashboard_widget_control' );
1250 +
1251 + // Move the toggle in the widget header.
1252 + toggle.appendTo( '#jetpack_summary_widget .handle-actions' );
1253 +
1254 + // Toggle settings when clicking on it.
1255 + toggle.show().click( function( e ) {
1256 + e.preventDefault();
1257 + e.stopImmediatePropagation();
1258 + $( this ).parent().toggleClass( 'controlVisible' );
1259 + $( '#stats_dashboard_widget_control' ).slideToggle();
1260 + } );
1261 +} );
1262 +/* ]]> */
1263 +</script>
1264 + <?php
1265 +}
1266 +
1267 +/**
1213 1268 * Stats Dashboard Widget Content.
1214 1269 *
1215 - * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1216 - *
1217 1270 * @access public
1218 1271 * @return void
1219 1272 */
1220 1273 function stats_dashboard_widget_content() {
@@ -1268,9 +1321,9 @@
1268 1321 $post_ids = array();
1269 1322
1270 1323 $csv_end_date = current_time( 'Y-m-d' );
1271 1324 $csv_args = array(
1272 - 'top' => "&limit=6&end=$csv_end_date",
1325 + 'top' => "&limit=8&end=$csv_end_date",
1273 1326 'search' => "&limit=5&end=$csv_end_date",
1274 1327 );
1275 1328
1276 1329 $top_posts = stats_get_csv( 'postviews', "days=$options[top]$csv_args[top]" );
@@ -1282,9 +1335,9 @@
1282 1335 $post_ids[] = $post['post_id'];
1283 1336 }
1284 1337
1285 1338 // Cache.
1286 - get_posts( array( 'include' => implode( ',', array_unique( $post_ids ) ) ) );
1339 + get_posts( array( 'include' => join( ',', array_unique( $post_ids ) ) ) );
1287 1340
1288 1341 $searches = array();
1289 1342 $search_terms = stats_get_csv( 'searchterms', "days=$options[search]$csv_args[search]" );
1290 1343 foreach ( $search_terms as $search_term ) {
@@ -1295,73 +1348,73 @@
1295 1348 }
1296 1349
1297 1350 ?>
1298 1351 <div id="stats-info">
1299 - <div id="stats-info-container">
1300 - <div class="stats-info-header">
1301 - <h2><?php esc_html_e( 'Highlights', 'jetpack' ); ?></h2>
1302 - <div class="stats-info-header-right">
1303 - <a href="<?php echo esc_url( admin_url( 'admin.php?page=stats' ) ); ?>" class="button button-primary">
1304 - <?php esc_html_e( 'View detailed stats', 'jetpack' ); ?>
1305 - </a>
1306 - </div>
1307 - </div>
1308 - <div class="stats-info-content">
1309 - <div id="top-posts" class="stats-section">
1310 - <div class="stats-section-inner">
1311 - <h3 class="heading"><?php esc_html_e( 'Top Posts', 'jetpack' ); ?></h3>
1312 - <?php
1313 - if ( empty( $top_posts ) ) {
1314 - ?>
1315 - <p class="nothing"><?php esc_html_e( 'Sorry, nothing to report.', 'jetpack' ); ?></p>
1316 - <?php
1317 - } else {
1318 - foreach ( $top_posts as $post ) {
1319 - if ( ! get_post( $post['post_id'] ) ) {
1320 - continue;
1321 - }
1322 - ?>
1323 - <p>
1324 - <?php
1325 - printf(
1326 - esc_html(
1327 - /* Translators: Stats dashboard widget Post list with view count: "Post Title 1 View (or Views if plural)". */
1328 - _n( '%1$s %2$s View', '%1$s %2$s Views', $post['views'], 'jetpack' )
1329 - ),
1330 - '<a href="' . esc_url( get_permalink( $post['post_id'] ) ) . '">' . esc_html( get_the_title( $post['post_id'] ) ) . '</a>',
1331 - esc_html( number_format_i18n( $post['views'] ) )
1332 - );
1333 - ?>
1334 - </p>
1335 - <?php
1336 - }
1352 + <div id="top-posts" class='stats-section'>
1353 + <div class="stats-section-inner">
1354 + <h3 class="heading"><?php esc_html_e( 'Top Posts', 'jetpack' ); ?></h3>
1355 + <?php
1356 + if ( empty( $top_posts ) ) {
1357 + ?>
1358 + <p class="nothing"><?php esc_html_e( 'Sorry, nothing to report.', 'jetpack' ); ?></p>
1359 + <?php
1360 + } else {
1361 + foreach ( $top_posts as $post ) {
1362 + if ( ! get_post( $post['post_id'] ) ) {
1363 + continue;
1337 1364 }
1338 1365 ?>
1339 - </div>
1340 - </div>
1341 - <div id="top-search" class="stats-section">
1342 - <div class="stats-section-inner">
1343 - <h3 class="heading"><?php esc_html_e( 'Top Searches', 'jetpack' ); ?></h3>
1366 + <p>
1344 1367 <?php
1345 - if ( empty( $searches ) ) {
1346 - ?>
1347 - <p class="nothing"><?php esc_html_e( 'Sorry, nothing to report.', 'jetpack' ); ?></p>
1348 - <?php
1349 - } else {
1350 - foreach ( $searches as $search_term_item ) {
1351 - printf(
1352 - '<p>%s</p>',
1353 - esc_html( $search_term_item )
1354 - );
1355 - }
1356 - }
1368 + printf(
1369 + esc_html(
1370 + /* Translators: Stats dashboard widget Post list with view count: "Post Title 1 View (or Views if plural)". */
1371 + _n( '%1$s %2$s View', '%1$s %2$s Views', $post['views'], 'jetpack' )
1372 + ),
1373 + '<a href="' . esc_url( get_permalink( $post['post_id'] ) ) . '">' . esc_html( get_the_title( $post['post_id'] ) ) . '</a>',
1374 + esc_html( number_format_i18n( $post['views'] ) )
1375 + );
1357 1376 ?>
1358 - </div>
1359 - </div>
1377 + </p>
1378 + <?php
1379 + }
1380 + }
1381 + ?>
1360 1382 </div>
1361 1383 </div>
1384 + <div id="top-search" class='stats-section'>
1385 + <div class="stats-section-inner">
1386 + <h3 class="heading"><?php esc_html_e( 'Top Searches', 'jetpack' ); ?></h3>
1387 + <?php
1388 + if ( empty( $searches ) ) {
1389 + ?>
1390 + <p class="nothing"><?php esc_html_e( 'Sorry, nothing to report.', 'jetpack' ); ?></p>
1391 + <?php
1392 + } else {
1393 + foreach ( $searches as $search_term_item ) {
1394 + printf(
1395 + '<p>%s</p>',
1396 + esc_html( $search_term_item )
1397 + );
1398 + }
1399 + }
1400 + ?>
1401 + </div>
1402 + </div>
1362 1403 </div>
1404 +<div class="clear"></div>
1405 +<div class="stats-view-all">
1363 1406 <?php
1407 + $stats_day_url = Redirect::get_url( 'calypso-stats-day' );
1408 + printf(
1409 + '<a class="button" target="_blank" rel="noopener noreferrer" href="%1$s">%2$s</a>',
1410 + esc_url( $stats_day_url ),
1411 + esc_html__( 'View all stats', 'jetpack' )
1412 + );
1413 + ?>
1414 +</div>
1415 +<div class="clear"></div>
1416 + <?php
1364 1417 exit;
1365 1418 }
1366 1419
1367 1420 /**
@@ -1378,11 +1431,11 @@
1378 1431 $error = md5( wp_json_encode( compact( 'get', 'url' ) ) );
1379 1432 Jetpack::state( $state_name, $error );
1380 1433 if ( $error !== $previous_error ) {
1381 1434 ?>
1382 - <div class="wrap">
1383 - <p><?php esc_html_e( 'We were unable to get your stats just now. Please reload this page to try again.', 'jetpack' ); ?></p>
1384 - </div>
1435 + <div class="wrap">
1436 + <p><?php esc_html_e( 'We were unable to get your stats just now. Please reload this page to try again.', 'jetpack' ); ?></p>
1437 + </div>
1385 1438 <?php
1386 1439 return;
1387 1440 }
1388 1441 ?>
@@ -1387,39 +1440,43 @@
1387 1440 }
1388 1441 ?>
1389 1442 <div class="wrap">
1390 1443 <p>
1391 - <?php
1392 - printf(
1393 - /* translators: placeholder is an a href for a support site. */
1394 - esc_html__( 'We were unable to get your stats just now. Please reload this page to try again. If this error persists, please contact %1$s. In your report, please include the information below.', 'jetpack' ),
1395 - sprintf(
1396 - '<a href="https://support.wordpress.com/contact/?jetpack=needs-service">%s</a>',
1397 - esc_html__( 'Jetpack Support', 'jetpack' )
1398 - )
1399 - );
1400 - ?>
1401 - </p>
1402 - <pre class="stats-widget-error">
1403 - User Agent: "<?php echo isset( $_SERVER['HTTP_USER_AGENT'] ) ? esc_html( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"
1404 - Page URL: "http<?php echo ( is_ssl() ? 's' : '' ) . '://' . esc_html( ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : '' ) . ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"
1405 - API URL: "<?php echo esc_url( $url ); ?>"
1406 - <?php
1407 - if ( is_wp_error( $get ) ) {
1408 - foreach ( $get->get_error_codes() as $code ) {
1409 - foreach ( $get->get_error_messages( $code ) as $message ) {
1410 - print esc_html( $code ) . ': "' . esc_html( $message ) . '"';
1411 - }
1444 + <?php
1445 + printf(
1446 + /* translators: placeholder is an a href for a support site. */
1447 + esc_html__( 'We were unable to get your stats just now. Please reload this page to try again. If this error persists, please contact %1$s. In your report, please include the information below.', 'jetpack' ),
1448 + sprintf(
1449 + '<a href="https://support.wordpress.com/contact/?jetpack=needs-service">%s</a>',
1450 + esc_html__( 'Jetpack Support', 'jetpack' )
1451 + )
1452 + );
1453 + ?>
1454 + </p>
1455 + <pre>
1456 + User Agent: "<?php echo isset( $_SERVER['HTTP_USER_AGENT'] ) ? esc_html( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"
1457 + Page URL: "http<?php echo ( is_ssl() ? 's' : '' ) . '://' . esc_html( ( isset( $_SERVER['HTTP_HOST'] ) ? wp_unslash( $_SERVER['HTTP_HOST'] ) : '' ) . ( isset( $_SERVER['REQUEST_URI'] ) ? wp_unslash( $_SERVER['REQUEST_URI'] ) : '' ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>"
1458 + API URL: "<?php echo esc_url( $url ); ?>"
1459 + <?php
1460 + if ( is_wp_error( $get ) ) {
1461 + foreach ( $get->get_error_codes() as $code ) {
1462 + foreach ( $get->get_error_messages( $code ) as $message ) {
1463 + ?>
1464 + <?php print esc_html( $code ) . ': "' . esc_html( $message ) . '"'; ?>
1465 +
1466 + <?php
1412 1467 }
1413 - } else {
1414 - $get_code = wp_remote_retrieve_response_code( $get );
1415 - $content_length = strlen( wp_remote_retrieve_body( $get ) );
1416 - ?>
1417 - Response code: "<?php print esc_html( $get_code ); ?>"
1418 - Content length: "<?php print esc_html( $content_length ); ?>"
1419 - <?php
1420 1468 }
1469 + } else {
1470 + $get_code = wp_remote_retrieve_response_code( $get );
1471 + $content_length = strlen( wp_remote_retrieve_body( $get ) );
1421 1472 ?>
1473 +Response code: "<?php print esc_html( $get_code ); ?>"
1474 +Content length: "<?php print esc_html( $content_length ); ?>"
1475 +
1476 + <?php
1477 + }
1478 + ?>
1422 1479 </pre>
1423 1480 </div>
1424 1481 <?php
1425 1482 }
@@ -1563,9 +1620,9 @@
1563 1620 * @return string
1564 1621 */
1565 1622 function jetpack_stats_api_path( $resource = '' ) {
1566 1623 $resource = ltrim( $resource, '/' );
1567 - return sprintf( '/sites/%d/stats/%s', Stats_Options::get_option( 'blog_id' ), $resource );
1624 + return sprintf( '/sites/%d/stats/%s', stats_get_option( 'blog_id' ), $resource );
1568 1625 }
1569 1626
1570 1627 /**
1571 1628 * Fetches stats data from the REST API. Caches locally for 5 minutes.
@@ -1571,15 +1628,13 @@
1571 1628 * Fetches stats data from the REST API. Caches locally for 5 minutes.
1572 1629 *
1573 1630 * @link: https://developer.wordpress.com/docs/api/1.1/get/sites/%24site/stats/
1574 1631 * @access public
1575 - * @deprecated 11.5 Use WPCOM_Stats available methodsinstead.
1576 1632 * @param array $args (default: array()) The args that are passed to the endpoint.
1577 1633 * @param string $resource (default: '') Optional sub-endpoint following /stats/.
1578 1634 * @return array|WP_Error.
1579 1635 */
1580 1636 function stats_get_from_restapi( $args = array(), $resource = '' ) {
1581 - _deprecated_function( __METHOD__, 'jetpack-11.5', 'Please checkout the methods available in Automattic\Jetpack\Stats\WPCOM_Stats' );
1582 1637 $endpoint = jetpack_stats_api_path( $resource );
1583 1638 $api_version = '1.1';
1584 1639 $args = wp_parse_args( $args, array() );
1585 1640 $cache_key = md5( implode( '|', array( $endpoint, $api_version, wp_json_encode( $args ) ) ) );
@@ -1635,9 +1690,9 @@
1635 1690 <?php
1636 1691 }
1637 1692
1638 1693 /**
1639 - * Set header for column that allows to view an entry's stats.
1694 + * Set header for column that allows to go to WordPress.com to see an entry's stats.
1640 1695 *
1641 1696 * @param array $columns An array of column names.
1642 1697 *
1643 1698 * @since 4.7.0
@@ -1644,24 +1699,10 @@
1644 1699 *
1645 1700 * @return mixed
1646 1701 */
1647 1702 function jetpack_stats_post_table( $columns ) {
1648 - /*
1649 - * Stats can be accessed in wp-admin or in Calypso,
1650 - * depending on what version of the stats screen is enabled on your site.
1651 - *
1652 - * In both cases, the user must be allowed to access stats.
1653 - *
1654 - * If the Odyssey Stats experience isn't enabled, the user will need to go to Calypso,
1655 - * so they need to be connected to WordPress.com to be able to access that page.
1656 - */
1657 - if (
1658 - ! current_user_can( 'view_stats' )
1659 - || (
1660 - ! Stats_Options::get_option( 'enable_odyssey_stats' )
1661 - && ! ( new Connection_Manager( 'jetpack' ) )->is_user_connected()
1662 - )
1663 - ) {
1703 + // Adds a stats link on the edit posts page.
1704 + if ( ! current_user_can( 'view_stats' ) || ! ( new Connection_Manager( 'jetpack' ) )->is_user_connected() ) {
1664 1705 return $columns;
1665 1706 }
1666 1707
1667 1708 // Array-Fu to add before comments.
@@ -1683,9 +1724,9 @@
1683 1724 return call_user_func_array( 'array_merge', $chunks );
1684 1725 }
1685 1726
1686 1727 /**
1687 - * Set content for cell with link to an entry's stats in Odyssey Stats.
1728 + * Set content for cell with link to an entry's stats in WordPress.com.
1688 1729 *
1689 1730 * @param string $column The name of the column to display.
1690 1731 * @param int $post_id The current post ID.
1691 1732 *
@@ -1700,51 +1741,18 @@
1700 1741 '<span aria-hidden="true">—</span><span class="screen-reader-text">%s</span>',
1701 1742 esc_html__( 'No stats', 'jetpack' )
1702 1743 );
1703 1744 } else {
1704 - $stats_post_url = ! ( new Host() )->is_woa_site() && Stats_Options::get_option( 'enable_odyssey_stats' )
1705 - ? admin_url( sprintf( 'admin.php?page=stats#!/stats/post/%d/%d', $post_id, Jetpack_Options::get_option( 'id', 0 ) ) )
1706 - : Redirect::get_url(
1745 + $stats_post_url = Redirect::get_url(
1707 1746 'calypso-stats-post',
1708 1747 array(
1709 1748 'path' => $post_id,
1710 1749 )
1711 1750 );
1712 -
1713 1751 printf(
1714 1752 '<a href="%s" title="%s" class="dashicons dashicons-chart-bar" target="_blank"></a>',
1715 1753 esc_url( $stats_post_url ),
1716 - esc_html__( 'View stats for this post', 'jetpack' )
1754 + esc_html__( 'View stats for this post at WordPress.com', 'jetpack' )
1717 1755 );
1718 1756 }
1719 1757 }
1720 -}
1721 -
1722 -/**
1723 - * Add the Jetpack plugin version to the stats tracking data.
1724 - *
1725 - * @param array $kvs The stats array in key values.
1726 - * @return array
1727 - */
1728 -function filter_stats_array_add_jp_version( $kvs ) {
1729 - $kvs['j'] = sprintf( '%s:%s', JETPACK__API_VERSION, JETPACK__VERSION );
1730 -
1731 - return $kvs;
1732 -}
1733 -
1734 -/**
1735 - * Convert stats array to object after sanity checking the array is valid.
1736 - *
1737 - * @param array $stats_array The stats array.
1738 - * @return WP_Error|Object|null
1739 - */
1740 -function convert_stats_array_to_object( $stats_array ) {
1741 -
1742 - if ( is_wp_error( $stats_array ) ) {
1743 - return $stats_array;
1744 - }
1745 - $encoded_array = wp_json_encode( $stats_array );
1746 - if ( ! $encoded_array ) {
1747 - return new WP_Error( 'stats_encoding_error', 'Failed to encode stats array' );
1748 - }
1749 - return json_decode( $encoded_array );
1750 1758 }