Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
19.37% |
61 / 315 |
|
14.29% |
3 / 21 |
CRAP | n/a |
0 / 0 |
|
| wpcomsh_get_attachment_url | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 | |||
| wpcomsh_jetpack_sso_auth_cookie_expiration | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
20 | |||
| wpcomsh_bypass_jetpack_sso_login | |
0.00% |
0 / 16 |
|
0.00% |
0 / 1 |
30 | |||
| wpcomsh_modify_jetpack_sso_allowed_actions | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| wpcomsh_admin_enqueue_style | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
| wpcomsh_allow_custom_wp_options | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
2 | |||
| check_site_has_pending_automated_transfer | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| wpcomsh_jetpack_api_fix_unserializable_track_number | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| wpcomsh_filter_outgoing_user_agent | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| wpcomsh_allowed_redirect_hosts | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
| wpcomsh_make_content_clickable | |
73.33% |
11 / 15 |
|
0.00% |
0 / 1 |
6.68 | |||
| wpcomsh_hide_scan_threats_from_transients | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| wpcomsh_remove_threats_from_toolbar | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| wpcom_hide_scan_threats_from_api | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
56 | |||
| wpcomsh_stats_timezone_string | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
6 | |||
| wpcomsh_footer_rum_js | |
76.47% |
26 / 34 |
|
0.00% |
0 / 1 |
8.83 | |||
| wpcomsh_get_woo_rum_data | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
| wpcomsh_woocommerce_tracker_data | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
| wpcomsh_record_tracks_event | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
2 | |||
| wpcomsh_jetpack_filter_tos_for_tracking | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
| wpcomsh_avoid_proxied_v2_banner | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
12 | |||
| 1 | <?php |
| 2 | /** |
| 3 | * Plugin Name: WordPress.com Site Helper |
| 4 | * Description: A helper for connecting WordPress.com sites to external host infrastructure. |
| 5 | * Version: 9.0.0 |
| 6 | * Author: Automattic |
| 7 | * Author URI: http://automattic.com/ |
| 8 | * |
| 9 | * @package wpcomsh |
| 10 | */ |
| 11 | |
| 12 | define( 'WPCOMSH_VERSION', '9.0.0' ); |
| 13 | |
| 14 | // Loaded first: fatal-error screen filter + one-shot plugin-deactivation endpoint. |
| 15 | // The deactivator also needs to load before any regular plugin, so in production |
| 16 | // a stub in wp-content/mu-plugins/ should re-include fatal-plugin-deactivator.php |
| 17 | // directly (see wpcom-fatal-error/mu-plugin-stub.php). |
| 18 | require_once __DIR__ . '/wpcom-fatal-error/load.php'; |
| 19 | |
| 20 | // If true, Typekit fonts will be available in addition to Google fonts |
| 21 | add_filter( 'jetpack_fonts_enable_typekit', '__return_true' ); |
| 22 | |
| 23 | // This exists only on the Atomic platform. Blank if migrated elsewhere, so it doesn't fatal. |
| 24 | if ( ! class_exists( 'Atomic_Persistent_Data' ) ) { |
| 25 | require_once __DIR__ . '/class-atomic-persistent-data.php'; |
| 26 | } |
| 27 | |
| 28 | require_once __DIR__ . '/constants.php'; |
| 29 | require_once __DIR__ . '/wpcom-features/functions-wpcom-features.php'; |
| 30 | require_once __DIR__ . '/wpcom-marketplace/software/class-marketplace-software-manager.php'; |
| 31 | require_once __DIR__ . '/functions.php'; |
| 32 | require_once __DIR__ . '/i18n.php'; |
| 33 | require_once __DIR__ . '/lib/require-lib.php'; |
| 34 | |
| 35 | require_once __DIR__ . '/plugin-hotfixes.php'; |
| 36 | |
| 37 | require_once __DIR__ . '/footer-credit/footer-credit.php'; |
| 38 | require_once __DIR__ . '/storefront/storefront.php'; |
| 39 | require_once __DIR__ . '/custom-colors/colors.php'; |
| 40 | require_once __DIR__ . '/storage/storage.php'; |
| 41 | require_once __DIR__ . '/imports/class-backup-import-manager.php'; |
| 42 | |
| 43 | // Interoperability with the core WordPress data privacy functionality (See also "GDPR") |
| 44 | require_once __DIR__ . '/privacy/class-wp-privacy-participating-plugins.php'; |
| 45 | |
| 46 | // Functionality to make sites private and only accessible to members with appropriate capabilities |
| 47 | require_once __DIR__ . '/private-site/private-site.php'; |
| 48 | |
| 49 | // Updates customizer Save/Publish labels to avoid confusion on launching vs saving changes on a site. |
| 50 | require_once __DIR__ . '/customizer-fixes/customizer-fixes.php'; |
| 51 | |
| 52 | require_once __DIR__ . '/class-wpcomsh-log.php'; |
| 53 | require_once __DIR__ . '/safeguard/plugins.php'; |
| 54 | require_once __DIR__ . '/jetpack-token-error-header/class-atomic-record-jetpack-token-errors.php'; |
| 55 | |
| 56 | /** |
| 57 | * WP.com Widgets (in alphabetical order) |
| 58 | */ |
| 59 | require_once __DIR__ . '/widgets/class-gravatar-widget.php'; |
| 60 | require_once __DIR__ . '/widgets/class-jetpack-posts-i-like-widget.php'; |
| 61 | require_once __DIR__ . '/widgets/class-music-player-widget.php'; |
| 62 | require_once __DIR__ . '/widgets/class-widget-authors-grid.php'; |
| 63 | require_once __DIR__ . '/widgets/class-wpcom-freshly-pressed-widget.php'; |
| 64 | require_once __DIR__ . '/widgets/class-wpcom-widget-recent-comments.php'; |
| 65 | require_once __DIR__ . '/widgets/class-wpcom-widget-reservations.php'; |
| 66 | |
| 67 | // WP.com Category Cloud widget |
| 68 | require_once __DIR__ . '/widgets/class-wpcom-category-cloud-widget.php'; |
| 69 | // Override core tag cloud widget to add a settable `limit` parameter |
| 70 | require_once __DIR__ . '/widgets/class-wpcom-tag-cloud-widget.php'; |
| 71 | |
| 72 | require_once __DIR__ . '/widgets/tlkio/class-tlkio-widget.php'; |
| 73 | require_once __DIR__ . '/widgets/class-widget-top-clicks.php'; |
| 74 | require_once __DIR__ . '/widgets/class-pd-top-rated.php'; |
| 75 | require_once __DIR__ . '/widgets/class-jetpack-widget-twitter.php'; |
| 76 | |
| 77 | /* |
| 78 | * Autoloader check: This ensures the plugin doesn't fatal if activated before |
| 79 | * `composer install` has been run. This is a common oversight during development |
| 80 | * setup. The admin notice helps developers quickly identify the issue. |
| 81 | */ |
| 82 | $jetpack_autoloader = __DIR__ . '/vendor/autoload_packages.php'; |
| 83 | if ( is_readable( $jetpack_autoloader ) ) { |
| 84 | require_once $jetpack_autoloader; |
| 85 | } else { |
| 86 | if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { |
| 87 | error_log( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log |
| 88 | __( 'Error loading autoloader file for WordPress.com Site Helper plugin', 'wpcomsh' ) |
| 89 | ); |
| 90 | } |
| 91 | |
| 92 | add_action( |
| 93 | 'admin_notices', |
| 94 | function () { |
| 95 | if ( get_current_screen()->id !== 'plugins' ) { |
| 96 | return; |
| 97 | } |
| 98 | |
| 99 | $message = sprintf( |
| 100 | wp_kses( |
| 101 | /* translators: Placeholder is a link to a support document. */ |
| 102 | __( 'Your installation of WordPress.com Site Helper is incomplete. If you installed WordPress.com Site Helper from GitHub, please refer to <a href="%1$s" target="_blank" rel="noopener noreferrer">this document</a> to set up your development environment. WordPress.com Site Helper must have Composer dependencies installed and built via the build command.', 'wpcomsh' ), |
| 103 | array( |
| 104 | 'a' => array( |
| 105 | 'href' => array(), |
| 106 | 'target' => array(), |
| 107 | 'rel' => array(), |
| 108 | ), |
| 109 | ) |
| 110 | ), |
| 111 | 'https://github.com/Automattic/jetpack/blob/trunk/docs/development-environment.md#building-your-project' |
| 112 | ); |
| 113 | wp_admin_notice( |
| 114 | $message, |
| 115 | array( |
| 116 | 'type' => 'error', |
| 117 | 'dismissible' => true, |
| 118 | ) |
| 119 | ); |
| 120 | } |
| 121 | ); |
| 122 | |
| 123 | return; |
| 124 | } |
| 125 | require_once __DIR__ . '/vendor/automattic/at-pressable-podcasting/podcasting.php'; |
| 126 | require_once __DIR__ . '/vendor/automattic/custom-fonts/custom-fonts.php'; |
| 127 | require_once __DIR__ . '/vendor/automattic/custom-fonts-typekit/custom-fonts-typekit.php'; |
| 128 | require_once __DIR__ . '/vendor/automattic/text-media-widget-styles/text-media-widget-styles.php'; |
| 129 | |
| 130 | // REST API |
| 131 | require_once __DIR__ . '/endpoints/rest-api.php'; |
| 132 | |
| 133 | // Load feature plugins. |
| 134 | require_once __DIR__ . '/feature-plugins/activitypub.php'; |
| 135 | require_once __DIR__ . '/feature-plugins/additional-css.php'; |
| 136 | require_once __DIR__ . '/feature-plugins/autosave-revision.php'; |
| 137 | require_once __DIR__ . '/feature-plugins/blaze.php'; |
| 138 | require_once __DIR__ . '/feature-plugins/coblocks-mods.php'; |
| 139 | require_once __DIR__ . '/feature-plugins/full-site-editing.php'; |
| 140 | require_once __DIR__ . '/feature-plugins/google-fonts.php'; |
| 141 | require_once __DIR__ . '/feature-plugins/gutenberg-mods.php'; |
| 142 | require_once __DIR__ . '/feature-plugins/headstart-util.php'; |
| 143 | require_once __DIR__ . '/feature-plugins/headstart-woocommerce-terms.php'; |
| 144 | require_once __DIR__ . '/feature-plugins/hooks.php'; |
| 145 | require_once __DIR__ . '/feature-plugins/managed-plugins.php'; |
| 146 | require_once __DIR__ . '/feature-plugins/managed-themes.php'; |
| 147 | require_once __DIR__ . '/feature-plugins/marketplace.php'; |
| 148 | require_once __DIR__ . '/feature-plugins/masterbar.php'; |
| 149 | require_once __DIR__ . '/feature-plugins/migrate-guru-canary.php'; |
| 150 | require_once __DIR__ . '/feature-plugins/nav-redesign.php'; |
| 151 | require_once __DIR__ . '/feature-plugins/post-list.php'; |
| 152 | require_once __DIR__ . '/feature-plugins/class-wpcomsh-recovery-mode-sync.php'; |
| 153 | require_once __DIR__ . '/feature-plugins/sensei-pro-mods.php'; |
| 154 | require_once __DIR__ . '/feature-plugins/smtp-email-priority.php'; |
| 155 | require_once __DIR__ . '/feature-plugins/staging-sites.php'; |
| 156 | require_once __DIR__ . '/feature-plugins/stats.php'; |
| 157 | require_once __DIR__ . '/feature-plugins/woocommerce.php'; |
| 158 | require_once __DIR__ . '/feature-plugins/wordpress-mods.php'; |
| 159 | require_once __DIR__ . '/feature-plugins/wpcom-reader-link.php'; |
| 160 | require_once __DIR__ . '/feature-plugins/reprint-exporter-api.php'; |
| 161 | require_once __DIR__ . '/feature-plugins/featured-image-in-email.php'; |
| 162 | |
| 163 | /** |
| 164 | * Conditionally load the jetpack-mu-wpcom package. |
| 165 | * |
| 166 | * JETPACK_MU_WPCOM_LOAD_VIA_BETA_PLUGIN=true will load the package via the Jetpack Beta Tester plugin, not wpcomsh. |
| 167 | */ |
| 168 | if ( ! defined( 'JETPACK_MU_WPCOM_LOAD_VIA_BETA_PLUGIN' ) || ! JETPACK_MU_WPCOM_LOAD_VIA_BETA_PLUGIN ) { |
| 169 | if ( class_exists( 'Automattic\Jetpack\Jetpack_Mu_Wpcom' ) ) { |
| 170 | Automattic\Jetpack\Jetpack_Mu_Wpcom::init(); |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | if ( ! class_exists( 'Jetpack_Data' ) ) { |
| 175 | require_once __DIR__ . '/feature-plugins/class-jetpack-data.php'; |
| 176 | } |
| 177 | |
| 178 | // Front end notices. |
| 179 | require_once __DIR__ . '/frontend-notices/wpcomsh-frontend-notices.php'; |
| 180 | |
| 181 | // wp-admin Notices |
| 182 | require_once __DIR__ . '/notices/plan-notices.php'; |
| 183 | require_once __DIR__ . '/notices/storage-notices.php'; |
| 184 | require_once __DIR__ . '/notices/php-version-notices.php'; |
| 185 | require_once __DIR__ . '/notices/media-library-private-site-cdn-notice.php'; |
| 186 | require_once __DIR__ . '/notices/anyone-can-register-notice.php'; |
| 187 | require_once __DIR__ . '/notices/feature-moved-to-jetpack-notices.php'; |
| 188 | |
| 189 | // Performance Profiler |
| 190 | require_once __DIR__ . '/performance-profiler/performance-profiler.php'; |
| 191 | |
| 192 | if ( defined( 'WP_CLI' ) && WP_CLI ) { |
| 193 | require_once __DIR__ . '/class-wpcomsh-cli-commands.php'; |
| 194 | require_once __DIR__ . '/woa.php'; |
| 195 | } |
| 196 | |
| 197 | require_once __DIR__ . '/wpcom-migration-helpers/site-migration-helpers.php'; |
| 198 | |
| 199 | // We include WPCom Themes results and installation on non-WP_CLI context. |
| 200 | if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) { |
| 201 | require_once __DIR__ . '/wpcom-themes/themes.php'; |
| 202 | } |
| 203 | |
| 204 | require_once __DIR__ . '/class-jetpack-plugin-compatibility.php'; |
| 205 | Jetpack_Plugin_Compatibility::get_instance(); |
| 206 | |
| 207 | require_once __DIR__ . '/support-session.php'; |
| 208 | |
| 209 | // Adds fallback behavior for non-Gutenframed sites to be able to use the 'Share Post' functionality from WPCOM Reader. |
| 210 | require_once __DIR__ . '/share-post/share-post.php'; |
| 211 | |
| 212 | // Jetpack Connection Handlers (external storage and protected owner). |
| 213 | require_once __DIR__ . '/connection/connection-handlers.php'; |
| 214 | |
| 215 | // Require a Jetpack Connection Owner. |
| 216 | require_once __DIR__ . '/jetpack-require-connection-owner/class-wpcomsh-require-connection-owner.php'; |
| 217 | |
| 218 | // Enable MailPoet subscriber stats reports |
| 219 | require_once __DIR__ . '/mailpoet/class-wpcomsh-mailpoet-subscribers-stats-report.php'; |
| 220 | |
| 221 | // Force Jetpack to update plugins one-at-a-time to avoid a site-breaking core concurrent update bug |
| 222 | // https://core.trac.wordpress.org/ticket/53705 |
| 223 | if ( |
| 224 | ! defined( 'JETPACK_PLUGIN_AUTOUPDATE' ) && |
| 225 | 0 === strncmp( $_SERVER['REQUEST_URI'], '/xmlrpc.php?', strlen( '/xmlrpc.php?' ) ) ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput |
| 226 | define( 'JETPACK_PLUGIN_AUTOUPDATE', true ); |
| 227 | } |
| 228 | |
| 229 | /** |
| 230 | * Filter attachment URLs if the 'wpcom_attachment_subdomain' option is present. |
| 231 | * Local image files will be unaffected, as they will pass a file_exists check. |
| 232 | * Files stored remotely will be filtered to have the correct URL. |
| 233 | * |
| 234 | * Once the files have been transferred, the 'wpcom_attachment_subdomain' will |
| 235 | * be removed, preventing further stats. |
| 236 | * |
| 237 | * @param string $url The attachment URL. |
| 238 | * @param int $post_id The post id. |
| 239 | * @return string The filtered attachment URL. |
| 240 | */ |
| 241 | function wpcomsh_get_attachment_url( $url, $post_id ) { |
| 242 | $attachment_subdomain = get_option( 'wpcom_attachment_subdomain' ); |
| 243 | if ( $attachment_subdomain ) { |
| 244 | $file = get_post_meta( $post_id, '_wp_attached_file', true ); |
| 245 | |
| 246 | if ( $file ) { |
| 247 | $local_file = WP_CONTENT_DIR . '/uploads/' . $file; |
| 248 | if ( ! file_exists( $local_file ) ) { |
| 249 | return esc_url( 'https://' . $attachment_subdomain . '/' . $file ); |
| 250 | } |
| 251 | } |
| 252 | } |
| 253 | return $url; |
| 254 | } |
| 255 | add_filter( 'wp_get_attachment_url', 'wpcomsh_get_attachment_url', 11, 2 ); |
| 256 | |
| 257 | /** |
| 258 | * When WordPress.com passes along an expiration for auth cookies and it is smaller |
| 259 | * than the value set by Jetpack by default (YEAR_IN_SECONDS), use the smaller value. |
| 260 | * |
| 261 | * @param int $seconds The cookie expiration in seconds. |
| 262 | * @return int The filtered cookie expiration in seconds |
| 263 | */ |
| 264 | function wpcomsh_jetpack_sso_auth_cookie_expiration( $seconds ) { |
| 265 | if ( isset( $_GET['expires'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 266 | $expires = absint( $_GET['expires'] ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended |
| 267 | |
| 268 | if ( ! empty( $expires ) && $expires < $seconds ) { |
| 269 | $seconds = $expires; |
| 270 | } |
| 271 | } |
| 272 | return intval( $seconds ); |
| 273 | } |
| 274 | add_filter( 'jetpack_sso_auth_cookie_expiration', 'wpcomsh_jetpack_sso_auth_cookie_expiration' ); |
| 275 | |
| 276 | /** |
| 277 | * Determine if users should be enforced to log in with their WP.com account. |
| 278 | * |
| 279 | * Sites without local users: |
| 280 | * - WP.com login, always. |
| 281 | * |
| 282 | * Sites with local users: |
| 283 | * - If user comes from Calypso: WP.com login |
| 284 | * - Otherwise: Jetpack SSO login, so they can decide whether to use a WP.com account or a local account. |
| 285 | */ |
| 286 | function wpcomsh_bypass_jetpack_sso_login() { |
| 287 | $calypso_domains = array( |
| 288 | 'https://wordpress.com/', |
| 289 | 'https://horizon.wordpress.com/', |
| 290 | 'https://wpcalypso.wordpress.com/', |
| 291 | 'http://calypso.localhost:3000/', |
| 292 | 'http://127.0.0.1:41050/', // Desktop App. |
| 293 | ); |
| 294 | if ( in_array( wp_get_referer(), $calypso_domains, true ) ) { |
| 295 | return true; |
| 296 | } |
| 297 | |
| 298 | if ( class_exists( '\Automattic\Jetpack\Connection\Manager' ) ) { |
| 299 | $connection_manager = new \Automattic\Jetpack\Connection\Manager( 'jetpack' ); |
| 300 | |
| 301 | // Fetching an extra field to overcome the caching bug: https://core.trac.wordpress.org/ticket/62003 |
| 302 | $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) ); |
| 303 | foreach ( $users as $user ) { |
| 304 | if ( ! $connection_manager->is_user_connected( $user->ID ) ) { |
| 305 | return false; |
| 306 | } |
| 307 | } |
| 308 | } |
| 309 | |
| 310 | return true; |
| 311 | } |
| 312 | add_filter( 'jetpack_sso_bypass_login_forward_wpcom', 'wpcomsh_bypass_jetpack_sso_login' ); |
| 313 | |
| 314 | /** |
| 315 | * Add 'loggedout' to the list of actions that allow the wpcom login form to be used. |
| 316 | * |
| 317 | * This means that the login screen the user sees immediately after logging out is consistent |
| 318 | * with the login screen the user sees when they are not logged in: the wpcom login form. |
| 319 | * |
| 320 | * @param array $allowed_actions The allowed actions. |
| 321 | * @return array The modified allowed actions. |
| 322 | */ |
| 323 | function wpcomsh_modify_jetpack_sso_allowed_actions( $allowed_actions ) { |
| 324 | $allowed_actions[] = 'loggedout'; |
| 325 | return $allowed_actions; |
| 326 | } |
| 327 | add_filter( 'jetpack_sso_allowed_actions', 'wpcomsh_modify_jetpack_sso_allowed_actions' ); |
| 328 | |
| 329 | /** |
| 330 | * Overwrite the default value of SSO "Match by Email" setting. |
| 331 | * p9o2xV-2zY-p2 |
| 332 | */ |
| 333 | add_filter( 'default_option_jetpack_sso_match_by_email', '__return_true' ); |
| 334 | |
| 335 | /** |
| 336 | * Admin enqueue style |
| 337 | */ |
| 338 | function wpcomsh_admin_enqueue_style() { |
| 339 | wp_enqueue_style( |
| 340 | 'wpcomsh-admin-style', |
| 341 | plugins_url( 'assets/admin-style.css', __FILE__ ), |
| 342 | array(), |
| 343 | WPCOMSH_VERSION |
| 344 | ); |
| 345 | } |
| 346 | add_action( 'admin_enqueue_scripts', 'wpcomsh_admin_enqueue_style', 999 ); |
| 347 | |
| 348 | /** |
| 349 | * Allow custom wp options |
| 350 | * |
| 351 | * @param array $options The options. |
| 352 | * |
| 353 | * @return array |
| 354 | */ |
| 355 | function wpcomsh_allow_custom_wp_options( $options ) { |
| 356 | // For storing AT options. |
| 357 | $options[] = 'at_options'; |
| 358 | $options[] = 'at_options_logging_on'; |
| 359 | $options[] = 'at_wpcom_premium_theme'; |
| 360 | $options[] = 'jetpack_fonts'; |
| 361 | $options[] = 'site_logo'; |
| 362 | $options[] = 'footercredit'; |
| 363 | $options[] = 'wpcomsh_at_managed_plugins'; |
| 364 | |
| 365 | return $options; |
| 366 | } |
| 367 | add_filter( 'jetpack_options_whitelist', 'wpcomsh_allow_custom_wp_options' ); |
| 368 | |
| 369 | add_filter( 'jetpack_site_automated_transfer', '__return_true' ); |
| 370 | |
| 371 | /** |
| 372 | * Check site has pending automated transfer |
| 373 | * |
| 374 | * @return bool |
| 375 | */ |
| 376 | function check_site_has_pending_automated_transfer() { |
| 377 | return get_option( 'has_pending_automated_transfer' ); |
| 378 | } |
| 379 | |
| 380 | add_filter( 'jetpack_site_pending_automated_transfer', 'check_site_has_pending_automated_transfer' ); |
| 381 | |
| 382 | /** |
| 383 | * We have some instances where `track_number` of an audio attachment is `??0` and shows up as type string. |
| 384 | * However the problem is, that if post has nested property attachments with this track_number, `json_serialize` fails silently. |
| 385 | * Of course, this should be fixed during audio upload, but we need this fix until we can clean this up properly. |
| 386 | * More detail here: https://github.com/Automattic/automated-transfer/issues/235 |
| 387 | * |
| 388 | * @param array $exif_data The file exif data. |
| 389 | * |
| 390 | * @return array |
| 391 | */ |
| 392 | function wpcomsh_jetpack_api_fix_unserializable_track_number( $exif_data ) { |
| 393 | if ( isset( $exif_data['track_number'] ) ) { |
| 394 | $exif_data['track_number'] = intval( $exif_data['track_number'] ); |
| 395 | } |
| 396 | return $exif_data; |
| 397 | } |
| 398 | add_filter( 'wp_get_attachment_metadata', 'wpcomsh_jetpack_api_fix_unserializable_track_number' ); |
| 399 | |
| 400 | // Jetpack for Atomic sites are always production version. |
| 401 | add_filter( 'jetpack_development_version', '__return_false' ); |
| 402 | |
| 403 | /** |
| 404 | * Make User Agent consistent with the rest of WordPress.com. |
| 405 | * |
| 406 | * @param mixed $agent The agent. |
| 407 | */ |
| 408 | function wpcomsh_filter_outgoing_user_agent( $agent ) { |
| 409 | global $wp_version; |
| 410 | |
| 411 | return str_replace( "WordPress/$wp_version", 'WordPress.com', $agent ); |
| 412 | } |
| 413 | add_filter( 'http_headers_useragent', 'wpcomsh_filter_outgoing_user_agent', 999 ); |
| 414 | |
| 415 | /** |
| 416 | * Allow redirects to WordPress.com from Customizer. |
| 417 | * |
| 418 | * @param array $hosts The hosts. |
| 419 | */ |
| 420 | function wpcomsh_allowed_redirect_hosts( $hosts ) { |
| 421 | if ( is_array( $hosts ) ) { |
| 422 | $hosts[] = 'wordpress.com'; |
| 423 | $hosts[] = 'calypso.localhost'; |
| 424 | $hosts = array_unique( $hosts ); |
| 425 | } |
| 426 | return $hosts; |
| 427 | } |
| 428 | add_filter( 'allowed_redirect_hosts', 'wpcomsh_allowed_redirect_hosts', 11 ); |
| 429 | |
| 430 | /** |
| 431 | * WP.com make clickable |
| 432 | * |
| 433 | * Converts all plain-text HTTP URLs in post_content to links on display. |
| 434 | * Uses WP_HTML_Tag_Processor for proper HTML tokenization that won't be confused by |
| 435 | * content inside tags (e.g., JavaScript comparison operators in script tags). |
| 436 | * |
| 437 | * @param string $content The content. |
| 438 | * @return string Modified content with linkified URLs. |
| 439 | * @uses make_clickable() |
| 440 | * @since 20121125 |
| 441 | */ |
| 442 | function wpcomsh_make_content_clickable( $content ) { |
| 443 | // Fast path: no URL-shaped substring, no work to do. Avoids loading the |
| 444 | // linkifier and walking the tokenizer for the common case. |
| 445 | if ( false === stripos( $content, 'http' ) && false === stripos( $content, 'www.' ) ) { |
| 446 | return $content; |
| 447 | } |
| 448 | |
| 449 | if ( ! method_exists( 'WP_HTML_Tag_Processor', 'next_token' ) ) { |
| 450 | if ( function_exists( 'bump_stats_extras' ) ) { |
| 451 | bump_stats_extras( 'wpcomsh-make-content-clickable', 'skipped-no-html-api' ); |
| 452 | } |
| 453 | return $content; |
| 454 | } |
| 455 | |
| 456 | require_once __DIR__ . '/class-wpcomsh-html-linkifier.php'; |
| 457 | |
| 458 | return Wpcomsh_HTML_Linkifier::modify_raw_text_nodes( |
| 459 | $content, |
| 460 | static function ( $raw_text ) { |
| 461 | return 1 === preg_match( '~https?://|www\.~', $raw_text ) |
| 462 | ? make_clickable( $raw_text ) |
| 463 | : $raw_text; |
| 464 | } |
| 465 | ); |
| 466 | } |
| 467 | add_filter( 'the_content', 'wpcomsh_make_content_clickable', 120 ); |
| 468 | add_filter( 'the_excerpt', 'wpcomsh_make_content_clickable', 120 ); |
| 469 | |
| 470 | /** |
| 471 | * Hide scan threats from transients |
| 472 | * |
| 473 | * @param mixed $response The response. |
| 474 | * |
| 475 | * @return mixed |
| 476 | */ |
| 477 | function wpcomsh_hide_scan_threats_from_transients( $response ) { |
| 478 | if ( ! empty( $response->threats ) ) { |
| 479 | $response->threats = array(); |
| 480 | } |
| 481 | return $response; |
| 482 | } |
| 483 | add_filter( 'transient_jetpack_scan_state', 'wpcomsh_hide_scan_threats_from_transients' ); |
| 484 | |
| 485 | /** |
| 486 | * Unhook Jetpack Scan Admin Notice |
| 487 | * |
| 488 | * @return void |
| 489 | */ |
| 490 | function wpcomsh_remove_threats_from_toolbar() { |
| 491 | global $wp_admin_bar; |
| 492 | $wp_admin_bar->remove_node( 'jetpack-scan-notice' ); |
| 493 | } |
| 494 | add_action( 'wp_before_admin_bar_render', 'wpcomsh_remove_threats_from_toolbar', 999999 ); |
| 495 | |
| 496 | /** |
| 497 | * Hide scan threats from api |
| 498 | * |
| 499 | * @param mixed $response The reponse. |
| 500 | * |
| 501 | * @return mixed |
| 502 | */ |
| 503 | function wpcom_hide_scan_threats_from_api( $response ) { |
| 504 | if ( |
| 505 | ! ( $response instanceof WP_REST_Response ) |
| 506 | || $response->get_matched_route() !== '/jetpack/v4/scan' |
| 507 | ) { |
| 508 | return $response; |
| 509 | } |
| 510 | $response_data = $response->get_data(); |
| 511 | if ( empty( $response_data['data'] ) || ! is_string( $response_data['data'] ) ) { |
| 512 | return $response; |
| 513 | } |
| 514 | |
| 515 | $json_body = json_decode( $response_data['data'], true ); |
| 516 | if ( null === $json_body || empty( $json_body['threats'] ) ) { |
| 517 | return $response; |
| 518 | } |
| 519 | |
| 520 | $json_body['threats'] = array(); |
| 521 | $response_data['data'] = wp_json_encode( $json_body, JSON_UNESCAPED_SLASHES ); |
| 522 | $response->set_data( $response_data ); |
| 523 | |
| 524 | return $response; |
| 525 | } |
| 526 | add_filter( 'rest_post_dispatch', 'wpcom_hide_scan_threats_from_api' ); |
| 527 | |
| 528 | /** |
| 529 | * Returns a standardized timezone string. |
| 530 | * |
| 531 | * `wp_timezone_string()` sometimes returns offsets (e.g. "-07:00"), which are |
| 532 | * a non-standard representation of a UTC offset that only works in PHP. |
| 533 | * This function returns a standardized timezone string instead, of the form |
| 534 | * "Etc/GMT+7" for integer hour offsets, or a matching "<Area>/<City>" form for |
| 535 | * fractional hour offsets (used e.g. in India). |
| 536 | */ |
| 537 | function wpcomsh_stats_timezone_string() { |
| 538 | $wp_tz = wp_timezone_string(); |
| 539 | |
| 540 | // Did we get back an offset? |
| 541 | if ( preg_match( '/^([+-])?(\d{1,2}):(\d{2})$/', $wp_tz, $matches ) ) { |
| 542 | $sign = $matches[1] === '-' ? -1 : 1; |
| 543 | $hours = intval( $matches[2], 10 ); |
| 544 | $minutes = intval( $matches[3], 10 ); |
| 545 | |
| 546 | // For fractional hour offsets, use `timezone_name_from_abbr` to get a |
| 547 | // matching "<Area>/<City>" timezone. |
| 548 | if ( $minutes > 0 ) { |
| 549 | $offset = $sign * ( $hours * 3600 + $minutes * 60 ); |
| 550 | $city_tz = timezone_name_from_abbr( '', $offset, 0 ); |
| 551 | |
| 552 | if ( ! empty( $city_tz ) ) { |
| 553 | return $city_tz; |
| 554 | } |
| 555 | } |
| 556 | |
| 557 | // For integer hour offsets, use "Etc/GMT(+|-)<offset>". |
| 558 | // The sign is flipped, to match how the `Etc` area is specced. |
| 559 | // |
| 560 | // This codepath is also followed if no city exists to match a |
| 561 | // fractional offset, by simply discarding the fractional part. |
| 562 | // This isn't ideal, but there's no standard way of describing |
| 563 | // these offsets, and is likely to be an extreme edge case. |
| 564 | return 'Etc/GMT' . ( $sign === -1 ? '+' : '-' ) . $hours; |
| 565 | } |
| 566 | |
| 567 | // For anything that's not an offset, return the string we got from WP. |
| 568 | return $wp_tz; |
| 569 | } |
| 570 | |
| 571 | /** |
| 572 | * Collect RUM performance data |
| 573 | * p9o2xV-XY-p2 |
| 574 | */ |
| 575 | function wpcomsh_footer_rum_js() { |
| 576 | $service = 'atomic'; |
| 577 | $allow_iframe = ''; |
| 578 | if ( 'admin_footer' === current_action() ) { |
| 579 | $service = 'atomic-wpadmin'; |
| 580 | |
| 581 | $block_editor = \Automattic\Jetpack\Jetpack_Mu_Wpcom\WPCOM_Block_Editor\Jetpack_WPCOM_Block_Editor::init(); |
| 582 | if ( $block_editor->is_iframed_block_editor() ) { |
| 583 | $service = 'atomic-gutenframe'; |
| 584 | $allow_iframe = 'data-allow-iframe="true"'; |
| 585 | } |
| 586 | } |
| 587 | |
| 588 | $rum_kv = array(); |
| 589 | $rum_kv = apply_filters( 'wpcomsh_rum_kv', $rum_kv, $service ); |
| 590 | if ( ! is_array( $rum_kv ) ) { |
| 591 | $rum_kv = array(); |
| 592 | } |
| 593 | |
| 594 | $rum_kv = wpcomsh_get_woo_rum_data( $rum_kv ); |
| 595 | // Add user login and theme info. |
| 596 | $rum_kv['logged_in'] = is_user_logged_in() ? '1' : '0'; |
| 597 | $rum_kv['wptheme'] = get_stylesheet(); |
| 598 | $rum_kv['wptheme_is_block'] = wp_is_block_theme() ? '1' : '0'; |
| 599 | |
| 600 | if ( count( $rum_kv ) > 0 ) { |
| 601 | $rum_kv = wp_json_encode( $rum_kv, JSON_FORCE_OBJECT | JSON_UNESCAPED_SLASHES | JSON_HEX_AMP ); |
| 602 | if ( is_string( $rum_kv ) ) { |
| 603 | $rum_kv = 'data-customproperties="' . esc_attr( $rum_kv ) . '"'; |
| 604 | } else { |
| 605 | $rum_kv = ''; |
| 606 | } |
| 607 | } else { |
| 608 | $rum_kv = ''; |
| 609 | } |
| 610 | |
| 611 | $data_site_tz = 'data-site-tz="' . esc_attr( wpcomsh_stats_timezone_string() ) . '"'; |
| 612 | |
| 613 | printf( |
| 614 | '<meta id="bilmur" property="bilmur:data" content="" %1$s data-provider="wordpress.com" data-service="%2$s" %3$s %4$s >' . "\n", |
| 615 | $rum_kv, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 616 | esc_attr( $service ), |
| 617 | wp_kses_post( $allow_iframe ), |
| 618 | $data_site_tz // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 619 | ); |
| 620 | printf( |
| 621 | '<script defer src="%s"></script>' . "\n", //phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript |
| 622 | esc_url( 'https://s0.wp.com/wp-content/js/bilmur.min.js?m=' . gmdate( 'YW' ) ) |
| 623 | ); |
| 624 | } |
| 625 | |
| 626 | /** |
| 627 | * Adds WooCommerce-related data to the Real User Monitoring (RUM) array. |
| 628 | * |
| 629 | * This function checks if WooCommerce is active on the site and adds |
| 630 | * this information to the provided RUM data array. It's designed to be |
| 631 | * used as part of the RUM data collection process for Atomic sites. |
| 632 | * |
| 633 | * @param array $rum_kv An array of existing RUM key-value pairs. |
| 634 | * If not provided, an empty array will be used. |
| 635 | * |
| 636 | * @return array The input array with added WooCommerce data. |
| 637 | * The 'woo_active' key will be added with a boolean value |
| 638 | * indicating whether WooCommerce is active. |
| 639 | */ |
| 640 | function wpcomsh_get_woo_rum_data( $rum_kv = array() ) { |
| 641 | $woo_active = class_exists( 'WooCommerce' ) ? '1' : '0'; |
| 642 | $rum_kv['woo_active'] = $woo_active; |
| 643 | return $rum_kv; |
| 644 | } |
| 645 | |
| 646 | add_action( 'wp_footer', 'wpcomsh_footer_rum_js' ); |
| 647 | add_action( 'admin_footer', 'wpcomsh_footer_rum_js' ); |
| 648 | |
| 649 | /** |
| 650 | * Adds Atomic site ID to WooCommerce tracker data. |
| 651 | * |
| 652 | * @param array $data The WooCommerce tracker data. |
| 653 | * |
| 654 | * @return array The WooCommerce tracker data with Atomic site ID added. |
| 655 | */ |
| 656 | function wpcomsh_woocommerce_tracker_data( $data ) { |
| 657 | $data['atomic_site_id'] = wpcomsh_get_atomic_site_id(); |
| 658 | return $data; |
| 659 | } |
| 660 | |
| 661 | add_filter( 'woocommerce_tracker_data', 'wpcomsh_woocommerce_tracker_data' ); |
| 662 | |
| 663 | add_filter( 'amp_dev_tools_user_default_enabled', '__return_false' ); |
| 664 | |
| 665 | /** |
| 666 | * Tracks helper. Filters Jetpack TOS option if class exists. |
| 667 | * |
| 668 | * @param mixed $event The event. |
| 669 | * @param mixed $event_properties The event property. |
| 670 | * |
| 671 | * @return void |
| 672 | */ |
| 673 | function wpcomsh_record_tracks_event( $event, $event_properties ) { |
| 674 | if ( class_exists( '\Automattic\Jetpack\Tracking' ) ) { |
| 675 | // User has to agree to ToS for tracking. Thing is, on initial Simple -> Atomic we never set the ToS option. |
| 676 | // And since they agreed to WP.com ToS, we can track but in a roundabout way. :). |
| 677 | add_filter( 'jetpack_options', 'wpcomsh_jetpack_filter_tos_for_tracking', 10, 2 ); |
| 678 | |
| 679 | $jetpack_tracks = new \Automattic\Jetpack\Tracking( 'atomic' ); |
| 680 | $jetpack_tracks->tracks_record_event( |
| 681 | wp_get_current_user(), |
| 682 | $event, |
| 683 | $event_properties |
| 684 | ); |
| 685 | |
| 686 | remove_filter( 'jetpack_options', 'wpcomsh_jetpack_filter_tos_for_tracking', 10 ); |
| 687 | } |
| 688 | } |
| 689 | |
| 690 | /** |
| 691 | * Helper for filtering tos_agreed for tracking purposes. |
| 692 | * Explicit function so it can be removed afterwards. |
| 693 | * |
| 694 | * @param mixed $value The value. |
| 695 | * @param mixed $name Name. |
| 696 | * |
| 697 | * @return mixed |
| 698 | */ |
| 699 | function wpcomsh_jetpack_filter_tos_for_tracking( $value, $name ) { |
| 700 | if ( 'tos_agreed' === $name ) { |
| 701 | return true; |
| 702 | } |
| 703 | |
| 704 | return $value; |
| 705 | } |
| 706 | |
| 707 | /** |
| 708 | * Avoid proxied v2 banner |
| 709 | * |
| 710 | * @return void |
| 711 | */ |
| 712 | function wpcomsh_avoid_proxied_v2_banner() { |
| 713 | $priority = has_action( 'wp_footer', 'atomic_proxy_bar' ); |
| 714 | if ( false !== $priority ) { |
| 715 | remove_action( 'wp_footer', 'atomic_proxy_bar', $priority ); |
| 716 | } |
| 717 | |
| 718 | $priority = has_action( 'admin_footer', 'atomic_proxy_bar' ); |
| 719 | if ( false !== $priority ) { |
| 720 | remove_action( 'admin_footer', 'atomic_proxy_bar', $priority ); |
| 721 | } |
| 722 | } |
| 723 | |
| 724 | // We don't want to show a "PROXIED V2" banner for legacy widget previews |
| 725 | // which are normally embedded within another page. |
| 726 | if ( |
| 727 | defined( 'AT_PROXIED_REQUEST' ) && AT_PROXIED_REQUEST && |
| 728 | isset( $_GET['legacy-widget-preview'] ) && //phpcs:ignore WordPress.Security.NonceVerification |
| 729 | 0 === strncmp( $_SERVER['REQUEST_URI'], '/wp-admin/widgets.php?', strlen( '/wp-admin/widgets.php?' ) ) ) { //phpcs:ignore WordPress.Security.ValidatedSanitizedInput |
| 730 | add_action( 'plugins_loaded', 'wpcomsh_avoid_proxied_v2_banner' ); |
| 731 | } |