PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 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 All 506 releases
← All changes | modules/stats.php +201 -535 12.4.2 → 16.3-a.7 View file →
@@ -1,8 +1,8 @@
1 1 <?php
2 2 /**
3 3 * Module Name: Jetpack Stats
4 - * Module Description: Collect valuable traffic stats and insights.
4 + * Module Description: Clear, concise traffic insights right in your WordPress dashboard.
5 5 * Sort Order: 1
6 6 * Recommendation Order: 2
7 7 * First Introduced: 1.1
8 8 * Requires Connection: Yes
@@ -13,22 +13,27 @@
13 13 *
14 14 * @package automattic/jetpack
15 15 */
16 16
17 +use Automattic\Jetpack\Admin_UI\Admin_Menu;
17 18 use Automattic\Jetpack\Connection\Client;
18 -use Automattic\Jetpack\Connection\Manager as Connection_Manager;
19 -use Automattic\Jetpack\Connection\XMLRPC_Async_Call;
20 19 use Automattic\Jetpack\Redirect;
21 20 use Automattic\Jetpack\Stats\Main as Stats;
22 21 use Automattic\Jetpack\Stats\Options as Stats_Options;
23 22 use Automattic\Jetpack\Stats\Tracking_Pixel as Stats_Tracking_Pixel;
23 +use Automattic\Jetpack\Stats\WPCOM_Stats;
24 24 use Automattic\Jetpack\Stats\XMLRPC_Provider as Stats_XMLRPC;
25 +use Automattic\Jetpack\Stats_Admin\Admin_Bar as Stats_Admin_Bar;
26 +use Automattic\Jetpack\Stats_Admin\Admin_Post_List_Column;
25 27 use Automattic\Jetpack\Stats_Admin\Dashboard as Stats_Dashboard;
26 28 use Automattic\Jetpack\Stats_Admin\Main as Stats_Main;
27 -use Automattic\Jetpack\Stats_Admin\Notices as Stats_Notices;
28 29 use Automattic\Jetpack\Status\Host;
29 30 use Automattic\Jetpack\Tracking;
30 31
32 +if ( ! defined( 'ABSPATH' ) ) {
33 + exit( 0 );
34 +}
35 +
31 36 if ( defined( 'STATS_DASHBOARD_SERVER' ) ) {
32 37 return;
33 38 }
34 39
@@ -51,20 +56,13 @@
51 56 */
52 57 function stats_load() {
53 58 Jetpack::enable_module_configurable( __FILE__ );
54 59
55 - add_action( 'wp_head', 'stats_admin_bar_head', 100 );
60 + Stats_Admin_Bar::init();
61 + Admin_Post_List_Column::register();
56 62
57 63 add_action( 'jetpack_admin_menu', 'stats_admin_menu' );
58 64
59 - add_filter( 'pre_option_db_version', 'stats_ignore_db_version' );
60 -
61 - // Add an icon to see stats in WordPress.com for a particular post.
62 - add_action( 'admin_print_styles-edit.php', 'jetpack_stats_load_admin_css' );
63 - add_filter( 'manage_posts_columns', 'jetpack_stats_post_table' );
64 - add_filter( 'manage_pages_columns', 'jetpack_stats_post_table' );
65 - add_action( 'manage_posts_custom_column', 'jetpack_stats_post_table_cell', 10, 2 );
66 - add_action( 'manage_pages_custom_column', 'jetpack_stats_post_table_cell', 10, 2 );
67 65 // Filter for adding the Jetpack plugin version to tracking stats.
68 66 add_filter( 'stats_array', 'filter_stats_array_add_jp_version' );
69 67
70 68 require_once __DIR__ . '/stats/class-jetpack-stats-upgrade-nudges.php';
@@ -83,24 +81,18 @@
83 81 }
84 82
85 83 /**
86 84 * Prevent sparkline img requests being redirected to upgrade.php.
87 - * See wp-admin/admin.php where it checks $wp_db_version.
88 85 *
86 + * @deprecated 16.3
87 + *
89 88 * @access public
90 89 * @param mixed $version Version.
91 90 * @return string $version.
92 91 */
93 92 function stats_ignore_db_version( $version ) {
94 - if (
95 - is_admin() &&
96 - isset( $_GET['page'] ) && 'stats' === $_GET['page'] && // phpcs:ignore WordPress.Security.NonceVerification.Recommended
97 - isset( $_GET['chart'] ) && strpos( $_GET['chart'], 'admin-bar-hours' ) === 0 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput
98 - ) {
99 - global $wp_db_version;
100 - return $wp_db_version;
101 - }
102 - return $version;
93 + _deprecated_function( __FUNCTION__, 'jetpack-16.3', 'Automattic\Jetpack\Stats_Admin\Admin_Bar::ignore_db_version' );
94 + return Stats_Admin_Bar::ignore_db_version( $version );
103 95 }
104 96
105 97 /**
106 98 * Maps view_stats cap to read cap as needed.
@@ -134,9 +126,9 @@
134 126 * Stats Build View Data.
135 127 *
136 128 * @deprecated 11.5
137 129 * @access public
138 - * @return array.
130 + * @return array
139 131 */
140 132 function stats_build_view_data() {
141 133 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Tracking_Pixel::build_view_data' );
142 134 return Stats_Tracking_Pixel::build_view_data();
@@ -147,9 +139,9 @@
147 139 *
148 140 * @deprecated 11.5
149 141 *
150 142 * @access public
151 - * @return array.
143 + * @return array
152 144 */
153 145 function stats_get_options() {
154 146 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::get_options' );
155 147 return Stats_Options::get_options();
@@ -161,9 +153,9 @@
161 153 * @deprecated 11.5
162 154 *
163 155 * @access public
164 156 * @param mixed $option Option.
165 - * @return mixed|null.
157 + * @return mixed|null
166 158 */
167 159 function stats_get_option( $option ) {
168 160 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::get_option' );
169 161 return Stats_Options::get_option( $option );
@@ -176,9 +168,9 @@
176 168 *
177 169 * @access public
178 170 * @param mixed $option Option.
179 171 * @param mixed $value Value.
180 - * @return bool.
172 + * @return bool
181 173 */
182 174 function stats_set_option( $option, $value ) {
183 175 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Automattic\Jetpack\Stats\Options::set_option' );
184 176 return Stats_Options::set_option( $option, $value );
@@ -227,9 +219,9 @@
227 219 $redirect_url = str_replace( array( '/wp-admin/index.php?', '/wp-admin/?' ), '/wp-admin/admin.php?', isset( $_SERVER['REQUEST_URI'] ) ? filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : null );
228 220 $relative_pos = strpos( $redirect_url, '/wp-admin/' );
229 221 if ( false !== $relative_pos ) {
230 222 wp_safe_redirect( admin_url( substr( $redirect_url, $relative_pos + 10 ) ) );
231 - exit;
223 + exit( 0 );
232 224 }
233 225 }
234 226
235 227 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -239,20 +231,28 @@
239 231 Stats_Main::update_new_stats_status( true );
240 232 }
241 233
242 234 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
243 - if ( ( new Host() )->is_woa_site() || ! Stats_Options::get_option( 'enable_odyssey_stats' ) || isset( $_GET['noheader'] ) ) {
235 + if ( ! Stats_Options::get_option( 'enable_odyssey_stats' ) || isset( $_GET['noheader'] ) ) {
244 236 // Show old Jetpack Stats interface for:
245 - // - Atomic sites.
246 237 // - When the "enable_odyssey_stats" option is disabled.
247 238 // - 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' );
239 + $hook = Admin_Menu::add_menu(
240 + __( 'Stats', 'jetpack' ),
241 + __( 'Stats', 'jetpack' ),
242 + 'view_stats',
243 + 'stats',
244 + 'jetpack_admin_ui_stats_report_page_wrapper',
245 + null,
246 + array(
247 + 'product' => 'stats',
248 + 'key' => 'jetpack-stats',
249 + )
250 + );
249 251 add_action( "load-$hook", 'stats_reports_load' );
250 252 } else {
251 253 // 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' ) );
254 + Stats_Dashboard::init();
255 255 }
256 256 }
257 257
258 258 /**
@@ -292,9 +292,8 @@
292 292 // Detect if JS is on. If so, remove cookie so next page load is via JS.
293 293 add_action( 'admin_print_footer_scripts', 'stats_js_remove_stnojs_cookie' );
294 294 } elseif ( ! isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
295 295 // Normal page load. Load page content via JS.
296 - add_action( 'admin_print_footer_scripts', 'stats_js_load_page_via_ajax' );
297 296 add_action( 'admin_print_footer_scripts', 'stats_script_dismiss_nudge_handler' );
298 297 }
299 298 }
300 299
@@ -313,10 +312,10 @@
313 312 element.classList.toggle( "is-hidden" );
314 313 // Send an AJAX request.
315 314 // Note we can provide a 'postponed_for' parameter to set the delay.
316 315 // 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' ) ); ?>;
316 + let nonce = <?php echo wp_json_encode( wp_create_nonce( 'wp_rest' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
317 + let url = <?php echo wp_json_encode( rest_url( '/jetpack/v4/stats-app/stats/notices' ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ); ?>;
319 318 let data = {
320 319 id: 'opt_in_new_stats',
321 320 status: 'postponed',
322 321 };
@@ -344,16 +343,8 @@
344 343 max-width: 1040px;
345 344 margin: 0 auto;
346 345 overflow: hidden;
347 346 }
348 -
349 -#stats-loading-wrap p {
350 - text-align: center;
351 - font-size: 2em;
352 - margin-bottom: 3em;
353 - height: 64px;
354 - line-height: 64px;
355 -}
356 347 </style>
357 348 <?php
358 349 }
359 350
@@ -367,9 +358,9 @@
367 358 $parsed = wp_parse_url( admin_url() );
368 359 ?>
369 360 <script type="text/javascript">
370 361 /* <![CDATA[ */
371 -document.cookie = 'stnojs=0; expires=Wed, 9 Mar 2011 16:55:50 UTC; path=<?php echo esc_js( $parsed['path'] ); ?>';
362 +document.cookie = <?php echo wp_json_encode( 'stnojs=0; expires=Wed, 9 Mar 2011 16:55:50 UTC; path=' . $parsed['path'], JSON_UNESCAPED_SLASHES | JSON_HEX_TAG ); ?>;
372 363 /* ]]> */
373 364 </script>
374 365 <?php
375 366 }
@@ -374,33 +365,8 @@
374 365 <?php
375 366 }
376 367
377 368 /**
378 - * Normal page load. Load page content via JS.
379 - *
380 - * @access public
381 - * @return void
382 - */
383 -function stats_js_load_page_via_ajax() {
384 - ?>
385 -<script type="text/javascript">
386 -/* <![CDATA[ */
387 -if ( -1 == document.location.href.indexOf( 'noheader' ) ) {
388 - jQuery( function( $ ) {
389 - const loadStatsUrl = new URL( document.location.href );
390 - loadStatsUrl.searchParams.append( 'noheader', 1 );
391 - $.get( loadStatsUrl.toString(), function( responseText ) {
392 - $( '#stats-loading-wrap' ).replaceWith( responseText );
393 - $( '#jp-stats-wrap' )[0].dispatchEvent( new Event( 'stats-loaded' ) );
394 - } );
395 - } );
396 -}
397 -/* ]]> */
398 -</script>
399 - <?php
400 -}
401 -
402 -/**
403 369 * Jetpack Admin Page Wrapper.
404 370 */
405 371 function jetpack_admin_ui_stats_report_page_wrapper() {
406 372 if ( ! isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) && empty( $_COOKIE['stnojs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -417,19 +383,110 @@
417 383 * @param bool $main_chart_only (default: false) Main Chart Only.
418 384 */
419 385 function stats_reports_page( $main_chart_only = false ) {
420 386 if ( isset( $_GET['dashboard'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
421 - return stats_dashboard_widget_content();
387 + stats_dashboard_widget_content();
388 + exit( 0 ); // @phan-suppress-current-line PhanPluginUnreachableCode -- Safer to include it even though stats_dashboard_widget_content() never returns.
422 389 }
423 390
424 - $blog_id = Stats_Options::get_option( 'blog_id' );
391 + $blog_id = Stats_Options::get_option( 'blog_id' );
392 + $learn_url = Redirect::get_url( 'jetpack-stats-learn-more' );
393 + $redirect_url = admin_url( 'admin.php?page=stats&enable_new_stats=1' );
394 + $stats_bg_url = plugins_url( 'images/odyssey-upgrade/background.png', JETPACK__PLUGIN_FILE );
395 + $stats_bg_gradient_url = plugins_url( 'images/odyssey-upgrade/gradient.png', JETPACK__PLUGIN_FILE );
425 396
426 - if ( ! $main_chart_only && ! isset( $_GET['noheader'] ) && empty( $_GET['nojs'] ) && empty( $_COOKIE['stnojs'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
427 - $nojs_url = add_query_arg( 'nojs', '1' );
428 - $http = is_ssl() ? 'https' : 'http';
429 - // Loading message. No JS fallback message.
397 + if ( ! $main_chart_only && ! isset( $_GET['noheader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
430 398 ?>
431 399
400 + <style>
401 + .stats-odyssey-notice {
402 + display: flex;
403 + font-size: var( --font-body );
404 +
405 + border: 1px solid var( --jp-gray-5 );
406 + border-left-color: var( --jp-black );
407 + border-left-width: 6px;
408 + border-radius: 4px;
409 +
410 + margin-top: 24px;
411 + background: white;
412 + position: relative;
413 + }
414 + .stats-odyssey-notice--content__highlighted {
415 + border-left-color: var( --jp-red );
416 + }
417 + .stats-odyssey-notice--content {
418 + padding: 24px 0 24px 30px;
419 + font-size: 2em;
420 + width: 100%;
421 + }
422 + .stats-odyssey-notice--content-header {
423 + font-size: 24px;
424 + line-height: 32px;
425 + margin: 0;
426 + margin-bottom: 8px;
427 + }
428 + .stats-odyssey-notice--content-text {
429 + font-size: 16px;
430 + margin: 0;
431 + }
432 + .stats-odyssey-notice--image-container {
433 + background-image: url("<?php echo esc_url( $stats_bg_url ); ?>"), url("<?php echo esc_url( $stats_bg_gradient_url ); ?>");
434 + background-size: cover;
435 + padding-right: 28px;
436 + width: 100%;
437 + }
438 + .stats-odyssey-notice--close-button {
439 + position: absolute;
440 + top: 1rem;
441 + right: 1rem;
442 + background-color: transparent;
443 + border: none;
444 + cursor: pointer;
445 + }
446 + .stats-odyssey-notice--action-bar {
447 + display: flex;
448 + align-items: center;
449 + margin-top: 24px;
450 + }
451 + .stats-odyssey-notice--primary-button {
452 + margin-right: 18px;
453 + padding-left: 20px;
454 + padding-right: 20px;
455 + font-size: 16px;
456 + border-color: black;
457 + background-color: black;
458 + }
459 + .stats-odyssey-notice--primary-button:hover {
460 + border-color: #3c434a;
461 + background-color: #3c434a;
462 + }
463 + .is-primary-link {
464 + color: white;
465 + text-decoration: none;
466 + }
467 + .is-primary-link:active {
468 + color: white;
469 + }
470 + .is-primary-link:focus {
471 + color: white;
472 + box-shadow: none;
473 + outline: none;
474 + }
475 + .is-primary-link:hover {
476 + color: white;
477 + }
478 + .is-secondary-link {
479 + color: black;
480 + font-size: var( --font-body );
481 + }
482 + .is-secondary-link:hover {
483 + color: black;
484 + }
485 + .is-hidden {
486 + display: none;
487 + }
488 + </style>
432 489 <div id="jp-stats-wrap">
433 490 <div class="wrap">
434 491 <h1><?php esc_html_e( 'Jetpack Stats', 'jetpack' ); ?>
435 492 <?php
@@ -437,9 +494,9 @@
437 494 $i18n_headers = jetpack_get_module_i18n( 'stats' );
438 495 ?>
439 496 <a
440 497 style="font-size:13px;"
441 - href="<?php echo esc_url( admin_url( 'admin.php?page=jetpack#/settings?term=' . rawurlencode( $i18n_headers['name'] ) ) ); ?>"
498 + href="<?php echo esc_url( admin_url( 'admin.php?page=jetpack-settings#/settings?term=' . rawurlencode( $i18n_headers['name'] ?? '' ) ) ); ?>"
442 499 >
443 500 <?php esc_html_e( 'Configure', 'jetpack' ); ?>
444 501 </a>
445 502 <?php
@@ -444,27 +501,27 @@
444 501 </a>
445 502 <?php
446 503 endif;
447 504
448 - /**
449 - * Sets external resource URL.
450 - *
451 - * @module stats
452 - *
453 - * @since 1.4.0
454 - * @todo Clean up various uses of this filter. It's seemingly filtering different types of images in different places.
455 - *
456 - * @param string $args URL of external resource.
457 - */
458 - $static_url = apply_filters( 'jetpack_static_url', "{$http}://en.wordpress.com/i/loading/loading-64.gif" );
459 505 ?>
460 506 </h2>
461 507 </div>
462 - <div id="stats-loading-wrap" class="wrap">
463 - <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>
508 + <div class="wrap">
509 + <div class="stats-odyssey-notice stats-odyssey-notice--content__highlighted">
510 + <div class="stats-odyssey-notice--content">
511 + <h2 class="stats-odyssey-notice--content-header"><?php esc_html_e( 'Deprecated Jetpack Stats Experience', 'jetpack' ); ?></h2>
512 + <p class="stats-odyssey-notice--content-text"><?php esc_html_e( 'The old Jetpack Stats has been deprecated. Please click the button to enable the new experience.', 'jetpack' ); ?></p>
513 + <div class="stats-odyssey-notice--action-bar">
514 + <button class="dops-button stats-odyssey-notice--primary-button">
515 + <a class="is-primary-link" href="<?php echo esc_url( $redirect_url ); ?>"><?php esc_html_e( 'Switch to new Stats', 'jetpack' ); ?></a>
516 + </button>
517 + <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>
518 + </div>
519 + </div>
520 + <div class="stats-odyssey-notice--image-container"></div>
521 + </div>
466 522 </div>
523 + <p></p>
467 524 </div>
468 525 <?php
469 526 return;
470 527 }
@@ -521,21 +578,20 @@
521 578 }
522 579 } elseif ( null === $vals ) {
523 580 $q[ $var ] = '';
524 581 } elseif ( 'data' === $vals ) {
525 - if ( 'index.php' === substr( $val, 0, 9 ) ) {
582 + if ( str_starts_with( $val, 'index.php' ) ) {
526 583 $q[ $var ] = $val;
527 584 }
528 585 }
529 586 }
530 587
588 + $url = 'https://' . STATS_DASHBOARD_SERVER . '/wp-admin/index.php';
531 589 if ( isset( $_GET['chart'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
532 590 if ( preg_match( '/^[a-z0-9-]+$/', $_GET['chart'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput
533 591 $chart = sanitize_title( $_GET['chart'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput
534 592 $url = 'https://' . STATS_DASHBOARD_SERVER . "/wp-includes/charts/{$chart}.php";
535 593 }
536 - } else {
537 - $url = 'https://' . STATS_DASHBOARD_SERVER . '/wp-admin/index.php';
538 594 }
539 595
540 596 $url = add_query_arg( $q, $url );
541 597 $method = 'GET';
@@ -543,34 +599,19 @@
543 599 $user_id = 0; // Means use the blog token.
544 600
545 601 $get = Client::remote_request( compact( 'url', 'method', 'timeout', 'user_id' ) );
546 602 $get_code = wp_remote_retrieve_response_code( $get );
547 - if ( is_wp_error( $get ) || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
603 + if ( is_wp_error( $get ) || $get_code === '' || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
548 604 stats_print_wp_remote_error( $get, $url );
549 - } else {
550 - if ( ! empty( $get['headers']['content-type'] ) ) {
551 - $type = $get['headers']['content-type'];
552 - if ( substr( $type, 0, 5 ) === 'image' ) {
553 - $img = $get['body'];
554 - header( 'Content-Type: ' . $type );
555 - header( 'Content-Length: ' . strlen( $img ) );
556 - echo $img; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
557 - die();
558 - }
605 + } elseif ( ! empty( $get['headers']['content-type'] ) ) {
606 + $type = $get['headers']['content-type'];
607 + if ( str_starts_with( $type, 'image' ) ) {
608 + $img = $get['body'];
609 + header( 'Content-Type: ' . $type );
610 + header( 'Content-Length: ' . strlen( $img ) );
611 + echo $img; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
612 + die( 0 );
559 613 }
560 - $body = stats_convert_post_titles( $get['body'] );
561 - $body = stats_convert_chart_urls( $body );
562 - $body = stats_convert_image_urls( $body );
563 - $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 );
573 614 }
574 615
575 616 if ( isset( $_GET['page'] ) && 'stats' === $_GET['page'] && ! isset( $_GET['chart'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
576 617 $tracking = new Tracking();
@@ -577,246 +618,13 @@
577 618 $tracking->record_user_event( 'wpa_page_view', array( 'path' => 'old_stats' ) );
578 619 }
579 620
580 621 if ( isset( $_GET['noheader'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
581 - die;
622 + die( 0 );
582 623 }
583 624 }
584 625
585 626 /**
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 - * Stats Convert Admin Urls.
809 - *
810 - * @access public
811 - * @param mixed $html HTML.
812 - * @return string
813 - */
814 -function stats_convert_admin_urls( $html ) {
815 - return str_replace( 'index.php?page=stats', 'admin.php?page=stats', $html );
816 -}
817 -
818 -/**
819 627 * Stats Convert Image URLs.
820 628 *
821 629 * @access public
822 630 * @param mixed $html HTML.
@@ -917,63 +725,30 @@
917 725
918 726 /**
919 727 * Stats Admin Bar Head.
920 728 *
729 + * @deprecated 16.3
730 + *
921 731 * @access public
922 732 * @return void
923 733 */
924 734 function stats_admin_bar_head() {
925 - if ( ! Stats_Options::get_option( 'admin_bar' ) ) {
926 - return;
927 - }
928 -
929 - if ( ! current_user_can( 'view_stats' ) ) {
930 - return;
931 - }
932 -
933 - if ( ! is_admin_bar_showing() ) {
934 - return;
935 - }
936 -
937 - add_action( 'admin_bar_menu', 'stats_admin_bar_menu', 100 );
938 - ?>
939 -
940 -<style data-ampdevmode type='text/css'>
941 -#wpadminbar .quicklinks li#wp-admin-bar-stats {
942 - height: 32px;
735 + _deprecated_function( __FUNCTION__, 'jetpack-16.3', 'Automattic\Jetpack\Stats_Admin\Admin_Bar::maybe_add_chart' );
736 + Stats_Admin_Bar::maybe_add_chart();
943 737 }
944 -#wpadminbar .quicklinks li#wp-admin-bar-stats a {
945 - height: 32px;
946 - padding: 0;
947 -}
948 -#wpadminbar .quicklinks li#wp-admin-bar-stats a div {
949 - height: 32px;
950 - width: 95px;
951 - overflow: hidden;
952 - margin: 0 10px;
953 -}
954 -#wpadminbar .quicklinks li#wp-admin-bar-stats a:hover div {
955 - width: auto;
956 - margin: 0 8px 0 10px;
957 -}
958 -#wpadminbar .quicklinks li#wp-admin-bar-stats a img {
959 - height: 24px;
960 - margin: 4px 0;
961 - max-width: none;
962 - border: none;
963 -}
964 -</style>
965 - <?php
966 -}
967 738
968 739 /**
969 740 * Gets the image source of the given stats chart.
970 741 *
742 + * @deprecated 16.3
743 + *
971 744 * @param string $chart Name of the chart.
972 745 * @param array $args Extra list of argument to use in the image source.
973 746 * @return string An image source.
974 747 */
975 748 function stats_get_image_chart_src( $chart, $args = array() ) {
749 + _deprecated_function( __FUNCTION__, 'jetpack-16.3', 'Automattic\Jetpack\Stats_Admin\Admin_Bar::get_chart_src' );
750 +
976 751 $url = add_query_arg( 'page', 'stats', admin_url( 'admin.php' ) );
977 752
978 753 return add_query_arg(
979 754 array_merge(
@@ -990,41 +765,30 @@
990 765
991 766 /**
992 767 * Stats AdminBar.
993 768 *
769 + * @deprecated 16.3
770 + *
994 771 * @access public
995 772 * @param mixed $wp_admin_bar WPAdminBar.
996 773 * @return void
997 774 */
998 775 function stats_admin_bar_menu( &$wp_admin_bar ) {
999 - $img_src = esc_attr( stats_get_image_chart_src( 'admin-bar-hours-scale' ) );
1000 - $img_src_2x = esc_attr( stats_get_image_chart_src( 'admin-bar-hours-scale-2x' ) );
1001 - $alt = esc_attr( __( 'Stats', 'jetpack' ) );
1002 - $title = esc_attr( __( 'Views over 48 hours. Click for more Jetpack Stats.', 'jetpack' ) );
1003 -
1004 - $menu = array(
1005 - 'id' => 'stats',
1006 - 'href' => add_query_arg( 'page', 'stats', admin_url( 'admin.php' ) ), // no menu_page_url() blog-side.
1007 - 'title' => "<div><img src='$img_src' srcset='$img_src 1x, $img_src_2x 2x' width='112' height='24' alt='$alt' title='$title'></div>",
1008 - );
1009 -
1010 - $wp_admin_bar->add_menu( $menu );
776 + _deprecated_function( __FUNCTION__, 'jetpack-16.3', 'Automattic\Jetpack\Stats_Admin\Admin_Bar::add_chart_node' );
777 + Stats_Admin_Bar::add_chart_node( $wp_admin_bar );
1011 778 }
1012 779
1013 780 /**
781 + * Adds a Stats link to the site-name admin bar submenu, alongside Dashboard.
1014 782 *
1015 - * Deprecated. The stats module should not update blog details. This is handled by Sync.
783 + * @deprecated 16.3
1016 784 *
1017 - * Stats Update Blog.
1018 - *
1019 785 * @access public
1020 786 * @return void
1021 - *
1022 - * @deprecated since 10.3.
1023 787 */
1024 -function stats_update_blog() {
1025 - _deprecated_function( __METHOD__, 'jetpack-10.3' );
1026 - XMLRPC_Async_Call::add_call( 'jetpack.updateBlog', 0, stats_get_blog() );
788 +function stats_add_link_to_admin_bar_site_menu() {
789 + _deprecated_function( __FUNCTION__, 'jetpack-16.3', 'Automattic\Jetpack\Stats_Admin\Admin_Bar::add_site_menu_link' );
790 + Stats_Admin_Bar::add_site_menu_link();
1027 791 }
1028 792
1029 793 /**
1030 794 * Stats Get Blog.
@@ -1214,9 +978,9 @@
1214 978 *
1215 979 * TODO: This should be moved into class-jetpack-stats-dashboard-widget.php.
1216 980 *
1217 981 * @access public
1218 - * @return void
982 + * @return never
1219 983 */
1220 984 function stats_dashboard_widget_content() {
1221 985 $width = isset( $_GET['width'] ) ? intval( $_GET['width'] ) / 2 : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1222 986 $height = isset( $_GET['height'] ) ? intval( $_GET['height'] ) - 36 : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
@@ -1255,9 +1019,9 @@
1255 1019 $user_id = 0; // Means use the blog token.
1256 1020
1257 1021 $get = Client::remote_request( compact( 'url', 'method', 'timeout', 'user_id' ) );
1258 1022 $get_code = wp_remote_retrieve_response_code( $get );
1259 - if ( is_wp_error( $get ) || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
1023 + if ( is_wp_error( $get ) || $get_code === '' || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
1260 1024 stats_print_wp_remote_error( $get, $url );
1261 1025 } else {
1262 1026 $body = stats_convert_post_titles( $get['body'] );
1263 1027 $body = stats_convert_chart_urls( $body );
@@ -1360,9 +1124,9 @@
1360 1124 </div>
1361 1125 </div>
1362 1126 </div>
1363 1127 <?php
1364 - exit;
1128 + exit( 0 );
1365 1129 }
1366 1130
1367 1131 /**
1368 1132 * Stats Print WP Remote Error.
@@ -1374,9 +1138,9 @@
1374 1138 */
1375 1139 function stats_print_wp_remote_error( $get, $url ) {
1376 1140 $state_name = 'stats_remote_error_' . substr( md5( $url ), 0, 8 );
1377 1141 $previous_error = Jetpack::state( $state_name );
1378 - $error = md5( wp_json_encode( compact( 'get', 'url' ) ) );
1142 + $error = md5( wp_json_encode( compact( 'get', 'url' ), JSON_UNESCAPED_SLASHES ) );
1379 1143 Jetpack::state( $state_name, $error );
1380 1144 if ( $error !== $previous_error ) {
1381 1145 ?>
1382 1146 <div class="wrap">
@@ -1436,8 +1200,9 @@
1436 1200 * @type string $days The length of the desired time frame. Default is 30. Maximum 90 days.
1437 1201 * @type int $limit The maximum number of records to return. Default is 10. Maximum 100.
1438 1202 * @type int $post_id The ID of the post to retrieve stats data for
1439 1203 * @type string $summarize If present, summarizes all matching records. Default Null.
1204 + * @type int $blog_id The WordPress.com blog ID to retrieve stats data for. Default is the current blog.
1440 1205 *
1441 1206 * }
1442 1207 *
1443 1208 * @return array {
@@ -1459,13 +1224,13 @@
1459 1224 'days' => false,
1460 1225 'limit' => 3,
1461 1226 'post_id' => false,
1462 1227 'summarize' => '',
1228 + 'blog_id' => Jetpack_Options::get_option( 'id' ),
1463 1229 );
1464 1230
1465 - $args = wp_parse_args( $args, $defaults );
1466 - $args['table'] = $table;
1467 - $args['blog_id'] = Jetpack_Options::get_option( 'id' );
1231 + $args = wp_parse_args( $args, $defaults );
1232 + $args['table'] = $table;
1468 1233
1469 1234 $stats_csv_url = add_query_arg( $args, 'https://stats.wordpress.com/csv.php' );
1470 1235
1471 1236 $key = md5( $stats_csv_url );
@@ -1535,9 +1300,9 @@
1535 1300 $user_id = 0; // Blog token.
1536 1301
1537 1302 $get = Client::remote_request( compact( 'url', 'method', 'timeout', 'user_id' ) );
1538 1303 $get_code = wp_remote_retrieve_response_code( $get );
1539 - if ( is_wp_error( $get ) || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
1304 + if ( is_wp_error( $get ) || $get_code === '' || ( 2 !== (int) ( $get_code / 100 ) && 304 !== $get_code ) || empty( $get['body'] ) ) {
1540 1305 return array(); // @todo: return an error?
1541 1306 } else {
1542 1307 return stats_str_getcsv( $get['body'] );
1543 1308 }
@@ -1548,13 +1313,19 @@
1548 1313 *
1549 1314 * @since 9.7.0 Remove custom handling since str_getcsv is available on all servers running this now.
1550 1315 *
1551 1316 * @param mixed $csv CSV.
1552 - * @return array.
1317 + * @return array
1553 1318 */
1554 1319 function stats_str_getcsv( $csv ) {
1555 - $lines = str_getcsv( $csv, "\n" );
1556 - return array_map( 'str_getcsv', $lines );
1320 + // @todo Correctly handle embedded newlines. Note, despite claims online, `str_getcsv( $csv, "\n" )` does not actually work.
1321 + $lines = explode( "\n", rtrim( $csv, "\n" ) );
1322 + return array_map(
1323 + function ( $line ) {
1324 + return str_getcsv( $line, ',', '"', '' );
1325 + },
1326 + $lines
1327 + );
1557 1328 }
1558 1329
1559 1330 /**
1560 1331 * Abstract out building the rest api stats path.
@@ -1574,9 +1345,9 @@
1574 1345 * @access public
1575 1346 * @deprecated 11.5 Use WPCOM_Stats available methodsinstead.
1576 1347 * @param array $args (default: array()) The args that are passed to the endpoint.
1577 1348 * @param string $resource (default: '') Optional sub-endpoint following /stats/.
1578 - * @return array|WP_Error.
1349 + * @return array|WP_Error
1579 1350 */
1580 1351 function stats_get_from_restapi( $args = array(), $resource = '' ) {
1581 1352 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Please checkout the methods available in Automattic\Jetpack\Stats\WPCOM_Stats' );
1582 1353 $endpoint = jetpack_stats_api_path( $resource );
@@ -1581,9 +1352,9 @@
1581 1352 _deprecated_function( __METHOD__, 'jetpack-11.5', 'Please checkout the methods available in Automattic\Jetpack\Stats\WPCOM_Stats' );
1582 1353 $endpoint = jetpack_stats_api_path( $resource );
1583 1354 $api_version = '1.1';
1584 1355 $args = wp_parse_args( $args, array() );
1585 - $cache_key = md5( implode( '|', array( $endpoint, $api_version, wp_json_encode( $args ) ) ) );
1356 + $cache_key = md5( implode( '|', array( $endpoint, $api_version, wp_json_encode( $args, JSON_UNESCAPED_SLASHES ) ) ) );
1586 1357
1587 1358 $transient_name = "jetpack_restapi_stats_cache_{$cache_key}";
1588 1359
1589 1360 $stats_cache = get_transient( $transient_name );
@@ -1620,107 +1391,8 @@
1620 1391 return $return;
1621 1392 }
1622 1393
1623 1394 /**
1624 - * Load CSS needed for Stats column width in WP-Admin area.
1625 - *
1626 - * @since 4.7.0
1627 - */
1628 -function jetpack_stats_load_admin_css() {
1629 - ?>
1630 - <style type="text/css">
1631 - .fixed .column-stats {
1632 - width: 5em;
1633 - }
1634 - </style>
1635 - <?php
1636 -}
1637 -
1638 -/**
1639 - * Set header for column that allows to view an entry's stats.
1640 - *
1641 - * @param array $columns An array of column names.
1642 - *
1643 - * @since 4.7.0
1644 - *
1645 - * @return mixed
1646 - */
1647 -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 - ) {
1664 - return $columns;
1665 - }
1666 -
1667 - // Array-Fu to add before comments.
1668 - $pos = array_search( 'comments', array_keys( $columns ), true );
1669 -
1670 - // Fallback to the last position if the post type does not support comments.
1671 - if ( ! is_int( $pos ) ) {
1672 - $pos = count( $columns );
1673 - }
1674 -
1675 - // Final fallback, if the array was malformed by another plugin for example.
1676 - if ( ! is_int( $pos ) ) {
1677 - return $columns;
1678 - }
1679 -
1680 - $chunks = array_chunk( $columns, $pos, true );
1681 - $chunks[0]['stats'] = esc_html__( 'Stats', 'jetpack' );
1682 -
1683 - return call_user_func_array( 'array_merge', $chunks );
1684 -}
1685 -
1686 -/**
1687 - * Set content for cell with link to an entry's stats in Odyssey Stats.
1688 - *
1689 - * @param string $column The name of the column to display.
1690 - * @param int $post_id The current post ID.
1691 - *
1692 - * @since 4.7.0
1693 - *
1694 - * @return mixed
1695 - */
1696 -function jetpack_stats_post_table_cell( $column, $post_id ) {
1697 - if ( 'stats' === $column ) {
1698 - if ( 'publish' !== get_post_status( $post_id ) ) {
1699 - printf(
1700 - '<span aria-hidden="true">—</span><span class="screen-reader-text">%s</span>',
1701 - esc_html__( 'No stats', 'jetpack' )
1702 - );
1703 - } 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(
1707 - 'calypso-stats-post',
1708 - array(
1709 - 'path' => $post_id,
1710 - )
1711 - );
1712 -
1713 - printf(
1714 - '<a href="%s" title="%s" class="dashicons dashicons-chart-bar" target="_blank"></a>',
1715 - esc_url( $stats_post_url ),
1716 - esc_html__( 'View stats for this post', 'jetpack' )
1717 - );
1718 - }
1719 - }
1720 -}
1721 -
1722 -/**
1723 1395 * Add the Jetpack plugin version to the stats tracking data.
1724 1396 *
1725 1397 * @param array $kvs The stats array in key values.
1726 1398 * @return array
@@ -1737,14 +1409,8 @@
1737 1409 * @param array $stats_array The stats array.
1738 1410 * @return WP_Error|Object|null
1739 1411 */
1740 1412 function convert_stats_array_to_object( $stats_array ) {
1413 + _deprecated_function( __FUNCTION__, 'jetpack-13.2', 'Automattic\Jetpack\Stats\WPCOM_Stats->convert_stats_array_to_object' );
1741 1414
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 );
1415 + return ( new WPCOM_Stats() )->convert_stats_array_to_object( $stats_array );
1750 1416 }