This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,18 @@
<?php
/**
* Legacy base class for Jetpack's debugging tests.
*
* @deprecated Use Connection_Health_Test_Base or Connection_Health_Tests from the connection package directly.
* @package automattic/jetpack
*/
use Automattic\Jetpack\Connection\Connection_Health_Test_Base;
/**
* "Unit Tests" for the Jetpack connection.
*
* @since 7.1.0
* @deprecated Use Connection_Health_Test_Base or Connection_Health_Tests from the connection package directly.
*/
class Jetpack_Cxn_Test_Base extends Connection_Health_Test_Base {
}
@@ -0,0 +1,94 @@
<?php
/**
* Jetpack-specific connection tests.
*
* Extends the connection package's Connection_Health_Test_Base with Jetpack-specific
* tests (sync health) and Jetpack-specific helper overrides.
*
* @package automattic/jetpack
*/
use Automattic\Jetpack\Connection\Connection_Health_Test_Base;
use Automattic\Jetpack\Redirect;
use Automattic\Jetpack\Sync\Health as Sync_Health;
use Automattic\Jetpack\Sync\Settings as Sync_Settings;
if ( ! defined( 'ABSPATH' ) ) {
exit( 0 );
}
/**
* Class Jetpack_Cxn_Tests contains the Jetpack-specific connection tests.
*
* Extends the connection package's framework and provides Jetpack-specific
* tests (sync health), encryption, and Jetpack-specific helper overrides.
*
* Jetpack-specific tests are also registered with the connection package's
* Site Health integration via the jetpack_connection_tests_loaded action.
*/
class Jetpack_Cxn_Tests extends Connection_Health_Test_Base {
/**
* Register Jetpack-specific tests on an external test suite instance.
*
* Used to add Jetpack tests to the connection package's Site Health integration
* via the jetpack_connection_tests_loaded action.
*
* @param Connection_Health_Test_Base $target The test suite to register tests on.
*/
public function register_tests_on( $target ) {
$methods = get_class_methods( static::class );
foreach ( $methods as $method ) {
if ( ! str_contains( $method, 'test__' ) ) {
continue;
}
$target->add_test( array( $this, $method ), $method, 'direct' );
}
}
/**
* Sync Health Tests.
*
* @return array Test results.
*/
protected function test__sync_health() {
$name = 'test__sync_health';
if ( ! $this->helper_is_connected() ) {
return self::skipped_test(
array(
'name' => $name,
'show_in_site_health' => false,
)
);
}
if ( ! Sync_Settings::is_sync_enabled() ) {
return self::failing_test(
array(
'name' => $name,
'label' => __( 'Jetpack Sync has been disabled on your site.', 'jetpack' ),
'severity' => 'recommended',
'action' => 'https://github.com/Automattic/jetpack/blob/trunk/projects/packages/sync/src/class-settings.php',
'action_label' => __( 'See GitHub for more on Sync Settings', 'jetpack' ),
'short_description' => __( 'Jetpack Sync has been disabled on your site. This could be impacting some of your site\'s Jetpack-powered features. Developers may enable / disable syncing using the Sync Settings API.', 'jetpack' ),
)
);
}
if ( Sync_Health::get_status() === Sync_Health::STATUS_OUT_OF_SYNC ) {
return self::failing_test(
array(
'name' => $name,
'label' => __( 'Jetpack has detected a problem with the communication between your site and WordPress.com', 'jetpack' ),
'severity' => 'critical',
'action' => Redirect::get_url( 'jetpack-contact-support' ),
'action_label' => __( 'Contact Jetpack Support', 'jetpack' ),
'short_description' => __( 'There is a problem with the communication between your site and WordPress.com. This could be impacting some of your site\'s Jetpack-powered features. If you continue to see this error, please contact support for assistance.', 'jetpack' ),
)
);
}
return self::passing_test( array( 'name' => $name ) );
}
}
@@ -0,0 +1,413 @@
<?php
/**
* Jetpack Debug Data for the Site Health sections.
*
* @package automattic/jetpack
*/
use Automattic\Jetpack\Connection\Tokens;
use Automattic\Jetpack\Connection\Urls;
use Automattic\Jetpack\Constants;
use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
use Automattic\Jetpack\Identity_Crisis;
use Automattic\Jetpack\Redirect;
use Automattic\Jetpack\Status;
use Automattic\Jetpack\Sync\Modules;
use Automattic\Jetpack\Sync\Sender;
/**
* Class Jetpack_Debug_Data
*
* Collect and return debug data for Jetpack.
*
* @since 7.3.0
*/
class Jetpack_Debug_Data {
/**
* Determine the active plan and normalize it for the debugger results.
*
* @since 7.3.0
*
* @return string The plan slug.
*/
public static function what_jetpack_plan() {
$plan = Jetpack_Plan::get();
return ! empty( $plan['class'] ) ? $plan['class'] : 'undefined';
}
/**
* Convert seconds to human readable time.
*
* A dedication function instead of using Core functionality to allow for output in seconds.
*
* @since 7.3.0
*
* @param int $seconds Number of seconds to convert to human time.
*
* @return string Human readable time.
*/
public static function seconds_to_time( $seconds ) {
$seconds = (int) $seconds;
$units = array(
'week' => WEEK_IN_SECONDS,
'day' => DAY_IN_SECONDS,
'hour' => HOUR_IN_SECONDS,
'minute' => MINUTE_IN_SECONDS,
'second' => 1,
);
// specifically handle zero.
if ( 0 === $seconds ) {
return '0 seconds';
}
$human_readable = '';
foreach ( $units as $name => $divisor ) {
$quot = (int) ( $seconds / $divisor );
if ( $quot ) {
$human_readable .= "$quot $name";
$human_readable .= ( abs( $quot ) > 1 ? 's' : '' ) . ', ';
$seconds -= $quot * $divisor;
}
}
return substr( $human_readable, 0, -2 );
}
/**
* Return debug data in the format expected by Core's Site Health Info tab.
*
* @since 7.3.0
*
* @param array $debug {
* The debug information already compiled by Core.
*
* @type string $label The title for this section of the debug output.
* @type string $description Optional. A description for your information section which may contain basic HTML
* markup: `em`, `strong` and `a` for linking to documentation or putting emphasis.
* @type boolean $show_count Optional. If set to `true` the amount of fields will be included in the title for
* this section.
* @type boolean $private Optional. If set to `true` the section and all associated fields will be excluded
* from the copy-paste text area.
* @type array $fields {
* An associative array containing the data to be displayed.
*
* @type string $label The label for this piece of information.
* @type string $value The output that is of interest for this field.
* @type boolean $private Optional. If set to `true` the field will not be included in the copy-paste text area
* on top of the page, allowing you to show, for example, API keys here.
* }
* }
*
* @return array $args Debug information in the same format as the initial argument.
*/
public static function core_debug_data( $debug ) {
$support_url = Jetpack::is_development_version()
? Redirect::get_url( 'jetpack-contact-support-beta-group' )
: Redirect::get_url( 'jetpack-contact-support' );
$jetpack = array(
'jetpack' => array(
'label' => __( 'Jetpack', 'jetpack' ),
'description' => sprintf(
/* translators: %1$s is URL to jetpack.com's contact support page. %2$s accessibility text */
__(
'Diagnostic information helpful to <a href="%1$s" target="_blank" rel="noopener noreferrer">your Jetpack Happiness team<span class="screen-reader-text">%2$s</span></a>',
'jetpack'
),
esc_url( $support_url ),
__( '(opens in a new tab)', 'jetpack' )
),
'fields' => self::debug_data(),
),
);
$debug = array_merge( $debug, $jetpack );
return $debug;
}
/**
* Compile and return array of debug information.
*
* @since 7.3.0
*
* @return array $args {
* Associated array of arrays with the following.
* @type string $label The label for this piece of information.
* @type string $value The output that is of interest for this field.
* @type boolean $private Optional. Set to true if data is sensitive (API keys, etc).
* }
*/
public static function debug_data() {
$debug_info = array();
/* Add various important Jetpack options */
$debug_info['site_id'] = array(
'label' => 'Jetpack Site ID',
'value' => Jetpack_Options::get_option( 'id' ),
'private' => false,
);
$debug_info['ssl_cert'] = array(
'label' => 'Jetpack SSL Verfication Bypass',
'value' => ( Jetpack_Options::get_option( 'fallback_no_verify_ssl_certs' ) ) ? 'Yes' : 'No',
'private' => false,
);
$debug_info['time_diff'] = array(
'label' => "Offset between Jetpack server's time and this server's time.",
'value' => Jetpack_Options::get_option( 'time_diff' ),
'private' => false,
);
$debug_info['version_option'] = array(
'label' => 'Current Jetpack Version Option',
'value' => Jetpack_Options::get_option( 'version' ),
'private' => false,
);
$debug_info['old_version'] = array(
'label' => 'Previous Jetpack Version',
'value' => Jetpack_Options::get_option( 'old_version' ),
'private' => false,
);
$debug_info['public'] = array(
'label' => 'Jetpack Site Public',
'value' => ( Jetpack_Options::get_option( 'public' ) ) ? 'Public' : 'Private',
'private' => false,
);
$debug_info['master_user'] = array(
'label' => 'Jetpack Master User',
'value' => self::human_readable_master_user(), // Only ID number and user name.
'private' => false,
);
$debug_info['is_offline_mode'] = array(
'label' => 'Jetpack Offline Mode',
'value' => ( new Status() )->is_offline_mode() ? 'on' : 'off',
'private' => false,
);
$debug_info['is_offline_mode_constant'] = array(
'label' => 'JETPACK_DEV_DEBUG Constant',
'value' => ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) ? 'on' : 'off',
'private' => false,
);
/**
* Token information is private, but awareness if there one is set is helpful.
*
* To balance out information vs privacy, we only display and include the "key",
* which is a segment of the token prior to a period within the token and is
* technically not private.
*
* If a token does not contain a period, then it is malformed and we report it as such.
*/
$user_id = get_current_user_id();
$blog_token = ( new Tokens() )->get_access_token();
$user_token = ( new Tokens() )->get_access_token( $user_id );
$tokenset = '';
if ( $blog_token ) {
$tokenset = 'Blog ';
$blog_key = substr( $blog_token->secret, 0, strpos( $blog_token->secret, '.' ) );
// Intentionally not translated since this is helpful when sent to Happiness.
$blog_key = ( $blog_key ) ? $blog_key : 'Potentially Malformed Token.';
}
if ( $user_token ) {
$tokenset .= 'User';
$user_key = substr( $user_token->secret, 0, strpos( $user_token->secret, '.' ) );
// Intentionally not translated since this is helpful when sent to Happiness.
$user_key = ( $user_key ) ? $user_key : 'Potentially Malformed Token.';
}
if ( ! $tokenset ) {
$tokenset = 'None';
}
$debug_info['current_user'] = array(
'label' => 'Current User',
'value' => self::human_readable_user( $user_id ),
'private' => false,
);
$debug_info['tokens_set'] = array(
'label' => 'Tokens defined',
'value' => $tokenset,
'private' => false,
);
$debug_info['blog_token'] = array(
'label' => 'Blog Public Key',
'value' => $blog_key ?? 'Not set.',
'private' => false,
);
$debug_info['user_token'] = array(
'label' => 'User Public Key',
'value' => $user_key ?? 'Not set.',
'private' => false,
);
/** Jetpack Environmental Information */
$debug_info['version'] = array(
'label' => 'Jetpack Version',
'value' => JETPACK__VERSION,
'private' => false,
);
$debug_info['jp_plugin_dir'] = array(
'label' => 'Jetpack Directory',
'value' => JETPACK__PLUGIN_DIR,
'private' => false,
);
$debug_info['plan'] = array(
'label' => 'Plan Type',
'value' => self::what_jetpack_plan(),
'private' => false,
);
foreach ( array(
'HTTP_HOST',
'SERVER_PORT',
'HTTPS',
'GD_PHP_HANDLER',
'HTTP_AKAMAI_ORIGIN_HOP',
'HTTP_CF_CONNECTING_IP',
'HTTP_CLIENT_IP',
'HTTP_FASTLY_CLIENT_IP',
'HTTP_FORWARDED',
'HTTP_FORWARDED_FOR',
'HTTP_INCAP_CLIENT_IP',
'HTTP_TRUE_CLIENT_IP',
'HTTP_X_CLIENTIP',
'HTTP_X_CLUSTER_CLIENT_IP',
'HTTP_X_FORWARDED',
'HTTP_X_FORWARDED_FOR',
'HTTP_X_IP_TRAIL',
'HTTP_X_REAL_IP',
'HTTP_X_VARNISH',
'REMOTE_ADDR',
) as $header ) {
if ( isset( $_SERVER[ $header ] ) ) {
$debug_info[ $header ] = array(
'label' => 'Server Variable ' . $header,
'value' => empty( $_SERVER[ $header ] ) ? 'false' : filter_var( wp_unslash( $_SERVER[ $header ] ) ),
'private' => true, // This isn't really 'private' information, but we don't want folks to easily paste these into public forums.
);
}
}
$debug_info['protect_header'] = array(
'label' => 'Trusted IP',
'value' => wp_json_encode( get_site_option( 'trusted_ip_header' ), JSON_UNESCAPED_SLASHES ),
'private' => false,
);
/** Sync Debug Information */
$sync_module = Modules::get_module( 'full-sync' );
'@phan-var \Automattic\Jetpack\Sync\Modules\Full_Sync_Immediately|\Automattic\Jetpack\Sync\Modules\Full_Sync $sync_module';
if ( $sync_module ) {
$sync_statuses = $sync_module->get_status();
$human_readable_sync_status = array();
foreach ( $sync_statuses as $sync_status => $sync_status_value ) {
$human_readable_sync_status[ $sync_status ] =
in_array( $sync_status, array( 'started', 'queue_finished', 'send_started', 'finished' ), true )
? gmdate( 'r', $sync_status_value ) : $sync_status_value;
}
$debug_info['full_sync'] = array(
'label' => 'Full Sync Status',
'value' => wp_json_encode( $human_readable_sync_status, JSON_UNESCAPED_SLASHES ),
'private' => false,
);
}
$queue = Sender::get_instance()->get_sync_queue();
$debug_info['sync_size'] = array(
'label' => 'Sync Queue Size',
'value' => $queue->size(),
'private' => false,
);
$debug_info['sync_lag'] = array(
'label' => 'Sync Queue Lag',
'value' => self::seconds_to_time( $queue->lag() ),
'private' => false,
);
$full_sync_queue = Sender::get_instance()->get_full_sync_queue();
$debug_info['full_sync_size'] = array(
'label' => 'Full Sync Queue Size',
'value' => $full_sync_queue->size(),
'private' => false,
);
$debug_info['full_sync_lag'] = array(
'label' => 'Full Sync Queue Lag',
'value' => self::seconds_to_time( $full_sync_queue->lag() ),
'private' => false,
);
/**
* IDC Information
*
* Must follow sync debug since it depends on sync functionality.
*/
$idc_urls = array(
'home' => Urls::home_url(),
'siteurl' => Urls::site_url(),
'WP_HOME' => Constants::is_defined( 'WP_HOME' ) ? Constants::get_constant( 'WP_HOME' ) : '',
'WP_SITEURL' => Constants::is_defined( 'WP_SITEURL' ) ? Constants::get_constant( 'WP_SITEURL' ) : '',
);
$debug_info['idc_urls'] = array(
'label' => 'IDC URLs',
'value' => wp_json_encode( $idc_urls, JSON_UNESCAPED_SLASHES ),
'private' => false,
);
$debug_info['idc_error_option'] = array(
'label' => 'IDC Error Option',
'value' => wp_json_encode( Jetpack_Options::get_option( 'sync_error_idc' ), JSON_UNESCAPED_SLASHES ),
'private' => false,
);
$debug_info['idc_optin'] = array(
'label' => 'IDC Opt-in',
'value' => Identity_Crisis::should_handle_idc(),
'private' => false,
);
// @todo -- Add testing results?
$cxn_tests = new Automattic\Jetpack\Connection\Connection_Health_Tests();
$debug_info['cxn_tests'] = array(
'label' => 'Connection Tests',
'value' => '',
'private' => false,
);
if ( $cxn_tests->pass() ) {
$debug_info['cxn_tests']['value'] = 'All Pass.';
} else {
$debug_info['cxn_tests']['value'] = wp_json_encode( $cxn_tests->list_fails(), JSON_UNESCAPED_SLASHES );
}
return $debug_info;
}
/**
* Returns a human readable string for which user is the master user.
*
* @return string
*/
private static function human_readable_master_user() {
$master_user = Jetpack_Options::get_option( 'master_user' );
if ( ! $master_user ) {
return __( 'No master user set.', 'jetpack' );
}
$user = new WP_User( $master_user );
if ( ! $user->exists() ) {
return __( 'Master user no longer exists. Please disconnect and reconnect Jetpack.', 'jetpack' );
}
return self::human_readable_user( $user );
}
/**
* Return human readable string for a given user object.
*
* @param WP_User|int $user Object or ID.
*
* @return string
*/
private static function human_readable_user( $user ) {
$user = new WP_User( $user );
return sprintf( '#%1$d %2$s', $user->ID, $user->user_login ); // Format: "#1 username".
}
}
@@ -0,0 +1,367 @@
<?php
/**
* Jetpack Debugger functionality allowing for self-service diagnostic information via the legacy jetpack debugger.
*
* @package automattic/jetpack
*/
use Automattic\Jetpack\Redirect;
use Automattic\Jetpack\Status;
/**
* Class Jetpack_Debugger
*
* A namespacing class for functionality related to the legacy in-plugin diagnostic tooling.
*/
class Jetpack_Debugger {
/**
* Disconnect Jetpack and redirect user to connection flow.
*
* Used in class.jetpack-admin.php.
*/
public static function disconnect_and_redirect() {
if ( ! ( isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], 'jp_disconnect' ) ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
return;
}
if ( ! empty( $_GET['disconnect'] ) ) {
if ( Jetpack::is_connection_ready() ) {
Jetpack::disconnect();
wp_safe_redirect( Jetpack::admin_url() );
exit( 0 );
}
}
}
/**
* Handles output to the browser for the in-plugin debugger.
*/
public static function jetpack_debug_display_handler() {
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'jetpack' ) );
}
$support_url = Jetpack::is_development_version()
? Redirect::get_url( 'jetpack-contact-support-beta-group' )
: Redirect::get_url( 'jetpack-contact-support' );
$cxntests = new Automattic\Jetpack\Connection\Connection_Health_Tests();
?>
<div class="wrap">
<div class="jp-static-block">
<h2><?php esc_html_e( 'Debugging Center', 'jetpack' ); ?></h2>
<div class="jp-static-block-body">
<h3><?php esc_html_e( "Testing your site's compatibility with Jetpack...", 'jetpack' ); ?></h3>
<div class="jetpack-debug-test-container">
<?php
if ( $cxntests->pass() ) {
echo '<div class="jetpack-tests-succeed">' . esc_html__( 'Your Jetpack setup looks a-okay!', 'jetpack' ) . '</div>';
} else {
$failures = $cxntests->list_fails();
foreach ( $failures as $fail ) {
?>
<div class="notice notice-error inline">
<div class="notice-icon-wrapper">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" width="24" height="24" class="y_IPyP1wIAOhyNaqvXJq" aria-hidden="true" focusable="false"><path d="M10 2c4.42 0 8 3.58 8 8s-3.58 8-8 8-8-3.58-8-8 3.58-8 8-8zm1.13 9.38l.35-6.46H8.52l.35 6.46h2.26zm-.09 3.36c.24-.23.37-.55.37-.96 0-.42-.12-.74-.36-.97s-.59-.35-1.06-.35-.82.12-1.07.35-.37.55-.37.97c0 .41.13.73.38.96.26.23.61.34 1.06.34s.8-.11 1.05-.34z"></path></svg>
</div>
<div class="notice-main-content">
<div class="notice-title"><?php echo esc_html( $fail['short_description'] ); ?></div>
<div class="notice-action-bar">
<div>
<a href="<?php echo esc_attr( $fail['action'] ); ?>" aria-disabled="false" class="components-button is-primary"><span><?php echo esc_html( $fail['action_label'] ); ?></span></a>
</div>
</div>
</div>
</div>
<?php
}
}
?>
</div>
<div class="entry-content">
<h4><?php esc_html_e( 'Trouble with Jetpack?', 'jetpack' ); ?></h4>
<p><?php esc_html_e( 'It may be caused by one of these issues, which you can diagnose yourself:', 'jetpack' ); ?></p>
<ol>
<li><?php esc_html_e( 'A known issue.', 'jetpack' ); ?>
<?php
printf(
wp_kses(
/* translators: URLs to Jetpack support pages. */
__( 'Some themes and plugins have <a href="%1$s" target="_blank" rel="noopener noreferrer">known conflicts</a> with Jetpack check the list. (You can also browse the <a href="%2$s" target="_blank" rel="noopener noreferrer">Jetpack support pages</a> or <a href="%3$s" target="_blank" rel="noopener noreferrer">Jetpack support forum</a> to see if others have experienced and solved the problem.)', 'jetpack' ),
array(
'a' => array(
'href' => array(),
'target' => array(),
'rel' => array(),
),
)
),
esc_url( Redirect::get_url( 'jetpack-contact-support-known-issues' ) ),
esc_url( Redirect::get_url( 'jetpack-support' ) ),
esc_url( Redirect::get_url( 'wporg-support-plugin-jetpack' ) )
);
?>
</li>
<li>
<?php esc_html_e( 'An incompatible plugin.', 'jetpack' ); ?>
<?php esc_html_e( "Find out by disabling all plugins except Jetpack. If the problem persists, it's not a plugin issue. If the problem is solved, turn your plugins on one by one until the problem pops up again there's the culprit! Let us know, and we'll try to help.", 'jetpack' ); ?>
</li>
<li>
<?php esc_html_e( 'A theme conflict.', 'jetpack' ); ?>
<?php
$default_theme = wp_get_theme( WP_DEFAULT_THEME );
if ( $default_theme->exists() ) {
/* translators: %s is the name of a theme */
echo esc_html( sprintf( __( "If your problem isn't known or caused by a plugin, try activating %s (the default WordPress theme).", 'jetpack' ), $default_theme->get( 'Name' ) ) );
} else {
esc_html_e( "If your problem isn't known or caused by a plugin, try activating the default WordPress theme.", 'jetpack' );
}
?>
<?php esc_html_e( "If this solves the problem, something in your theme is probably broken let the theme's author know.", 'jetpack' ); ?>
</li>
<li>
<?php esc_html_e( 'A problem with your XML-RPC file.', 'jetpack' ); ?>
<?php
printf(
wp_kses(
/* translators: The URL to the site's xmlrpc.php file. */
__( 'Load your <a href="%s">XML-RPC file</a>. It should say “XML-RPC server accepts POST requests only.” on a line by itself.', 'jetpack' ),
array( 'a' => array( 'href' => array() ) )
),
esc_attr( site_url( 'xmlrpc.php' ) )
);
?>
<ul>
<li><?php esc_html_e( "If it's not by itself, a theme or plugin is displaying extra characters. Try steps 2 and 3.", 'jetpack' ); ?></li>
<li><?php esc_html_e( 'If you get a 404 message, contact your web host. Their security may block the XML-RPC file.', 'jetpack' ); ?></li>
</ul>
</li>
<?php if ( current_user_can( 'jetpack_disconnect' ) && Jetpack::is_connection_ready() ) : ?>
<li>
<?php esc_html_e( 'A connection problem with WordPress.com.', 'jetpack' ); ?>
<?php
printf(
wp_kses(
/* translators: URL to disconnect and reconnect Jetpack. */
__( 'Jetpack works by connecting to WordPress.com for a lot of features. Sometimes, when the connection gets messed up, you need to disconnect and reconnect to get things working properly. <a href="%s">Disconnect from WordPress.com</a>', 'jetpack' ),
array(
'a' => array(
'href' => array(),
'class' => array(),
),
)
),
esc_attr(
wp_nonce_url(
Jetpack::admin_url(
array(
'page' => 'jetpack-debugger',
'disconnect' => true,
)
),
'jp_disconnect',
'nonce'
)
)
);
?>
</li>
<?php endif; ?>
</ol>
<h4><?php esc_html_e( 'Still having trouble?', 'jetpack' ); ?></h4>
<p>
<?php esc_html_e( 'Ask us for help!', 'jetpack' ); ?>
<?php
/**
* Offload to new WordPress debug data.
*/
printf(
wp_kses(
/* translators: URL for Jetpack support. URL for WordPress's Site Health */
__( '<a href="%1$s">Contact our Happiness team</a>. When you do, please include the <a href="%2$s">full debug information from your site</a>.', 'jetpack' ),
array( 'a' => array( 'href' => array() ) )
),
esc_url( $support_url ),
esc_url( admin_url() . 'site-health.php?tab=debug' )
);
?>
</p>
</div>
</div>
</div>
<div class="jp-static-block">
<h2><?php esc_html_e( 'More details about your Jetpack settings', 'jetpack' ); ?></h2>
<div class="jp-static-block-body">
<?php if ( Jetpack::is_connection_ready() ) : ?>
<div id="connected-user-details">
<p>
<?php
printf(
wp_kses(
/* translators: %s is an e-mail address */
__( 'The primary connection is owned by <strong>%s</strong>\'s WordPress.com account.', 'jetpack' ),
array( 'strong' => array() )
),
esc_html( Jetpack::get_master_user_email() )
);
?>
</p>
</div>
<?php else : ?>
<div id="dev-mode-details">
<p>
<?php
printf(
wp_kses(
/* translators: Link to a Jetpack support page. */
__( 'Would you like to use Jetpack on your local development site? You can do so thanks to <a href="%s">Jetpack\'s offline mode</a>.', 'jetpack' ),
array( 'a' => array( 'href' => array() ) )
),
esc_url( Redirect::get_url( 'jetpack-support-development-mode' ) )
);
?>
</p>
</div>
<?php endif; ?>
<?php
if (
current_user_can( 'jetpack_manage_modules' )
&& ( ( new Status() )->is_offline_mode() || Jetpack::is_connection_ready() )
) {
printf(
wp_kses(
'<p><a href="%1$s">%2$s</a></p>',
array(
'a' => array( 'href' => array() ),
'p' => array(),
)
),
esc_attr( Jetpack::admin_url( 'page=jetpack_modules' ) ),
esc_html__( 'Access the full list of Jetpack modules available on your site.', 'jetpack' )
);
}
?>
</div>
</div>
</div>
<?php
}
/**
* Outputs html needed within the <head> for the in-plugin debugger page.
*/
public static function jetpack_debug_admin_head() {
$min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
wp_enqueue_style( 'jetpack-admin', plugins_url( "css/jetpack-admin{$min}.css", JETPACK__PLUGIN_FILE ), array( 'genericons', 'jetpack-connection' ), JETPACK__VERSION . '-20121016' );
wp_style_add_data( 'jetpack-admin', 'rtl', 'replace' );
wp_style_add_data( 'jetpack-admin', 'suffix', $min );
Jetpack_Admin_Page::load_wrapper_styles();
?>
<style type="text/css">
.jetpack-debug-test-container {
margin: 8px 0;
}
#connected-user-details p strong {
word-break: break-all;
}
.jetpack-tests-succeed {
font-size: large;
color: #069E08;
}
.jetpack-test-details {
margin: 4px 6px;
padding: 10px;
overflow: auto;
display: none;
}
.formbox {
margin: 0 0 25px 0;
}
.formbox input[type="text"], .formbox input[type="email"], .formbox input[type="url"], .formbox textarea, #debug_info_div {
border: 1px solid var(--wpds-color-stroke-surface-neutral-weak, #e4e4e4);
border-radius: var(--wpds-border-radius-md, 4px);
color: #646970;
font-size: 14px;
padding: 10px;
width: 97%;
}
#debug_info_div {
border-radius: var(--wpds-border-radius-lg, 8px);
margin-top: 16px;
background: var(--wpds-color-bg-surface-neutral-strong, #fff);
padding: 16px;
}
.formbox .contact-support input[type="submit"] {
float: right;
margin: 0 !important;
border-radius: 20px !important;
cursor: pointer;
font-size: 13pt !important;
height: auto !important;
margin: 0 0 2em 10px !important;
padding: 8px 16px !important;
background-color: #dcdcde;
border: 1px solid rgba(0,0,0,0.05);
border-top-color: rgba(255,255,255,0.1);
border-bottom-color: rgba(0,0,0,0.15);
color: #333;
font-weight: 400;
display: inline-block;
text-align: center;
text-decoration: none;
}
.formbox span.errormsg {
margin: 0 0 10px 10px;
color: #d00;
display: none;
}
.formbox.error span.errormsg {
display: block;
}
#debug_info_div, #toggle_debug_info, #debug_info_div p {
font-size: 12px;
}
#category_div ul li {
list-style-type: none;
}
</style>
<script type="text/javascript">
jQuery( document ).ready( function($) {
$( '#debug_info' ).prepend( 'jQuery version: ' + jQuery.fn.jquery + "\r\n" );
$( '#debug_form_info' ).prepend( 'jQuery version: ' + jQuery.fn.jquery + "\r\n" );
$( '.jetpack-test-error .jetpack-test-heading' ).on( 'click', function() {
$( this ).parents( '.jetpack-test-error' ).find( '.jetpack-test-details' ).slideToggle();
return false;
} );
} );
</script>
<?php
}
}
@@ -0,0 +1,125 @@
<?php
/**
* WP Site Health debugging functions.
*
* @deprecated 15.9 Site Health integration is now handled by the connection package.
* @package automattic/jetpack
*/
/**
* Test runner for Core's Site Health module.
*
* @since 7.3.0
* @deprecated 15.9 Use Automattic\Jetpack\Connection\Site_Health instead.
*/
function jetpack_debugger_ajax_local_testing_suite() {
_deprecated_function( __FUNCTION__, 'jetpack-15.9' );
check_ajax_referer( 'health-check-site-status' );
if ( ! current_user_can( 'jetpack_manage_modules' ) ) {
// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
wp_send_json_error( null, null, JSON_UNESCAPED_SLASHES );
}
$tests = new Automattic\Jetpack\Connection\Connection_Health_Tests();
// @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal -- It takes null, but its phpdoc only says int.
wp_send_json_success( $tests->output_results_for_core_async_site_health(), null, JSON_UNESCAPED_SLASHES );
}
/**
* Adds the Jetpack Local Testing Suite to the Core Site Health system.
*
* @since 7.3.0
* @deprecated 15.9 Use Automattic\Jetpack\Connection\Site_Health instead.
*
* @param array $core_tests Array of tests from Core's Site Health.
*
* @return array $core_tests Array of tests for Core's Site Health.
*/
function jetpack_debugger_site_status_tests( $core_tests ) {
_deprecated_function( __FUNCTION__, 'jetpack-15.9' );
$cxn_tests = new Automattic\Jetpack\Connection\Connection_Health_Tests();
$tests = $cxn_tests->list_tests( 'direct' );
foreach ( $tests as $test ) {
$core_tests['direct'][ $test['name'] ] = array(
'label' => __( 'Jetpack: ', 'jetpack' ) . $test['name'],
/**
* Callable for Core's Site Health system to execute.
*
* @var array $test A Jetpack Testing Suite test array.
* @var Automattic\Jetpack\Connection\Connection_Health_Tests $cxn_tests An instance of the connection test suite.
*
* @return array {
* A results array to match the format expected by WordPress Core.
*
* @type string $label Name for the test.
* @type string $status 'critical', 'recommended', or 'good'.
* @type array $badge Array for Site Health status. Keys label and color.
* @type string $description Description of the test result.
* @type string $action HTML to a link to resolve issue.
* @type string $test Unique test identifier.
* }
*/
'test' => function () use ( $test, $cxn_tests ) {
$results = $cxn_tests->run_test( $test['name'] );
if ( is_wp_error( $results ) ) {
return;
}
$label = $results['label'] ?
$results['label'] :
ucwords(
str_replace(
'_',
' ',
str_replace( 'test__', '', $test['name'] )
)
);
if ( $results['long_description'] ) {
$description = $results['long_description'];
} elseif ( $results['short_description'] ) {
$description = sprintf(
'<p>%s</p>',
$results['short_description']
);
} else {
$description = sprintf(
'<p>%s</p>',
__( 'This test successfully passed!', 'jetpack' )
);
}
$return = array(
'label' => $label,
'status' => 'good',
'badge' => array(
'label' => __( 'Jetpack', 'jetpack' ),
'color' => 'green',
),
'description' => $description,
'actions' => '',
'test' => 'jetpack_' . $test['name'],
);
if ( false === $results['pass'] ) {
$return['status'] = $results['severity'];
if ( ! empty( $results['action'] ) ) {
$return['actions'] = sprintf(
'<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a>',
esc_url( $results['action'] ),
$results['action_label'],
/* translators: accessibility text */
__( '(opens in a new tab)', 'jetpack' )
);
}
}
return $return;
},
);
}
$core_tests['async']['jetpack_test_suite'] = array(
'label' => __( 'Jetpack Tests', 'jetpack' ),
'test' => 'jetpack_local_testing_suite',
);
return $core_tests;
}