summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/_inc/lib')
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class-jetpack-about-page.php216
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php186
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php100
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php9
-rw-r--r--plugins/jetpack/_inc/lib/class.color.php18
-rw-r--r--plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php524
-rw-r--r--plugins/jetpack/_inc/lib/class.jetpack-automatic-install-skin.php7
-rw-r--r--plugins/jetpack/_inc/lib/class.jetpack-keyring-service-helper.php35
-rw-r--r--plugins/jetpack/_inc/lib/class.jetpack-password-checker.php2
-rw-r--r--plugins/jetpack/_inc/lib/class.media-extractor.php8
-rw-r--r--plugins/jetpack/_inc/lib/class.media-summary.php12
-rw-r--r--plugins/jetpack/_inc/lib/class.media.php80
-rw-r--r--plugins/jetpack/_inc/lib/components.php109
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php23
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php228
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php38
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-resolve-redirect.php94
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php26
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php6
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php17
-rw-r--r--plugins/jetpack/_inc/lib/debugger/0-load.php13
-rw-r--r--plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-test-base.php4
-rw-r--r--plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-tests.php66
-rw-r--r--plugins/jetpack/_inc/lib/debugger/class-jetpack-debug-data.php47
-rw-r--r--plugins/jetpack/_inc/lib/debugger/class-jetpack-debugger.php110
-rw-r--r--plugins/jetpack/_inc/lib/debugger/debug-functions.php (renamed from plugins/jetpack/_inc/lib/debugger/debug-functions-for-php53.php)0
-rw-r--r--plugins/jetpack/_inc/lib/icalendar-reader.php19
-rw-r--r--plugins/jetpack/_inc/lib/markdown/extra.php36
-rw-r--r--plugins/jetpack/_inc/lib/markdown/gfm.php2
-rw-r--r--plugins/jetpack/_inc/lib/plans.php75
-rw-r--r--plugins/jetpack/_inc/lib/tonesque.php12
-rw-r--r--plugins/jetpack/_inc/lib/tracks/class.tracks-client.php191
-rw-r--r--plugins/jetpack/_inc/lib/tracks/class.tracks-event.php149
-rw-r--r--plugins/jetpack/_inc/lib/tracks/client.php130
-rw-r--r--plugins/jetpack/_inc/lib/tracks/tracks-ajax.js2
-rw-r--r--plugins/jetpack/_inc/lib/tracks/tracks-callables.js3
-rw-r--r--plugins/jetpack/_inc/lib/widgets.php14
37 files changed, 1356 insertions, 1255 deletions
diff --git a/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-about-page.php b/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-about-page.php
index b9987a0f..5f519ff2 100644
--- a/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-about-page.php
+++ b/plugins/jetpack/_inc/lib/admin-pages/class-jetpack-about-page.php
@@ -27,6 +27,13 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
protected $dont_show_if_not_active = true;
/**
+ * Anonymous info about a12s. The method fetch_a8c_data() stores the response from wpcom here.
+ *
+ * @var array
+ */
+ private $a8c_data = null;
+
+ /**
* Add a submenu item to the Jetpack admin menu.
*
* @return string
@@ -34,9 +41,9 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
public function get_page_hook() {
// Add the main admin Jetpack menu.
return add_submenu_page(
- 'jetpack',
- esc_html__( 'About Jetpack', 'jetpack' ),
+ null,
esc_html__( 'About Jetpack', 'jetpack' ),
+ '',
'jetpack_admin_page',
'jetpack_about',
array( $this, 'render' )
@@ -49,9 +56,7 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
* @param string $hook Hook of current page, unused.
*/
public function add_page_actions( $hook ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
- // Place the Jetpack menu item on top and others in the order they appear.
- add_filter( 'custom_menu_order', '__return_true' );
- add_filter( 'menu_order', array( $this, 'submenu_order' ) );
+ $this->a8c_data = $this->fetch_a8c_data();
}
/**
@@ -82,37 +87,6 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
}
/**
- * Change order of menu item so the About page menu item is below Site Stats.
- *
- * @param array $menu_order List of menu slugs. It's unaffected. This filter is used to reorder the Jetpack submenu items.
- *
- * @return array
- */
- public function submenu_order( $menu_order ) {
- global $submenu;
-
- $stats_key = null;
- $about_key = null;
-
- foreach ( $submenu['jetpack'] as $index => $menu_item ) {
- if ( false !== array_search( 'stats', $menu_item, true ) ) {
- $stats_key = $index;
- }
- if ( false !== array_search( 'jetpack_about', $menu_item, true ) ) {
- $about_key = $index;
- }
- }
-
- if ( $stats_key && $about_key ) {
- $temp = $submenu['jetpack'][ $stats_key ];
- $submenu['jetpack'][ $stats_key ] = $submenu['jetpack'][ $about_key ]; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
- $submenu['jetpack'][ $about_key ] = $temp; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
- }
-
- return $menu_order;
- }
-
- /**
* Render the page content
*/
public function page_render() {
@@ -171,7 +145,17 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
</a>
</p>
<p>
- <?php esc_html_e( 'We’re a distributed company with over 875 Automatticians in more than 67 countries speaking at least 83 different languages. Our common goal is to democratize publishing so that anyone with a story can tell it, regardless of income, gender, politics, language, or where they live in the world.', 'jetpack' ); ?>
+ <?php
+ echo esc_html(
+ sprintf(
+ /* translators: first placeholder is the number of Automattic employees. The second is the number of countries of origin*/
+ __( 'We’re a distributed company with over %1$s Automatticians in more than %2$s countries speaking at least %3$s different languages. Our common goal is to democratize publishing so that anyone with a story can tell it, regardless of income, gender, politics, language, or where they live in the world.', 'jetpack' ),
+ $this->a8c_data['a12s'],
+ $this->a8c_data['countries'],
+ $this->a8c_data['languages']
+ )
+ );
+ ?>
</p>
<p>
<?php esc_html_e( 'We believe in Open Source and the vast majority of our work is available under the GPL.', 'jetpack' ); ?>
@@ -253,12 +237,7 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
);
// slugs for plugins we want to display.
- $a8c_plugins = array(
- 'woocommerce',
- 'wp-super-cache',
- 'wp-job-manager',
- 'co-authors-plus',
- );
+ $a8c_plugins = $this->a8c_data['featured_plugins'];
// need this to access the plugins_api() function.
include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
@@ -433,9 +412,9 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
/* translators: 1: "Update WordPress" screen URL, 2: "Update PHP" page URL */
' ' . wp_kses( __( '<a href="%1$s">Please update WordPress</a>, and then <a href="%2$s">learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
esc_url( self_admin_url( 'update-core.php' ) ),
- esc_url( $this->jp_get_update_php_url() )
+ esc_url( wp_get_update_php_url() )
);
- $this->jp_update_php_annotation();
+ wp_update_php_annotation();
} elseif ( current_user_can( 'update_core' ) ) {
printf(
/* translators: %s: "Update WordPress" screen URL */
@@ -446,9 +425,9 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
printf(
/* translators: %s: "Update PHP" page URL */
' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
- esc_url( $this->jp_get_update_php_url() )
+ esc_url( wp_get_update_php_url() )
);
- $this->jp_update_php_annotation();
+ wp_update_php_annotation();
}
} elseif ( ! $compatible_wp ) {
esc_html_e( 'This plugin doesn&#8217;t work with your version of WordPress.', 'jetpack' );
@@ -465,9 +444,9 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
printf(
/* translators: %s: "Update PHP" page URL */
' ' . wp_kses( __( '<a href="%s">Learn more about updating PHP</a>.', 'jetpack' ), array( 'a' => array( 'href' => true ) ) ),
- esc_url( $this->jp_get_update_php_url() )
+ esc_url( wp_get_update_php_url() )
);
- $this->jp_update_php_annotation();
+ wp_update_php_annotation();
}
}
echo '</p></div>';
@@ -479,7 +458,7 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
<h3>
<a href="<?php echo esc_url( $details_link ); ?>" class="jptracks thickbox open-plugin-details-modal" data-jptracks-name="jetpack_about_plugin_modal" data-jptracks-prop="<?php echo esc_attr( $plugin['slug'] ); ?>">
<?php echo esc_html( $title ); ?>
- <img src="<?php echo esc_attr( $plugin_icon_url ); ?>" class="plugin-icon" alt="">
+ <img src="<?php echo esc_url( $plugin_icon_url ); ?>" class="plugin-icon" alt="<?php esc_attr_e( 'Plugin icon', 'jetpack' ); ?>" aria-hidden="true">
</a>
</h3>
</div>
@@ -542,7 +521,43 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
}
/**
- * Fetch Gravatar hashes for public A12s from wpcom and display them as a list.
+ * Fetch anonymous data about A12s from wpcom: total count, number of countries, languages spoken.
+ *
+ * @since 7.4
+ *
+ * @return array $data
+ */
+ private function fetch_a8c_data() {
+ $data = get_transient( 'jetpack_a8c_data' );
+ if ( false === $data ) {
+ $data = json_decode(
+ wp_remote_retrieve_body(
+ wp_remote_get( 'https://public-api.wordpress.com/wpcom/v2/jetpack-about' )
+ ),
+ true
+ );
+ if ( ! empty( $data ) && is_array( $data ) ) {
+ set_transient( 'jetpack_a8c_data', $data, DAY_IN_SECONDS );
+ } else {
+ // Fallback if everything fails.
+ $data = array(
+ 'a12s' => 888,
+ 'countries' => 69,
+ 'languages' => 83,
+ 'featured_plugins' => array(
+ 'woocommerce',
+ 'wp-super-cache',
+ 'wp-job-manager',
+ 'co-authors-plus',
+ ),
+ );
+ }
+ }
+ return $data;
+ }
+
+ /**
+ * Compile and display a list of avatars for A12s that gave their permission.
*
* @since 7.3
*/
@@ -556,7 +571,7 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
'https://1.gravatar.com/avatar/c510e69d83c7d10be4df64feeff4e46a',
'https://0.gravatar.com/avatar/88ec0dcadea38adf5f30a17e54e9b248',
'https://1.gravatar.com/avatar/bc45834430c5b0936d76e3f468f9ca57',
- 'https://0.gravatar.com/avatar/032677e4115f3a38dc7785529e8cc4d9',
+ 'https://0.gravatar.com/avatar/0619d4de8aef78c81b2194ff1d164d85',
'https://0.gravatar.com/avatar/72a638c2520ea177976e8eafb201a82f',
'https://0.gravatar.com/avatar/b3618d70c63bbc5cc7caee0beded5ff0',
'https://1.gravatar.com/avatar/4d346581a3340e32cf93703c9ce46bd4',
@@ -579,101 +594,4 @@ class Jetpack_About_Page extends Jetpack_Admin_Page {
)
);
}
-
- // The following methods jp_get_update_php_url, jp_get_default_update_php_url, and jp_update_php_annotation,
- // are copies of functions introduced in WP 5.1
- // At the time of releasing this, we're still supporting WP 5.0, so we needed
- // to have them here to avoid fatal errors in old installations.
-
- /**
- * Gets the URL to learn more about updating the PHP version the site is running on.
- *
- * This URL can be overridden by specifying an environment variable `WP_UPDATE_PHP_URL` or by using the
- * {@see 'wp_update_php_url'} filter. Providing an empty string is not allowed and will result in the
- * default URL being used. Furthermore the page the URL links to should preferably be localized in the
- * site language.
- *
- * @todo: Remove when 5.1 is minimum WP version.
- * @since 5.1.0
- *
- * @return string URL to learn more about updating PHP.
- */
- private function jp_get_update_php_url() {
- $default_url = $this->jp_get_default_update_php_url();
-
- $update_url = $default_url;
- if ( false !== getenv( 'WP_UPDATE_PHP_URL' ) ) {
- $update_url = getenv( 'WP_UPDATE_PHP_URL' );
- }
-
- /**
- * Filters the URL to learn more about updating the PHP version the site is running on.
- *
- * Providing an empty string is not allowed and will result in the default URL being used. Furthermore
- * the page the URL links to should preferably be localized in the site language.
- *
- * @since 5.1.0
- *
- * @param string $update_url URL to learn more about updating PHP.
- */
- $update_url = apply_filters( 'wp_update_php_url', $update_url );
-
- if ( empty( $update_url ) ) {
- $update_url = $default_url;
- }
-
- return $update_url;
- }
-
- /**
- * Gets the default URL to learn more about updating the PHP version the site is running on.
- *
- * Do not use this function to retrieve this URL. Instead, use {@see wp_get_update_php_url()} when relying on the URL.
- * This function does not allow modifying the returned URL, and is only used to compare the actually used URL with the
- * default one.
- *
- * @todo: Remove when 5.1 is minimum WP version.
- * @since 5.1.0
- * @access private
- *
- * @return string Default URL to learn more about updating PHP.
- */
- private function jp_get_default_update_php_url() {
- return _x( 'https://wordpress.org/support/update-php/', 'localized PHP upgrade information page', 'jetpack' );
- }
-
- /**
- * Prints the default annotation for the web host altering the "Update PHP" page URL.
- *
- * This function is to be used after {@see wp_get_update_php_url()} to display a consistent
- * annotation if the web host has altered the default "Update PHP" page URL.
- *
- * @todo: Remove when 5.1 is minimum WP version.
- * @since 5.1.0
- */
- private function jp_update_php_annotation() {
- $update_url = $this->jp_get_update_php_url();
- $default_url = $this->jp_get_default_update_php_url();
-
- if ( $update_url === $default_url ) {
- return;
- }
-
- echo '<p class="description">';
- printf(
- wp_kses(
- /* translators: %s: default Update PHP page URL */
- __( 'This resource is provided by your web host, and is specific to your site. For more information, <a href="%s" target="_blank" rel="noopener noreferrer">see the official WordPress documentation</a>.', 'jetpack' ),
- array(
- 'a' => array(
- 'href' => true,
- 'rel' => true,
- ),
- )
- ),
- esc_url( $default_url )
- );
- echo '</p>';
- }
-
}
diff --git a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php
index a6822678..9baa3edb 100644
--- a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php
+++ b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-admin-page.php
@@ -1,5 +1,7 @@
<?php
+use Automattic\Jetpack\Status;
+
// Shared logic between Jetpack admin pages
abstract class Jetpack_Admin_Page {
// Add page specific actions given the page hook
@@ -38,13 +40,14 @@ abstract class Jetpack_Admin_Page {
function add_actions() {
global $pagenow;
- // If user is not an admin and site is in Dev Mode, don't do anything
- if ( ! current_user_can( 'manage_options' ) && Jetpack::is_development_mode() ) {
+ $is_development_mode = ( new Status() )->is_development_mode();
+ // If user is not an admin and site is in Dev Mode or not connected yet then don't do anything.
+ if ( ! current_user_can( 'manage_options' ) && ( $is_development_mode || ! Jetpack::is_active() ) ) {
return;
}
// Don't add in the modules page unless modules are available!
- if ( $this->dont_show_if_not_active && ! Jetpack::is_active() && ! Jetpack::is_development_mode() ) {
+ if ( $this->dont_show_if_not_active && ! Jetpack::is_active() && ! $is_development_mode ) {
return;
}
@@ -66,14 +69,25 @@ abstract class Jetpack_Admin_Page {
( 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'jetpack' === $_GET['page'] )
&& ! Jetpack::is_active()
&& current_user_can( 'jetpack_connect' )
- && ! Jetpack::is_development_mode()
+ && ! $is_development_mode
) {
add_action( 'admin_enqueue_scripts', array( 'Jetpack_Connection_Banner', 'enqueue_banner_scripts' ) );
+ add_action( 'admin_enqueue_scripts', array( 'Jetpack_Connection_Banner', 'enqueue_connect_button_scripts' ) );
add_action( 'admin_print_styles', array( Jetpack::init(), 'admin_banner_styles' ) );
add_action( 'admin_notices', array( 'Jetpack_Connection_Banner', 'render_connect_prompt_full_screen' ) );
delete_transient( 'activated_jetpack' );
}
+ // If Jetpack not yet connected, but user is viewing one of the pages with a Jetpack connection banner.
+ if (
+ ( 'index.php' === $pagenow || 'plugins.php' === $pagenow )
+ && ! Jetpack::is_active()
+ && current_user_can( 'jetpack_connect' )
+ && ! $is_development_mode
+ ) {
+ add_action( 'admin_enqueue_scripts', array( 'Jetpack_Connection_Banner', 'enqueue_connect_button_scripts' ) );
+ }
+
// Check if the site plan changed and deactivate modules accordingly.
add_action( 'current_screen', array( $this, 'check_plan_deactivate_modules' ) );
@@ -147,7 +161,7 @@ abstract class Jetpack_Admin_Page {
*/
function check_plan_deactivate_modules( $page ) {
if (
- Jetpack::is_development_mode()
+ ( new Status() )->is_development_mode()
|| ! in_array(
$page->base,
array(
@@ -202,7 +216,7 @@ abstract class Jetpack_Admin_Page {
static function load_wrapper_styles() {
$rtl = is_rtl() ? '.rtl' : '';
- wp_enqueue_style( 'dops-css', plugins_url( "_inc/build/admin.dops-style{$rtl}.css", JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION );
+ wp_enqueue_style( 'dops-css', plugins_url( "_inc/build/admin{$rtl}.css", JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION );
wp_enqueue_style( 'components-css', plugins_url( "_inc/build/style.min{$rtl}.css", JETPACK__PLUGIN_FILE ), array(), JETPACK__VERSION );
$custom_css = '
#wpcontent {
@@ -271,7 +285,6 @@ abstract class Jetpack_Admin_Page {
<?php
if ( is_network_admin() ) {
$current_screen = get_current_screen();
-
$highlight_current_sites = ( 'toplevel_page_jetpack-network' === $current_screen->id ? 'is-primary' : '' );
$highlight_current_settings = ( 'jetpack_page_jetpack-settings-network' === $current_screen->id ? 'is-primary' : '' );
?>
@@ -314,40 +327,135 @@ abstract class Jetpack_Admin_Page {
echo $callback_ui;
?>
<!-- END OF CALLBACK -->
- <div class="jp-footer">
- <div class="jp-footer__a8c-attr-container"><a href="https://automattic.com" target="_blank" rel="noopener noreferrer"><svg role="img" class="jp-footer__a8c-attr" x="0" y="0" viewBox="0 0 935 38.2" enable-background="new 0 0 935 38.2" aria-labelledby="a8c-svg-title"><title id="a8c-svg-title">An Automattic Airline</title><path d="M317.1 38.2c-12.6 0-20.7-9.1-20.7-18.5v-1.2c0-9.6 8.2-18.5 20.7-18.5 12.6 0 20.8 8.9 20.8 18.5v1.2C337.9 29.1 329.7 38.2 317.1 38.2zM331.2 18.6c0-6.9-5-13-14.1-13s-14 6.1-14 13v0.9c0 6.9 5 13.1 14 13.1s14.1-6.2 14.1-13.1V18.6zM175 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7L157 1.3h5.5L182 36.8H175zM159.7 8.2L152 23.1h15.7L159.7 8.2zM212.4 38.2c-12.7 0-18.7-6.9-18.7-16.2V1.3h6.6v20.9c0 6.6 4.3 10.5 12.5 10.5 8.4 0 11.9-3.9 11.9-10.5V1.3h6.7V22C231.4 30.8 225.8 38.2 212.4 38.2zM268.6 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H268.6zM397.3 36.8V8.7l-1.8 3.1 -14.9 25h-3.3l-14.7-25 -1.8-3.1v28.1h-6.5V1.3h9.2l14 24.4 1.7 3 1.7-3 13.9-24.4h9.1v35.5H397.3zM454.4 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7l19.2-35.5h5.5l19.5 35.5H454.4zM439.1 8.2l-7.7 14.9h15.7L439.1 8.2zM488.4 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H488.4zM537.3 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H537.3zM569.3 36.8V4.6c2.7 0 3.7-1.4 3.7-3.4h2.8v35.5L569.3 36.8 569.3 36.8zM628 11.3c-3.2-2.9-7.9-5.7-14.2-5.7 -9.5 0-14.8 6.5-14.8 13.3v0.7c0 6.7 5.4 13 15.3 13 5.9 0 10.8-2.8 13.9-5.7l4 4.2c-3.9 3.8-10.5 7.1-18.3 7.1 -13.4 0-21.6-8.7-21.6-18.3v-1.2c0-9.6 8.9-18.7 21.9-18.7 7.5 0 14.3 3.1 18 7.1L628 11.3zM321.5 12.4c1.2 0.8 1.5 2.4 0.8 3.6l-6.1 9.4c-0.8 1.2-2.4 1.6-3.6 0.8l0 0c-1.2-0.8-1.5-2.4-0.8-3.6l6.1-9.4C318.7 11.9 320.3 11.6 321.5 12.4L321.5 12.4z"></path><path d="M37.5 36.7l-4.7-8.9H11.7l-4.6 8.9H0L19.4 0.8H25l19.7 35.9H37.5zM22 7.8l-7.8 15.1h15.9L22 7.8zM82.8 36.7l-23.3-24 -2.3-2.5v26.6h-6.7v-36H57l22.6 24 2.3 2.6V0.8h6.7v35.9H82.8z"></path><path d="M719.9 37l-4.8-8.9H694l-4.6 8.9h-7.1l19.5-36h5.6l19.8 36H719.9zM704.4 8l-7.8 15.1h15.9L704.4 8zM733 37V1h6.8v36H733zM781 37c-1.8 0-2.6-2.5-2.9-5.8l-0.2-3.7c-0.2-3.6-1.7-5.1-8.4-5.1h-12.8V37H750V1h19.6c10.8 0 15.7 4.3 15.7 9.9 0 3.9-2 7.7-9 9 7 0.5 8.5 3.7 8.6 7.9l0.1 3c0.1 2.5 0.5 4.3 2.2 6.1V37H781zM778.5 11.8c0-2.6-2.1-5.1-7.9-5.1h-13.8v10.8h14.4c5 0 7.3-2.4 7.3-5.2V11.8zM794.8 37V1h6.8v30.4h28.2V37H794.8zM836.7 37V1h6.8v36H836.7zM886.2 37l-23.4-24.1 -2.3-2.5V37h-6.8V1h6.5l22.7 24.1 2.3 2.6V1h6.8v36H886.2zM902.3 37V1H935v5.6h-26v9.2h20v5.5h-20v10.1h26V37H902.3z"></path></svg></a></div>
- <ul class="jp-footer__links">
- <li class="jp-footer__link-item">
- <a href="https://jetpack.com" target="_blank" rel="noopener noreferrer" class="jp-footer__link" title="<?php esc_html_e( 'Jetpack version', 'jetpack' ); ?>">Jetpack <?php echo JETPACK__VERSION; ?></a>
- </li>
- <li class="jp-footer__link-item">
- <a href="https://wordpress.com/tos/" target="_blank" rel="noopener noreferrer" title="<?php esc_html__( 'WordPress.com Terms of Service', 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Terms', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <li class="jp-footer__link-item">
- <a href="<?php echo esc_url( $jetpack_admin_url . '#/privacy' ); ?>" rel="noopener noreferrer" title="<?php esc_html_e( "Automattic's Privacy Policy", 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Privacy', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <?php if ( is_multisite() && current_user_can( 'jetpack_network_sites_page' ) ) { ?>
- <li class="jp-footer__link-item">
- <a href="<?php echo esc_url( network_admin_url( 'admin.php?page=jetpack' ) ); ?>" title="<?php esc_html_e( "Manage your network's Jetpack Sites.", 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Network Sites', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <?php } ?>
- <?php if ( is_multisite() && current_user_can( 'jetpack_network_settings_page' ) ) { ?>
- <li class="jp-footer__link-item">
- <a href="<?php echo esc_url( network_admin_url( 'admin.php?page=jetpack-settings' ) ); ?>" title="<?php esc_html_e( "Manage your network's Jetpack Sites.", 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Network Settings', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <?php } ?>
- <?php if ( current_user_can( 'manage_options' ) ) { ?>
- <li class="jp-footer__link-item">
- <a href="<?php echo esc_url( admin_url() . 'admin.php?page=jetpack_modules' ); ?>" title="<?php esc_html_e( "Access the full list of Jetpack modules available on your site.", 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Modules', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <li class="jp-footer__link-item">
- <a href="<?php echo esc_url( admin_url() . 'admin.php?page=jetpack-debugger' ); ?>" title="<?php esc_html_e( "Test your site's compatibility with Jetpack.", 'jetpack' ); ?>" class="jp-footer__link"><?php echo esc_html_x( 'Debug', 'Navigation item', 'jetpack' ); ?></a>
- </li>
- <?php } ?>
- </ul>
- </div>
+ <?php self::render_footer(); ?>
</div>
<?php
return;
}
+
+ /**
+ * Output a list item with a link.
+ *
+ * @param string $url URL.
+ * @param string $title Link title attribute.
+ * @param string $text Link text.
+ * @param bool $is_internal Is the link linking to an internal or external domain.
+ */
+ public static function the_footer_link( $url, $title, $text, $is_internal = true ) {
+ printf(
+ '<li class="jp-footer__link-item"><a class="jp-footer__link" href="%1$s" title="%2$s" %4$s>%3$s</a></li>',
+ esc_url( $url ),
+ esc_attr( $title ),
+ esc_html( $text ),
+ ( $is_internal ? '' : 'target="_blank" rel="noopener noreferrer"' )
+ );
+ }
+
+ /**
+ * Render the footer of the jetpack dashboard. For admin pages.
+ *
+ * Note that the Jetpack Dashboard may append additional links to that list.
+ */
+ public static function render_footer() {
+ $admin_url = admin_url( 'admin.php?page=jetpack' );
+
+ $is_dev_mode_or_connected = Jetpack::is_active() || ( new Status() )->is_development_mode();
+
+ $privacy_url = ( $is_dev_mode_or_connected )
+ ? $admin_url . '#/privacy'
+ : 'https://automattic.com/privacy/';
+
+ $about_url = ( $is_dev_mode_or_connected )
+ ? admin_url( 'admin.php?page=jetpack_about' )
+ : 'https://jetpack.com';
+
+ ?>
+ <div class="jp-footer">
+ <div class="jp-footer__a8c-attr-container">
+ <a href="<?php echo esc_url( $about_url ); ?>">
+ <svg role="img" class="jp-footer__a8c-attr" x="0" y="0" viewBox="0 0 935 38.2" enable-background="new 0 0 935 38.2" aria-labelledby="a8c-svg-title"><title id="a8c-svg-title">An Automattic Airline</title><path d="M317.1 38.2c-12.6 0-20.7-9.1-20.7-18.5v-1.2c0-9.6 8.2-18.5 20.7-18.5 12.6 0 20.8 8.9 20.8 18.5v1.2C337.9 29.1 329.7 38.2 317.1 38.2zM331.2 18.6c0-6.9-5-13-14.1-13s-14 6.1-14 13v0.9c0 6.9 5 13.1 14 13.1s14.1-6.2 14.1-13.1V18.6zM175 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7L157 1.3h5.5L182 36.8H175zM159.7 8.2L152 23.1h15.7L159.7 8.2zM212.4 38.2c-12.7 0-18.7-6.9-18.7-16.2V1.3h6.6v20.9c0 6.6 4.3 10.5 12.5 10.5 8.4 0 11.9-3.9 11.9-10.5V1.3h6.7V22C231.4 30.8 225.8 38.2 212.4 38.2zM268.6 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H268.6zM397.3 36.8V8.7l-1.8 3.1 -14.9 25h-3.3l-14.7-25 -1.8-3.1v28.1h-6.5V1.3h9.2l14 24.4 1.7 3 1.7-3 13.9-24.4h9.1v35.5H397.3zM454.4 36.8l-4.7-8.8h-20.9l-4.5 8.8h-7l19.2-35.5h5.5l19.5 35.5H454.4zM439.1 8.2l-7.7 14.9h15.7L439.1 8.2zM488.4 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H488.4zM537.3 6.8v30h-6.7v-30h-15.5V1.3h37.7v5.5H537.3zM569.3 36.8V4.6c2.7 0 3.7-1.4 3.7-3.4h2.8v35.5L569.3 36.8 569.3 36.8zM628 11.3c-3.2-2.9-7.9-5.7-14.2-5.7 -9.5 0-14.8 6.5-14.8 13.3v0.7c0 6.7 5.4 13 15.3 13 5.9 0 10.8-2.8 13.9-5.7l4 4.2c-3.9 3.8-10.5 7.1-18.3 7.1 -13.4 0-21.6-8.7-21.6-18.3v-1.2c0-9.6 8.9-18.7 21.9-18.7 7.5 0 14.3 3.1 18 7.1L628 11.3zM321.5 12.4c1.2 0.8 1.5 2.4 0.8 3.6l-6.1 9.4c-0.8 1.2-2.4 1.6-3.6 0.8l0 0c-1.2-0.8-1.5-2.4-0.8-3.6l6.1-9.4C318.7 11.9 320.3 11.6 321.5 12.4L321.5 12.4z"></path><path d="M37.5 36.7l-4.7-8.9H11.7l-4.6 8.9H0L19.4 0.8H25l19.7 35.9H37.5zM22 7.8l-7.8 15.1h15.9L22 7.8zM82.8 36.7l-23.3-24 -2.3-2.5v26.6h-6.7v-36H57l22.6 24 2.3 2.6V0.8h6.7v35.9H82.8z"></path><path d="M719.9 37l-4.8-8.9H694l-4.6 8.9h-7.1l19.5-36h5.6l19.8 36H719.9zM704.4 8l-7.8 15.1h15.9L704.4 8zM733 37V1h6.8v36H733zM781 37c-1.8 0-2.6-2.5-2.9-5.8l-0.2-3.7c-0.2-3.6-1.7-5.1-8.4-5.1h-12.8V37H750V1h19.6c10.8 0 15.7 4.3 15.7 9.9 0 3.9-2 7.7-9 9 7 0.5 8.5 3.7 8.6 7.9l0.1 3c0.1 2.5 0.5 4.3 2.2 6.1V37H781zM778.5 11.8c0-2.6-2.1-5.1-7.9-5.1h-13.8v10.8h14.4c5 0 7.3-2.4 7.3-5.2V11.8zM794.8 37V1h6.8v30.4h28.2V37H794.8zM836.7 37V1h6.8v36H836.7zM886.2 37l-23.4-24.1 -2.3-2.5V37h-6.8V1h6.5l22.7 24.1 2.3 2.6V1h6.8v36H886.2zM902.3 37V1H935v5.6h-26v9.2h20v5.5h-20v10.1h26V37H902.3z"></path></svg>
+ </a>
+ </div>
+ <ul class="jp-footer__links" id="jp-footer__links-id">
+ <?php
+ // Version number.
+ self::the_footer_link(
+ 'https://jetpack.com',
+ __( 'Jetpack version', 'jetpack' ),
+ sprintf(
+ /* Translators: placeholder is a number. */
+ __( 'Jetpack version %s', 'jetpack' ),
+ JETPACK__VERSION
+ ),
+ false
+ );
+
+ // About page.
+ self::the_footer_link(
+ $about_url,
+ __( 'About Jetpack', 'jetpack' ),
+ __( 'About', 'jetpack' ),
+ $is_dev_mode_or_connected
+ );
+
+ // TOS.
+ self::the_footer_link(
+ 'https://wordpress.com/tos/',
+ __( 'WordPress.com Terms of Service', 'jetpack' ),
+ _x( 'Terms', 'Navigation item', 'jetpack' ),
+ false
+ );
+
+ // Privacy policy.
+ self::the_footer_link(
+ $privacy_url,
+ __( "Automattic's Privacy Policy", 'jetpack' ),
+ _x( 'Privacy', 'Navigation item', 'jetpack' ),
+ $is_dev_mode_or_connected
+ );
+
+ // Network Admin Jetpack dashboard.
+ if ( is_multisite() && current_user_can( 'jetpack_network_sites_page' ) ) {
+ self::the_footer_link(
+ network_admin_url( 'admin.php?page=jetpack' ),
+ __( "Manage your network's Jetpack Sites", 'jetpack' ),
+ _x( 'Network Sites', 'Navigation item', 'jetpack' ),
+ true
+ );
+ }
+
+ // Network Admin Jetpack settings.
+ if ( is_multisite() && current_user_can( 'jetpack_network_settings_page' ) ) {
+ self::the_footer_link(
+ network_admin_url( 'admin.php?page=jetpack-settings' ),
+ __( "Manage your network's Jetpack settings", 'jetpack' ),
+ _x( 'Network Settings', 'Navigation item', 'jetpack' ),
+ true
+ );
+ }
+
+ // Legacy Modules page.
+ if ( current_user_can( 'manage_options' ) && $is_dev_mode_or_connected ) {
+ self::the_footer_link(
+ admin_url( 'admin.php?page=jetpack_modules' ),
+ __( 'Access the full list of Jetpack modules available on your site', 'jetpack' ),
+ _x( 'Modules', 'Navigation item', 'jetpack' ),
+ true
+ );
+ }
+
+ // Debugger.
+ if ( current_user_can( 'manage_options' ) ) {
+ self::the_footer_link(
+ admin_url( 'admin.php?page=jetpack-debugger' ),
+ __( "Test your site's compatibility with Jetpack", 'jetpack' ),
+ _x( 'Debug', 'Navigation item', 'jetpack' ),
+ true
+ );
+ }
+ ?>
+ </ul>
+ </div>
+ <?php
+ }
}
diff --git a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php
index e5a423f0..9d3ce44c 100644
--- a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php
+++ b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php
@@ -1,4 +1,6 @@
<?php
+use Automattic\Jetpack\Status;
+
include_once( 'class.jetpack-admin-page.php' );
// Builds the landing page and its menu
@@ -51,7 +53,7 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
* @since 4.3.0
*/
function jetpack_add_dashboard_sub_nav_item() {
- if ( Jetpack::is_development_mode() || Jetpack::is_active() ) {
+ if ( ( new Status() )->is_development_mode() || Jetpack::is_active() ) {
global $submenu;
if ( current_user_can( 'jetpack_admin_page' ) ) {
$submenu['jetpack'][] = array( __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/dashboard' );
@@ -65,7 +67,7 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
* @since 4.3.0
*/
function jetpack_add_settings_sub_nav_item() {
- if ( ( Jetpack::is_development_mode() || Jetpack::is_active() ) && current_user_can( 'jetpack_admin_page' ) && current_user_can( 'edit_posts' ) ) {
+ if ( ( ( new Status() )->is_development_mode() || Jetpack::is_active() ) && current_user_can( 'jetpack_admin_page' ) && current_user_can( 'edit_posts' ) ) {
global $submenu;
$submenu['jetpack'][] = array( __( 'Settings', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/settings' );
}
@@ -113,6 +115,8 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
// We got the static.html so let's display it
echo $static_html;
+ self::render_footer();
+
}
}
@@ -144,21 +148,26 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
return; // No need for scripts on a fallback page
}
- $script_deps_path = JETPACK__PLUGIN_DIR . '_inc/build/admin.deps.json';
- $script_dependencies = file_exists( $script_deps_path )
- ? json_decode( file_get_contents( $script_deps_path ) )
- : array();
- $script_dependencies[] = 'wp-polyfill';
-
- wp_enqueue_script(
- 'react-plugin',
- plugins_url( '_inc/build/admin.js', JETPACK__PLUGIN_FILE ),
- $script_dependencies,
- JETPACK__VERSION,
- true
- );
+ $is_development_mode = ( new Status() )->is_development_mode();
+ $script_deps_path = JETPACK__PLUGIN_DIR . '_inc/build/admin.asset.php';
+ $script_dependencies = array( 'wp-polyfill' );
+ if ( file_exists( $script_deps_path ) ) {
+ $asset_manifest = include $script_deps_path;
+ $script_dependencies = $asset_manifest['dependencies'];
+ }
+
+ if ( Jetpack::is_active() || $is_development_mode ) {
+ wp_enqueue_script(
+ 'react-plugin',
+ plugins_url( '_inc/build/admin.js', JETPACK__PLUGIN_FILE ),
+ $script_dependencies,
+ JETPACK__VERSION,
+ true
+ );
+ }
+
- if ( ! Jetpack::is_development_mode() && Jetpack::is_active() ) {
+ if ( ! $is_development_mode && Jetpack::is_active() ) {
// Required for Analytics.
wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true );
}
@@ -219,6 +228,8 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
require_once JETPACK__PLUGIN_DIR . 'class.jetpack-affiliate.php';
}
+ $current_user_data = jetpack_current_user_data();
+
return array(
'WP_API_root' => esc_url_raw( rest_url() ),
'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
@@ -227,7 +238,7 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
'isActive' => Jetpack::is_active(),
'isStaging' => Jetpack::is_staging_site(),
'devMode' => array(
- 'isActive' => Jetpack::is_development_mode(),
+ 'isActive' => ( new Status() )->is_development_mode(),
'constant' => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
'url' => site_url() && false === strpos( site_url(), '.' ),
'filter' => apply_filters( 'jetpack_development_mode', false ),
@@ -236,13 +247,12 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
'isInIdentityCrisis' => Jetpack::validate_sync_error_idc_option(),
'sandboxDomain' => JETPACK__SANDBOX_DOMAIN,
),
- 'connectUrl' => Jetpack::init()->build_connect_url( true, false, false ),
+ 'connectUrl' => $current_user_data['isConnected'] == false ? Jetpack::init()->build_connect_url( true, false, false ) : '',
'dismissedNotices' => $this->get_dismissed_jetpack_notices(),
'isDevVersion' => Jetpack::is_development_version(),
'currentVersion' => JETPACK__VERSION,
'is_gutenberg_available' => true,
'getModules' => $modules,
- 'showJumpstart' => jetpack_show_jumpstart(),
'rawUrl' => Jetpack::build_raw_urls( get_home_url() ),
'adminUrl' => esc_url( admin_url() ),
'stats' => array(
@@ -259,13 +269,13 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
'settings' => $this->get_flattened_settings( $modules ),
'userData' => array(
// 'othersLinked' => Jetpack::get_other_linked_admins(),
- 'currentUser' => jetpack_current_user_data(),
+ 'currentUser' => $current_user_data,
),
'siteData' => array(
- 'icon' => has_site_icon()
+ 'icon' => has_site_icon()
? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) )
: '',
- 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ),
+ 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ), // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
/**
* Whether promotions are visible or not.
*
@@ -273,10 +283,11 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
*
* @param bool $are_promotions_active Status of promotions visibility. True by default.
*/
- 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ),
- 'isAtomicSite' => jetpack_is_atomic_site(),
- 'plan' => Jetpack_Plan::get(),
- 'showBackups' => Jetpack::show_backups_ui(),
+ 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ),
+ 'isAtomicSite' => jetpack_is_atomic_site(),
+ 'plan' => Jetpack_Plan::get(),
+ 'showBackups' => Jetpack::show_backups_ui(),
+ 'isMultisite' => is_multisite(),
),
'themeData' => array(
'name' => $current_theme->get( 'Name' ),
@@ -295,7 +306,8 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
'currentIp' => function_exists( 'jetpack_protect_get_ip' ) ? jetpack_protect_get_ip() : false,
'lastPostUrl' => esc_url( $last_post ),
- 'externalServicesConnectUrls' => $this->get_external_services_connect_urls()
+ 'externalServicesConnectUrls' => $this->get_external_services_connect_urls(),
+ 'calypsoEnv' => Jetpack::get_calypso_env(),
);
}
@@ -322,40 +334,6 @@ class Jetpack_React_Page extends Jetpack_Admin_Page {
}
}
-/*
- * Only show Jump Start on first activation.
- * Any option 'jumpstart' other than 'new connection' will hide it.
- *
- * The option can be of 4 things, and will be stored as such:
- * new_connection : Brand new connection - Show
- * jumpstart_activated : Jump Start has been activated - dismiss
- * jumpstart_dismissed : Manual dismissal of Jump Start - dismiss
- * jetpack_action_taken: Deprecated since 7.3 But still listed here to respect behaviour for old versions.
- * Manual activation of a module already happened - dismiss.
- *
- * @todo move to functions.global.php when available
- * @since 3.6
- * @return bool | show or hide
- */
-function jetpack_show_jumpstart() {
- if ( ! Jetpack::is_active() ) {
- return false;
- }
- $jumpstart_option = Jetpack_Options::get_option( 'jumpstart' );
-
- $hide_options = array(
- 'jumpstart_activated',
- 'jetpack_action_taken',
- 'jumpstart_dismissed'
- );
-
- if ( ! $jumpstart_option || in_array( $jumpstart_option, $hide_options ) ) {
- return false;
- }
-
- return true;
-}
-
/**
* Gather data about the current user.
*
diff --git a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php
index 69991c70..551b9f71 100644
--- a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php
+++ b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php
@@ -1,4 +1,8 @@
<?php
+
+use Automattic\Jetpack\Tracking;
+use Automattic\Jetpack\Assets;
+
include_once( 'class.jetpack-admin-page.php' );
include_once( JETPACK__PLUGIN_DIR . 'class.jetpack-modules-list-table.php' );
@@ -117,7 +121,8 @@ class Jetpack_Settings_Page extends Jetpack_Admin_Page {
</div><!-- /.content -->
<?php
- JetpackTracking::record_user_event( 'wpa_page_view', array( 'path' => 'old_settings' ) );
+ $tracking = new Tracking();
+ $tracking->record_user_event( 'wpa_page_view', array( 'path' => 'old_settings' ) );
}
/**
@@ -133,7 +138,7 @@ class Jetpack_Settings_Page extends Jetpack_Admin_Page {
function page_admin_scripts() {
wp_enqueue_script(
'jetpack-admin-js',
- Jetpack::get_file_url_for_environment( '_inc/build/jetpack-admin.min.js', '_inc/jetpack-admin.js' ),
+ Assets::get_file_url_for_environment( '_inc/build/jetpack-admin.min.js', '_inc/jetpack-admin.js' ),
array( 'jquery' ),
JETPACK__VERSION
);
diff --git a/plugins/jetpack/_inc/lib/class.color.php b/plugins/jetpack/_inc/lib/class.color.php
index a57f2009..e145298c 100644
--- a/plugins/jetpack/_inc/lib/class.color.php
+++ b/plugins/jetpack/_inc/lib/class.color.php
@@ -9,7 +9,7 @@
*
* @author Harold Asbridge <hasbridge@gmail.com>
* @author Matt Wiebe <wiebe@automattic.com>
- * @license http://www.opensource.org/licenses/MIT
+ * @license https://www.opensource.org/licenses/MIT
*/
class Jetpack_Color {
@@ -125,7 +125,7 @@ class Jetpack_Color {
/**
* Converts an HSL color value to RGB. Conversion formula
- * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
+ * adapted from https://en.wikipedia.org/wiki/HSL_color_space.
* @param int $h Hue. [0-360]
* @param in $s Saturation [0, 100]
* @param int $l Lightness [0, 100]
@@ -321,13 +321,13 @@ class Jetpack_Color {
}
/**
- * Converts an RGB color value to HSL. Conversion formula
- * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
- * Assumes r, g, and b are contained in the set [0, 255] and
- * returns h in [0, 360], s in [0, 100], l in [0, 100]
- *
- * @return Array The HSL representation
- */
+ * Converts an RGB color value to HSL. Conversion formula
+ * adapted from https://en.wikipedia.org/wiki/HSL_color_space.
+ * Assumes r, g, and b are contained in the set [0, 255] and
+ * returns h in [0, 360], s in [0, 100], l in [0, 100]
+ *
+ * @return Array The HSL representation
+ */
public function toHsl() {
list( $r, $g, $b ) = array_values( $this->toRgbInt() );
$r /= 255; $g /= 255; $b /= 255;
diff --git a/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php b/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php
index a0f0bf44..30a53865 100644
--- a/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php
+++ b/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php
@@ -1,4 +1,11 @@
<?php
+
+use Automattic\Jetpack\Connection\Client;
+use Automattic\Jetpack\Connection\Manager as Connection_Manager;
+use Automattic\Jetpack\JITM;
+use Automattic\Jetpack\Tracking;
+use Automattic\Jetpack\Status;
+
/**
* Register WP REST API endpoints for Jetpack.
*
@@ -61,7 +68,6 @@ class Jetpack_Core_Json_Api_Endpoints {
self::$stats_roles = array( 'administrator', 'editor', 'author', 'contributor', 'subscriber' );
- Jetpack::load_xml_rpc_client();
$ixr_client = new Jetpack_IXR_Client( array( 'user_id' => get_current_user_id() ) );
$core_api_endpoint = new Jetpack_Core_API_Data( $ixr_client );
$module_list_endpoint = new Jetpack_Core_API_Module_List_Endpoint();
@@ -74,7 +80,18 @@ class Jetpack_Core_Json_Api_Endpoints {
'methods' => WP_REST_Server::READABLE,
'callback' => __CLASS__ . '::get_plans',
'permission_callback' => __CLASS__ . '::connect_url_permission_callback',
+ ) );
+ register_rest_route( 'jetpack/v4', 'products', array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => __CLASS__ . '::get_products',
+ 'permission_callback' => __CLASS__ . '::connect_url_permission_callback',
+ ) );
+
+ register_rest_route( 'jetpack/v4', 'marketing/survey', array(
+ 'methods' => WP_REST_Server::CREATABLE,
+ 'callback' => __CLASS__ . '::submit_survey',
+ 'permission_callback' => __CLASS__ . '::disconnect_site_permission_callback',
) );
register_rest_route( 'jetpack/v4', '/jitm', array(
@@ -87,12 +104,6 @@ class Jetpack_Core_Json_Api_Endpoints {
'callback' => __CLASS__ . '::delete_jitm_message'
) );
- // Register a site
- register_rest_route( 'jetpack/v4', '/verify_registration', array(
- 'methods' => WP_REST_Server::EDITABLE,
- 'callback' => __CLASS__ . '::verify_registration',
- ) );
-
// Authorize a remote user
register_rest_route( 'jetpack/v4', '/remote_authorize', array(
'methods' => WP_REST_Server::EDITABLE,
@@ -139,6 +150,16 @@ class Jetpack_Core_Json_Api_Endpoints {
'permission_callback' => __CLASS__ . '::get_user_connection_data_permission_callback',
) );
+ // Start the connection process by registering the site on WordPress.com servers.
+ register_rest_route( 'jetpack/v4', '/connection/register', array(
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => __CLASS__ . '::register_site',
+ 'permission_callback' => __CLASS__ . '::connect_url_permission_callback',
+ 'args' => array(
+ 'registration_nonce' => array( 'type' => 'string' ),
+ ),
+ ) );
+
// Set the connection owner
register_rest_route( 'jetpack/v4', '/connection/owner', array(
'methods' => WP_REST_Server::EDITABLE,
@@ -191,6 +212,31 @@ class Jetpack_Core_Json_Api_Endpoints {
'permission_callback' => array( $site_endpoint , 'can_request' ),
) );
+ // Get current site purchases.
+ register_rest_route(
+ 'jetpack/v4',
+ '/site/purchases',
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $site_endpoint, 'get_purchases' ),
+ 'permission_callback' => array( $site_endpoint, 'can_request' ),
+ )
+ );
+
+ // Get current site benefits
+ register_rest_route( 'jetpack/v4', '/site/benefits', array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $site_endpoint, 'get_benefits' ),
+ 'permission_callback' => array( $site_endpoint, 'can_request' ),
+ ) );
+
+ // Get Activity Log data for this site.
+ register_rest_route( 'jetpack/v4', '/site/activity', array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => __CLASS__ . '::get_site_activity',
+ 'permission_callback' => __CLASS__ . '::manage_modules_permission_check',
+ ) );
+
// Confirm that a site in identity crisis should be in staging mode
register_rest_route( 'jetpack/v4', '/identity-crisis/confirm-safe-mode', array(
'methods' => WP_REST_Server::EDITABLE,
@@ -341,26 +387,6 @@ class Jetpack_Core_Json_Api_Endpoints {
'permission_callback' => __CLASS__ . '::manage_modules_permission_check',
) );
- // Return current Jumpstart status
- register_rest_route( 'jetpack/v4', '/jumpstart', array(
- 'methods' => WP_REST_Server::READABLE,
- 'callback' => __CLASS__ . '::jumpstart_status',
- 'permission_callback' => __CLASS__ . '::update_settings_permission_check',
- ) );
-
- // Update Jumpstart
- register_rest_route( 'jetpack/v4', '/jumpstart', array(
- 'methods' => WP_REST_Server::EDITABLE,
- 'callback' => __CLASS__ . '::jumpstart_toggle',
- 'permission_callback' => __CLASS__ . '::manage_modules_permission_check',
- 'args' => array(
- 'active' => array(
- 'required' => true,
- 'validate_callback' => __CLASS__ . '::validate_boolean',
- ),
- ),
- ) );
-
// Updates: get number of plugin updates available
register_rest_route( 'jetpack/v4', '/updates/plugins', array(
'methods' => WP_REST_Server::READABLE,
@@ -382,6 +408,12 @@ class Jetpack_Core_Json_Api_Endpoints {
'permission_callback' => __CLASS__ . '::activate_plugins_permission_check',
) );
+ register_rest_route( 'jetpack/v4', '/plugins/akismet/activate', array(
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => __CLASS__ . '::activate_akismet',
+ 'permission_callback' => __CLASS__ . '::activate_plugins_permission_check',
+ ) );
+
// Plugins: check if the plugin is active.
register_rest_route( 'jetpack/v4', '/plugin/(?P<plugin>[a-z\/\.\-_]+)', array(
'methods' => WP_REST_Server::READABLE,
@@ -452,10 +484,20 @@ class Jetpack_Core_Json_Api_Endpoints {
),
)
);
+
+ register_rest_route(
+ 'jetpack/v4',
+ '/mobile/send-login-email',
+ array(
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => __CLASS__ . '::send_mobile_magic_link',
+ 'permission_callback' => __CLASS__ . '::view_admin_page_permission_check',
+ )
+ );
}
public static function get_plans( $request ) {
- $request = Jetpack_Client::wpcom_json_api_request_as_user(
+ $request = Client::wpcom_json_api_request_as_user(
'/plans?_locale=' . get_user_locale(),
'2',
array(
@@ -466,7 +508,7 @@ class Jetpack_Core_Json_Api_Endpoints {
)
);
- $body = wp_remote_retrieve_body( $request );
+ $body = json_decode( wp_remote_retrieve_body( $request ) );
if ( 200 === wp_remote_retrieve_response_code( $request ) ) {
$data = $body;
} else {
@@ -478,6 +520,65 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
+ * Gets the WP.com products that are in use on wpcom.
+ * Similar to the WP.com plans that we currently in user on WPCOM.
+ *
+ * @param WP_REST_Request $request The request.
+ *
+ * @return string|WP_Error A JSON object of wpcom products if the request was successful, or a WP_Error otherwise.
+ */
+ public static function get_products( $request ) {
+ $wpcom_request = Client::wpcom_json_api_request_as_user(
+ '/products?_locale=' . get_user_locale() . '&type=jetpack',
+ '2',
+ array(
+ 'method' => 'GET',
+ 'headers' => array(
+ 'X-Forwarded-For' => Jetpack::current_user_ip( true ),
+ ),
+ )
+ );
+
+ $response_code = wp_remote_retrieve_response_code( $wpcom_request );
+ if ( 200 === $response_code ) {
+ return json_decode( wp_remote_retrieve_body( $wpcom_request ) );
+ } else {
+ // Something went wrong so we'll just return the response without caching.
+ return new WP_Error(
+ 'failed_to_fetch_data',
+ esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
+ array( 'status' => $response_code )
+ );
+ }
+ }
+
+ public static function submit_survey( $request ) {
+
+ $wpcom_request = Client::wpcom_json_api_request_as_user(
+ '/marketing/survey',
+ 'v2',
+ array(
+ 'method' => 'POST',
+ 'headers' => array(
+ 'Content-Type' => 'application/json',
+ 'X-Forwarded-For' => Jetpack::current_user_ip( true ),
+ ),
+ ),
+ $request->get_json_params()
+ );
+
+ $wpcom_request_body = json_decode( wp_remote_retrieve_body( $wpcom_request ) );
+ if ( 200 === wp_remote_retrieve_response_code( $wpcom_request ) ) {
+ $data = $wpcom_request_body;
+ } else {
+ // something went wrong so we'll just return the response without caching
+ return $wpcom_request_body;
+ }
+
+ return $data;
+ }
+
+ /**
* Asks for a jitm, unless they've been disabled, in which case it returns an empty array
*
* @param $request WP_REST_Request
@@ -485,11 +586,9 @@ class Jetpack_Core_Json_Api_Endpoints {
* @return array An array of jitms
*/
public static function get_jitm_message( $request ) {
- require_once( JETPACK__PLUGIN_DIR . 'class.jetpack-jitm.php' );
-
- $jitm = Jetpack_JITM::init();
+ $jitm = new JITM();
- if ( ! $jitm ) {
+ if ( ! $jitm->register() ) {
return array();
}
@@ -503,11 +602,9 @@ class Jetpack_Core_Json_Api_Endpoints {
* @return bool Always True
*/
public static function delete_jitm_message( $request ) {
- require_once( JETPACK__PLUGIN_DIR . 'class.jetpack-jitm.php' );
+ $jitm = new JITM();
- $jitm = Jetpack_JITM::init();
-
- if ( ! $jitm ) {
+ if ( ! $jitm->register() ) {
return true;
}
@@ -515,28 +612,6 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
- * Handles verification that a site is registered
- *
- * @since 5.4.0
- *
- * @param WP_REST_Request $request The request sent to the WP REST API.
- *
- * @return array|wp-error
- */
- public static function verify_registration( $request ) {
- require_once JETPACK__PLUGIN_DIR . 'class.jetpack-xmlrpc-server.php';
- $xmlrpc_server = new Jetpack_XMLRPC_Server();
- $result = $xmlrpc_server->verify_registration( array( $request['secret_1'], $request['state'] ) );
-
- if ( is_a( $result, 'IXR_Error' ) ) {
- $result = new WP_Error( $result->code, $result->message );
- }
-
- return $result;
- }
-
-
- /**
* Checks if this site has been verified using a service - only 'google' supported at present - and a specfic
* keyring to use to get the token if it is not
*
@@ -586,7 +661,6 @@ class Jetpack_Core_Json_Api_Endpoints {
return new WP_Error( 'forbidden', __( 'Site is under construction and cannot be verified', 'jetpack' ) );
}
- Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => get_current_user_id(),
) );
@@ -612,7 +686,6 @@ class Jetpack_Core_Json_Api_Endpoints {
public static function verify_site( $request ) {
- Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => get_current_user_id(),
) );
@@ -651,7 +724,6 @@ class Jetpack_Core_Json_Api_Endpoints {
* @return array|wp-error
*/
public static function remote_authorize( $request ) {
- require_once JETPACK__PLUGIN_DIR . 'class.jetpack-xmlrpc-server.php';
$xmlrpc_server = new Jetpack_XMLRPC_Server();
$result = $xmlrpc_server->remote_authorize( $request );
@@ -723,7 +795,7 @@ class Jetpack_Core_Json_Api_Endpoints {
return true;
}
- return new WP_Error( 'invalid_user_permission_jetpack_disconnect', self::$user_permissions_error_msg, array( 'status' => self::rest_authorization_required_code() ) );
+ return new WP_Error( 'invalid_user_permission_jetpack_connect', self::$user_permissions_error_msg, array( 'status' => self::rest_authorization_required_code() ) );
}
@@ -749,11 +821,12 @@ class Jetpack_Core_Json_Api_Endpoints {
* Check that user has permission to change the master user.
*
* @since 6.2.0
+ * @since 7.7.0 Update so that any user with jetpack_disconnect privs can set owner.
*
* @return bool|WP_Error True if user is able to change master user.
*/
public static function set_connection_owner_permission_callback() {
- if ( get_current_user_id() === Jetpack_Options::get_option( 'master_user' ) ) {
+ if ( current_user_can( 'jetpack_disconnect' ) ) {
return true;
}
@@ -903,10 +976,11 @@ class Jetpack_Core_Json_Api_Endpoints {
*/
public static function jetpack_connection_status() {
return rest_ensure_response( array(
- 'isActive' => Jetpack::is_active(),
- 'isStaging' => Jetpack::is_staging_site(),
- 'devMode' => array(
- 'isActive' => Jetpack::is_development_mode(),
+ 'isActive' => Jetpack::is_active(),
+ 'isStaging' => Jetpack::is_staging_site(),
+ 'isRegistered' => Jetpack::connection()->is_registered(),
+ 'devMode' => array(
+ 'isActive' => ( new Status() )->is_development_mode(),
'constant' => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
'url' => site_url() && false === strpos( site_url(), '.' ),
'filter' => apply_filters( 'jetpack_development_mode', false ),
@@ -1050,7 +1124,7 @@ class Jetpack_Core_Json_Api_Endpoints {
return new WP_Error( 'site_id_missing' );
}
- $response = Jetpack_Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d/rewind', $site_id ) .'?force=wpcom', '2', array(), null, 'wpcom' );
+ $response = Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d/rewind', $site_id ) .'?force=wpcom', '2', array(), null, 'wpcom' );
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
return new WP_Error( 'rewind_data_fetch_failed' );
@@ -1120,6 +1194,33 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
+ * Registers the Jetpack site
+ *
+ * @uses Jetpack::try_registration();
+ * @since 7.7.0
+ *
+ * @param WP_REST_Request $request The request sent to the WP REST API.
+ *
+ * @return bool|WP_Error True if Jetpack successfully registered
+ */
+ public static function register_site( $request ) {
+ if ( ! wp_verify_nonce( $request->get_param( 'registration_nonce' ), 'jetpack-registration-nonce' ) ) {
+ return new WP_Error( 'invalid_nonce', __( 'Unable to verify your request.', 'jetpack' ), array( 'status' => 403 ) );
+ }
+
+ $response = Jetpack::try_registration();
+
+ if ( is_wp_error( $response ) ) {
+ return $response;
+ }
+
+ return rest_ensure_response(
+ array(
+ 'authorizeUrl' => Jetpack::build_authorize_url( false, true )
+ ) );
+ }
+
+ /**
* Gets a new connect raw URL with fresh nonce.
*
* @uses Jetpack::disconnect();
@@ -1206,7 +1307,6 @@ class Jetpack_Core_Json_Api_Endpoints {
$updated = Jetpack_Options::update_option( 'master_user', $new_owner_id );
// Notify WPCOM about the master user change
- Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client( array(
'user_id' => get_current_user_id(),
) );
@@ -1215,6 +1315,13 @@ class Jetpack_Core_Json_Api_Endpoints {
) );
if ( $updated && ! $xml->isError() ) {
+
+ // Track it
+ if ( class_exists( 'Automattic\Jetpack\Tracking' ) ) {
+ $tracking = new Tracking();
+ $tracking->record_user_event( 'set_connection_owner_success' );
+ }
+
return rest_ensure_response(
array(
'code' => 'success',
@@ -1232,7 +1339,7 @@ class Jetpack_Core_Json_Api_Endpoints {
* Unlinks current user from the WordPress.com Servers.
*
* @since 4.3.0
- * @uses Jetpack::unlink_user
+ * @uses Automattic\Jetpack\Connection\Manager::disconnect_user
*
* @param WP_REST_Request $request The request sent to the WP REST API.
*
@@ -1244,7 +1351,7 @@ class Jetpack_Core_Json_Api_Endpoints {
return new WP_Error( 'invalid_param', esc_html__( 'Invalid Parameter', 'jetpack' ), array( 'status' => 404 ) );
}
- if ( Jetpack::unlink_user() ) {
+ if ( Connection_Manager::disconnect_user() ) {
return rest_ensure_response(
array(
'code' => 'success'
@@ -1270,7 +1377,7 @@ class Jetpack_Core_Json_Api_Endpoints {
'tracks_opt_out' => true, // Default to opt-out if not connected to wp.com.
);
} else {
- $response = Jetpack_Client::wpcom_json_api_request_as_user(
+ $response = Client::wpcom_json_api_request_as_user(
'/jetpack-user-tracking',
'v2',
array(
@@ -1303,7 +1410,7 @@ class Jetpack_Core_Json_Api_Endpoints {
'tracks_opt_out' => true, // Default to opt-out if not connected to wp.com.
);
} else {
- $response = Jetpack_Client::wpcom_json_api_request_as_user(
+ $response = Client::wpcom_json_api_request_as_user(
'/jetpack-user-tracking',
'v2',
array(
@@ -1334,10 +1441,18 @@ class Jetpack_Core_Json_Api_Endpoints {
$site_id = Jetpack_Options::get_option( 'id' );
if ( ! $site_id ) {
- new WP_Error( 'site_id_missing' );
+ new WP_Error( 'site_id_missing' );
+ }
+
+ $args = array( 'headers' => array() );
+
+ // Allow use a store sandbox. Internal ref: PCYsg-IA-p2.
+ if ( isset( $_COOKIE ) && isset( $_COOKIE['store_sandbox'] ) ) {
+ $secret = $_COOKIE['store_sandbox'];
+ $args['headers']['Cookie'] = "store_sandbox=$secret;";
}
- $response = Jetpack_Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d', $site_id ) .'?force=wpcom', '1.1' );
+ $response = Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d', $site_id ) .'?force=wpcom', '1.1', $args );
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
return new WP_Error( 'site_data_fetch_failed' );
@@ -1377,6 +1492,57 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
+ * Fetch AL data for this site and return it.
+ *
+ * @since 7.4
+ *
+ * @return array|WP_Error
+ */
+ public static function get_site_activity() {
+ $site_id = Jetpack_Options::get_option( 'id' );
+
+ if ( ! $site_id ) {
+ return new WP_Error(
+ 'site_id_missing',
+ esc_html__( 'Site ID is missing.', 'jetpack' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $response = Client::wpcom_json_api_request_as_user( "/sites/$site_id/activity", '2', array(
+ 'method' => 'GET',
+ 'headers' => array(
+ 'X-Forwarded-For' => Jetpack::current_user_ip( true ),
+ ),
+ ), null, 'wpcom' );
+ $response_code = wp_remote_retrieve_response_code( $response );
+
+ if ( 200 !== $response_code ) {
+ return new WP_Error(
+ 'activity_fetch_failed',
+ esc_html__( 'Could not retrieve site activity.', 'jetpack' ),
+ array( 'status' => $response_code )
+ );
+ }
+
+ $data = json_decode( wp_remote_retrieve_body( $response ) );
+
+ if ( ! isset( $data->current->orderedItems ) ) {
+ return new WP_Error(
+ 'activity_not_found',
+ esc_html__( 'No activity found', 'jetpack' ),
+ array( 'status' => 204 ) // no content
+ );
+ }
+
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'data' => $data->current->orderedItems,
+ )
+ );
+ }
+
+ /**
* Handles identity crisis mitigation, confirming safe mode for this site.
*
* @since 4.4.0
@@ -1484,8 +1650,6 @@ class Jetpack_Core_Json_Api_Endpoints {
$default_modules = Jetpack::get_default_modules();
Jetpack::update_active_modules( $default_modules );
- // Jumpstart option is special
- Jetpack_Options::update_option( 'jumpstart', 'new_connection' );
return rest_ensure_response( array(
'code' => 'success',
'message' => esc_html__( 'Jetpack options reset.', 'jetpack' ),
@@ -1510,148 +1674,6 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
- * Retrieves the current status of Jumpstart.
- *
- * @since 4.5.0
- *
- * @return bool
- */
- public static function jumpstart_status() {
- return array(
- 'status' => Jetpack_Options::get_option( 'jumpstart' )
- );
- }
-
- /**
- * Toggles activation or deactivation of the JumpStart
- *
- * @since 4.3.0
- *
- * @param WP_REST_Request $request The request sent to the WP REST API.
- *
- * @return bool|WP_Error True if toggling Jumpstart succeeded. Otherwise, a WP_Error instance with the corresponding error.
- */
- public static function jumpstart_toggle( $request ) {
-
- if ( $request[ 'active' ] ) {
- return self::jumpstart_activate( $request );
- } else {
- return self::jumpstart_deactivate( $request );
- }
- }
-
- /**
- * Activates a series of valid Jetpack modules and initializes some options.
- *
- * @since 4.3.0
- *
- * @param WP_REST_Request $request The request sent to the WP REST API.
- *
- * @return bool|WP_Error True if Jumpstart succeeded. Otherwise, a WP_Error instance with the corresponding error.
- */
- public static function jumpstart_activate( $request ) {
- $modules = Jetpack::get_available_modules();
- $activate_modules = array();
- foreach ( $modules as $module ) {
- $module_info = Jetpack::get_module( $module );
- if ( isset( $module_info['feature'] ) && is_array( $module_info['feature'] ) && in_array( 'Jumpstart', $module_info['feature'] ) ) {
- $activate_modules[] = $module;
- }
- }
-
- // Collect success/error messages like modules that are properly activated.
- $result = array(
- 'activated_modules' => array(),
- 'failed_modules' => array(),
- );
-
- // Update the jumpstart option
- if ( 'new_connection' === Jetpack_Options::get_option( 'jumpstart' ) ) {
- $result['jumpstart_activated'] = Jetpack_Options::update_option( 'jumpstart', 'jumpstart_activated' );
- }
-
- // Check for possible conflicting plugins
- $module_slugs_filtered = Jetpack::init()->filter_default_modules( $activate_modules );
-
- foreach ( $module_slugs_filtered as $module_slug ) {
- Jetpack::log( 'activate', $module_slug );
- if ( Jetpack::activate_module( $module_slug, false, false ) ) {
- $result['activated_modules'][] = $module_slug;
- } else {
- $result['failed_modules'][] = $module_slug;
- }
- }
-
- // Set the default sharing buttons and set to display on posts if none have been set.
- $sharing_services = get_option( 'sharing-services' );
- $sharing_options = get_option( 'sharing-options' );
- if ( empty( $sharing_services['visible'] ) ) {
- // Default buttons to set
- $visible = array(
- 'twitter',
- 'facebook',
- );
- $hidden = array();
-
- // Set some sharing settings
- if ( class_exists( 'Sharing_Service' ) ) {
- $sharing = new Sharing_Service();
- $sharing_options['global'] = array(
- 'button_style' => 'icon',
- 'sharing_label' => $sharing->default_sharing_label,
- 'open_links' => 'same',
- 'show' => array( 'post' ),
- 'custom' => isset( $sharing_options['global']['custom'] ) ? $sharing_options['global']['custom'] : array()
- );
-
- $result['sharing_options'] = update_option( 'sharing-options', $sharing_options );
- $result['sharing_services'] = update_option( 'sharing-services', array( 'visible' => $visible, 'hidden' => $hidden ) );
- }
- }
-
- // If all Jumpstart modules were activated
- if ( empty( $result['failed_modules'] ) ) {
- return rest_ensure_response( array(
- 'code' => 'success',
- 'message' => esc_html__( 'Jumpstart done.', 'jetpack' ),
- 'data' => $result,
- ) );
- }
-
- return new WP_Error( 'jumpstart_failed', esc_html( sprintf( _n( 'Jumpstart failed activating this module: %s.', 'Jumpstart failed activating these modules: %s.', count( $result['failed_modules'] ), 'jetpack' ), join( ', ', $result['failed_modules'] ) ) ), array( 'status' => 400 ) );
- }
-
- /**
- * Dismisses Jumpstart so user is not prompted to go through it again.
- *
- * @since 4.3.0
- *
- * @param WP_REST_Request $request The request sent to the WP REST API.
- *
- * @return bool|WP_Error True if Jumpstart was disabled or was nothing to dismiss. Otherwise, a WP_Error instance with a message.
- */
- public static function jumpstart_deactivate( $request ) {
-
- // If dismissed, flag the jumpstart option as such.
- if ( 'new_connection' === Jetpack_Options::get_option( 'jumpstart' ) ) {
- if ( Jetpack_Options::update_option( 'jumpstart', 'jumpstart_dismissed' ) ) {
- return rest_ensure_response( array(
- 'code' => 'success',
- 'message' => esc_html__( 'Jumpstart dismissed.', 'jetpack' ),
- ) );
- } else {
- return new WP_Error( 'jumpstart_failed_dismiss', esc_html__( 'Jumpstart could not be dismissed.', 'jetpack' ), array( 'status' => 400 ) );
- }
- }
-
- // If this was not a new connection and there was nothing to dismiss, don't fail.
- return rest_ensure_response( array(
- 'code' => 'success',
- 'message' => esc_html__( 'Nothing to dismiss. This was not a new connection.', 'jetpack' ),
- ) );
- }
-
- /**
* Get the query parameters to update module options or general settings.
*
* @since 4.3.0
@@ -1705,7 +1727,7 @@ class Jetpack_Core_Json_Api_Endpoints {
'jp_group' => 'carousel',
),
'carousel_display_exif' => array(
- 'description' => wp_kses( sprintf( __( 'Show photo metadata (<a href="http://en.wikipedia.org/wiki/Exchangeable_image_file_format" target="_blank">Exif</a>) in carousel, when available.', 'jetpack' ) ), array( 'a' => array( 'href' => true, 'target' => true ) ) ),
+ 'description' => wp_kses( sprintf( __( 'Show photo metadata (<a href="https://en.wikipedia.org/wiki/Exchangeable_image_file_format" target="_blank">Exif</a>) in carousel, when available.', 'jetpack' ) ), array( 'a' => array( 'href' => true, 'target' => true ) ) ),
'type' => 'boolean',
'default' => 0,
'validate_callback' => __CLASS__ . '::validate_boolean',
@@ -2149,7 +2171,7 @@ class Jetpack_Core_Json_Api_Endpoints {
// Stats
'admin_bar' => array(
- 'description' => esc_html__( 'Put a chart showing 48 hours of views in the admin bar.', 'jetpack' ),
+ 'description' => esc_html__( 'Include a small chart in your admin bar with a 48-hour traffic snapshot.', 'jetpack' ),
'type' => 'boolean',
'default' => 1,
'validate_callback' => __CLASS__ . '::validate_boolean',
@@ -3156,6 +3178,30 @@ class Jetpack_Core_Json_Api_Endpoints {
}
/**
+ * Ensures that Akismet is installed and activated.
+ *
+ * @since 7.7
+ *
+ * @return WP_REST_Response A response indicating whether or not the installation was successful.
+ */
+ public static function activate_akismet() {
+ jetpack_require_lib( 'plugins' );
+ $result = Jetpack_Plugins::install_and_activate_plugin('akismet');
+
+ if ( is_wp_error( $result ) ) {
+ return rest_ensure_response( array(
+ 'code' => 'failure',
+ 'message' => esc_html__( 'Unable to activate Akismet', 'jetpack' )
+ ) );
+ } else {
+ return rest_ensure_response( array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'Activated Akismet', 'jetpack' )
+ ) );
+ }
+ }
+
+ /**
* Get data about the queried plugin. Currently it only returns whether the plugin is active or not.
*
* @since 4.2.0
@@ -3193,4 +3239,38 @@ class Jetpack_Core_Json_Api_Endpoints {
) );
}
+ /**
+ * Proxies a request to WordPress.com to request that a magic link be sent to the current user
+ * to log this user in to the mobile app via email.
+ *
+ * @param WP_REST_REQUEST $request The request parameters.
+ * @return bool|WP_Error
+ */
+ public static function send_mobile_magic_link( $request ) {
+ $xml = new Jetpack_IXR_Client(
+ array(
+ 'user_id' => get_current_user_id(),
+ )
+ );
+
+ $xml->query( 'jetpack.sendMobileMagicLink', array() );
+ if ( $xml->isError() ) {
+ return new WP_Error(
+ 'error_sending_mobile_magic_link',
+ sprintf(
+ '%s: %s',
+ $xml->getErrorCode(),
+ $xml->getErrorMessage()
+ )
+ );
+ }
+
+ $response = $xml->getResponse();
+
+ return rest_ensure_response(
+ array(
+ 'code' => 'success',
+ )
+ );
+ }
} // class end
diff --git a/plugins/jetpack/_inc/lib/class.jetpack-automatic-install-skin.php b/plugins/jetpack/_inc/lib/class.jetpack-automatic-install-skin.php
index 228c6b2c..00afeb01 100644
--- a/plugins/jetpack/_inc/lib/class.jetpack-automatic-install-skin.php
+++ b/plugins/jetpack/_inc/lib/class.jetpack-automatic-install-skin.php
@@ -65,8 +65,11 @@ class Jetpack_Automatic_Install_Skin extends Automatic_Upgrader_Skin {
/**
* Overwrites the feedback function
+ *
+ * @param string|array|WP_Error $data Data.
+ * @param mixed ...$args Optional text replacements.
*/
- public function feedback( $data ) {
+ public function feedback( $data, ...$args ) {
$current_error = null;
if ( is_wp_error( $data ) ) {
@@ -86,8 +89,6 @@ class Jetpack_Automatic_Install_Skin extends Automatic_Upgrader_Skin {
}
if ( strpos( $string, '%' ) !== false ) {
- $args = func_get_args();
- $args = array_splice( $args, 1 );
if ( ! empty( $args ) ) {
$string = vsprintf( $string, $args );
}
diff --git a/plugins/jetpack/_inc/lib/class.jetpack-keyring-service-helper.php b/plugins/jetpack/_inc/lib/class.jetpack-keyring-service-helper.php
index c8005ea1..720f59a9 100644
--- a/plugins/jetpack/_inc/lib/class.jetpack-keyring-service-helper.php
+++ b/plugins/jetpack/_inc/lib/class.jetpack-keyring-service-helper.php
@@ -38,16 +38,43 @@ class Jetpack_Keyring_Service_Helper {
)
);
+ /**
+ * Constructor
+ */
private function __construct() {
+ add_action( 'admin_menu', array( __CLASS__, 'add_sharing_menu' ), 21 );
+
add_action( 'load-settings_page_sharing', array( __CLASS__, 'admin_page_load' ), 9 );
}
- function get_services( $filter = 'all' ) {
- $services = array(
+ /**
+ * We need a `sharing` submenu page to be able to connect and disconnect services.
+ */
+ public static function add_sharing_menu() {
+ global $submenu;
+
+ if (
+ ! isset( $submenu['options-general.php'] )
+ || ! is_array( $submenu['options-general.php'] )
+ ) {
+ return;
+ }
+ $general_settings_names = array_map(
+ function ( $menu ) {
+ return array_values( $menu )[0];
+ },
+ $submenu['options-general.php']
);
+ if ( ! in_array( 'Sharing', $general_settings_names, true ) ) {
+ add_submenu_page( 'options-general.php', '', '', 'manage_options', 'sharing', '__return_empty_string' );
+ }
+ }
+
+ function get_services( $filter = 'all' ) {
+ $services = array();
- if ( 'all' == $filter ) {
+ if ( 'all' === $filter ) {
return $services;
} else {
$connected_services = array();
@@ -161,7 +188,6 @@ class Jetpack_Keyring_Service_Helper {
break;
case 'completed':
- Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client();
$xml->query( 'jetpack.fetchPublicizeConnections' );
@@ -190,7 +216,6 @@ class Jetpack_Keyring_Service_Helper {
* Remove a Publicize connection
*/
static function disconnect( $service_name, $connection_id, $_blog_id = false, $_user_id = false, $force_delete = false ) {
- Jetpack::load_xml_rpc_client();
$xml = new Jetpack_IXR_Client();
$xml->query( 'jetpack.deletePublicizeConnection', $connection_id );
diff --git a/plugins/jetpack/_inc/lib/class.jetpack-password-checker.php b/plugins/jetpack/_inc/lib/class.jetpack-password-checker.php
index 14de6053..01b9c61c 100644
--- a/plugins/jetpack/_inc/lib/class.jetpack-password-checker.php
+++ b/plugins/jetpack/_inc/lib/class.jetpack-password-checker.php
@@ -518,7 +518,7 @@ class Jetpack_Password_Checker {
* L = String length (the for iterator)
* N = Our charset size, via get_charset_size()
*
- * @see http://en.wikipedia.org/wiki/Password_strength#Random_passwords
+ * @see https://en.wikipedia.org/wiki/Password_strength#Random_passwords
*
* On top of the base formula, we're also multiplying the bits of entropy for every char
* by 1 - (the probabily of it following the previous char)
diff --git a/plugins/jetpack/_inc/lib/class.media-extractor.php b/plugins/jetpack/_inc/lib/class.media-extractor.php
index 6acf34db..ba00ff97 100644
--- a/plugins/jetpack/_inc/lib/class.media-extractor.php
+++ b/plugins/jetpack/_inc/lib/class.media-extractor.php
@@ -206,7 +206,7 @@ class Jetpack_Media_Meta_Extractor {
if ( preg_match_all( '#(?:^|\s|"|\')(https?://([^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/))))#', $content, $matches ) ) {
foreach ( $matches[1] as $link_raw ) {
- $url = parse_url( $link_raw );
+ $url = wp_parse_url( $link_raw );
// Data URI links
if ( isset( $url['scheme'] ) && 'data' === $url['scheme'] )
@@ -286,7 +286,7 @@ class Jetpack_Media_Meta_Extractor {
$embeds = array();
foreach ( $matches[1] as $link_raw ) {
- $url = parse_url( $link_raw );
+ $url = wp_parse_url( $link_raw );
list( $proto, $link_all_but_proto ) = explode( '://', $link_raw );
@@ -402,11 +402,11 @@ class Jetpack_Media_Meta_Extractor {
if ( !empty( $from_html ) ) {
$srcs = wp_list_pluck( $from_html, 'src' );
foreach( $srcs as $image_url ) {
- if ( ( $src = parse_url( $image_url ) ) && isset( $src['scheme'], $src['host'], $src['path'] ) ) {
+ if ( ( $src = wp_parse_url( $image_url ) ) && isset( $src['scheme'], $src['host'], $src['path'] ) ) {
// Rebuild the URL without the query string
$queryless = $src['scheme'] . '://' . $src['host'] . $src['path'];
} elseif ( $length = strpos( $image_url, '?' ) ) {
- // If parse_url() didn't work, strip off the query string the old fashioned way
+ // If wp_parse_url() didn't work, strip off the query string the old fashioned way
$queryless = substr( $image_url, 0, $length );
} else {
// Failing that, there was no spoon! Err ... query string!
diff --git a/plugins/jetpack/_inc/lib/class.media-summary.php b/plugins/jetpack/_inc/lib/class.media-summary.php
index 732706d4..6d5f2d48 100644
--- a/plugins/jetpack/_inc/lib/class.media-summary.php
+++ b/plugins/jetpack/_inc/lib/class.media-summary.php
@@ -131,7 +131,7 @@ class Jetpack_Media_Summary {
$poster_image = get_post_meta( $post_id, 'vimeo_poster_image', true );
if ( !empty( $poster_image ) ) {
$return['image'] = $poster_image;
- $poster_url_parts = parse_url( $poster_image );
+ $poster_url_parts = wp_parse_url( $poster_image );
$return['secure']['image'] = 'https://secure-a.vimeocdn.com' . $poster_url_parts['path'];
}
}
@@ -162,12 +162,12 @@ class Jetpack_Media_Summary {
$poster_image = get_post_meta( $post_id, 'vimeo_poster_image', true );
if ( !empty( $poster_image ) ) {
$return['image'] = $poster_image;
- $poster_url_parts = parse_url( $poster_image );
+ $poster_url_parts = wp_parse_url( $poster_image );
$return['secure']['image'] = 'https://secure-a.vimeocdn.com' . $poster_url_parts['path'];
}
} else if ( false !== strpos( $embed, 'dailymotion' ) ) {
$return['image'] = str_replace( 'dailymotion.com/video/','dailymotion.com/thumbnail/video/', $embed );
- $return['image'] = parse_url( $return['image'], PHP_URL_SCHEME ) === null ? 'http://' . $return['image'] : $return['image'];
+ $return['image'] = wp_parse_url( $return['image'], PHP_URL_SCHEME ) === null ? 'http://' . $return['image'] : $return['image'];
$return['secure']['image'] = self::https( $return['image'] );
}
@@ -348,8 +348,8 @@ class Jetpack_Media_Summary {
static function split_content_in_words( $text ) {
$words = preg_split( '/[\s!?;,.]+/', $text, null, PREG_SPLIT_NO_EMPTY );
- // Return an empty array if the split above fails.
- return $words ? $words : array();
+ // Return an empty array if the split above fails.
+ return $words ? $words : array();
}
static function get_word_count( $post_content ) {
@@ -358,7 +358,7 @@ class Jetpack_Media_Summary {
static function get_word_remaining_count( $post_content, $excerpt_content ) {
$content_word_count = count( self::split_content_in_words( self::clean_text( $post_content ) ) );
- $excerpt_word_count = count( self::split_content_in_words( self::clean_text( $excerpt_content ) ) );
+ $excerpt_word_count = count( self::split_content_in_words( self::clean_text( $excerpt_content ) ) );
return (int) $content_word_count - $excerpt_word_count;
}
diff --git a/plugins/jetpack/_inc/lib/class.media.php b/plugins/jetpack/_inc/lib/class.media.php
index e48c4aad..9e419580 100644
--- a/plugins/jetpack/_inc/lib/class.media.php
+++ b/plugins/jetpack/_inc/lib/class.media.php
@@ -16,7 +16,7 @@ class Jetpack_Media {
* The returned name has the `{basename}-{hash}-{random-number}.{ext}` shape.
* The hash is built according to the filename trying to avoid name collisions
* with other media files.
- *
+ *
* @param number $media_id - media post ID
* @param string $new_filename - the new filename
* @return string A random filename.
@@ -85,7 +85,7 @@ class Jetpack_Media {
/**
* Return an array of allowed mime_type items used to upload a media file.
- *
+ *
* @return array mime_type array
*/
static function get_allowed_mime_types( $default_mime_types ) {
@@ -110,58 +110,12 @@ class Jetpack_Media {
* @return bool
*/
protected static function is_file_supported_for_sideloading( $file ) {
- if ( class_exists( 'finfo' ) ) { // php 5.3+
- // phpcs:ignore PHPCompatibility.PHP.NewClasses.finfoFound
- $finfo = new finfo( FILEINFO_MIME );
- $mime = explode( '; ', $finfo->file( $file ) );
- $type = $mime[0];
-
- } elseif ( function_exists( 'mime_content_type' ) ) { // PHP 5.2
- $type = mime_content_type( $file );
-
- } else {
- return false;
- }
-
- /**
- * Filter the list of supported mime types for media sideloading.
- *
- * @since 4.0
- *
- * @module json-api
- *
- * @param array $supported_mime_types Array of the supported mime types for media sideloading.
- */
- $supported_mime_types = apply_filters( 'jetpack_supported_media_sideload_types', array(
- 'image/png',
- 'image/jpeg',
- 'image/gif',
- 'image/bmp',
- 'video/quicktime',
- 'video/mp4',
- 'video/mpeg',
- 'video/ogg',
- 'video/3gpp',
- 'video/3gpp2',
- 'video/h261',
- 'video/h262',
- 'video/h264',
- 'video/x-msvideo',
- 'video/x-ms-wmv',
- 'video/x-ms-asf',
- ) );
-
- // If the type returned was not an array as expected, then we know we don't have a match.
- if ( ! is_array( $supported_mime_types ) ) {
- return false;
- }
-
- return in_array( $type, $supported_mime_types );
+ return jetpack_is_file_supported_for_sideloading( $file );
}
/**
* Try to remove the temporal file from the given file array.
- *
+ *
* @param array $file_array Array with data about the temporal file
* @return bool `true` if the file has been removed. `false` either the file doesn't exist or it couldn't be removed.
*/
@@ -173,11 +127,11 @@ class Jetpack_Media {
}
/**
- * Save the given temporal file considering file type,
+ * Save the given temporal file considering file type,
* correct location according to the original file path, etc.
* The file type control is done through of `jetpack_supported_media_sideload_types` filter,
* which allows define to the users their own file types list.
- *
+ *
* @param array $file_array file to save
* @param number $media_id
* @return array|WP_Error an array with information about the new file saved or a WP_Error is something went wrong.
@@ -228,9 +182,9 @@ class Jetpack_Media {
/**
* Return an object with an snapshot of a revision item.
- *
+ *
* @param object $media_item - media post object
- * @return object a revision item
+ * @return object a revision item
*/
public static function get_snapshot( $media_item ) {
$current_file = get_attached_file( $media_item->ID );
@@ -242,7 +196,7 @@ class Jetpack_Media {
'file' => (string) $file_paths['basename'],
'extension' => (string) $file_paths['extension'],
'mime_type' => (string) $media_item->post_mime_type,
- 'size' => (int) filesize( $current_file )
+ 'size' => (int) filesize( $current_file ),
);
return (object) $snapshot;
@@ -250,7 +204,7 @@ class Jetpack_Media {
/**
* Add a new item into revision_history array.
- *
+ *
* @param object $media_item - media post object
* @param file $file - file recently added
* @param bool $has_original_media - condition is the original media has been already added
@@ -265,7 +219,7 @@ class Jetpack_Media {
}
/**
* Return the `revision_history` of the given media.
- *
+ *
* @param number $media_id - media post ID
* @return array `revision_history` array
*/
@@ -294,7 +248,7 @@ class Jetpack_Media {
/**
* Try to delete a file according to the dirname of
* the media attached file and the filename.
- *
+ *
* @param number $media_id - media post ID
* @param string $filename - basename of the file ( name-of-file.ext )
* @return bool `true` is the file has been removed, `false` if not.
@@ -325,7 +279,7 @@ class Jetpack_Media {
* 'from' => (int) <from>,
* 'to' => (int) <to>,
* )
- *
+ *
* Also, it removes the file defined in each item.
*
* @param number $media_id - media post ID
@@ -364,7 +318,7 @@ class Jetpack_Media {
/**
* Limit the number of items of the `revision_history` array.
* When the stack is overflowing the oldest item is remove from there (FIFO).
- *
+ *
* @param number $media_id - media post ID
* @param number [$limit] - maximun amount of items. 20 as default.
* @return array items removed from `revision_history`
@@ -393,7 +347,7 @@ class Jetpack_Media {
/**
* Remove the original file and clean the post metadata.
- *
+ *
* @param number $media_id - media post ID
*/
public static function clean_original_media( $media_id ) {
@@ -412,7 +366,7 @@ class Jetpack_Media {
* - remove all media files tied to the `revision_history` items.
* - clean `revision_history` meta data.
* - remove and clean the `original_media`
- *
+ *
* @param number $media_id - media post ID
* @return array results of removing these files
*/
@@ -442,7 +396,7 @@ class Jetpack_Media {
* - update attachment file
* - preserve original media file
* - trace revision history
- *
+ *
* @param number $media_id - media post ID
* @param array $file_array - temporal file
* @return {Post|WP_Error} Updated media item or a WP_Error is something went wrong.
diff --git a/plugins/jetpack/_inc/lib/components.php b/plugins/jetpack/_inc/lib/components.php
new file mode 100644
index 00000000..9c8a4fe2
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/components.php
@@ -0,0 +1,109 @@
+<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Components Library
+ *
+ * Load and display a pre-rendered component
+ */
+class Jetpack_Components {
+ /**
+ * Load and display a pre-rendered component
+ *
+ * @since 7.7.0
+ *
+ * @param string $name Component name.
+ * @param array $props Component properties.
+ *
+ * @return string The component markup
+ */
+ public static function render_component( $name, $props ) {
+
+ $rtl = is_rtl() ? '.rtl' : '';
+ wp_enqueue_style( 'jetpack-components', plugins_url( "_inc/blocks/components{$rtl}.css", JETPACK__PLUGIN_FILE ), array( 'wp-components' ), JETPACK__VERSION );
+
+ ob_start();
+ // `include` fails gracefully and throws a warning, but doesn't halt execution.
+ include JETPACK__PLUGIN_DIR . "_inc/blocks/$name.html";
+ $markup = ob_get_clean();
+
+ foreach ( $props as $key => $value ) {
+ $markup = str_replace(
+ "#$key#",
+ $value,
+ $markup
+ );
+
+ // Workaround, required to replace strings in `sprintf`-expressions.
+ // See extensions/i18n-to-php.js for more information.
+ $markup = str_replace(
+ "%($key)s",
+ $value,
+ $markup
+ );
+ }
+
+ return $markup;
+ }
+
+ /**
+ * Load and display a pre-rendered component
+ *
+ * @since 7.7.0
+ *
+ * @param array $props Component properties.
+ *
+ * @return string The component markup
+ */
+ public static function render_upgrade_nudge( $props ) {
+ $plan_slug = $props['plan'];
+ jetpack_require_lib( 'plans' );
+ $plan = Jetpack_Plans::get_plan( $plan_slug );
+
+ if ( ! $plan ) {
+ return self::render_component(
+ 'upgrade-nudge',
+ array(
+ 'planName' => __( 'a paid plan', 'jetpack' ),
+ 'upgradeUrl' => '',
+ )
+ );
+ }
+
+ // WP.com plan objects have a dedicated `path_slug` field, Jetpack plan objects don't
+ // For Jetpack, we thus use the plan slug with the 'jetpack_' prefix removed.
+ $plan_path_slug = wp_startswith( $plan_slug, 'jetpack_' )
+ ? substr( $plan_slug, strlen( 'jetpack_' ) )
+ : $plan->path_slug;
+
+ $post_id = get_the_ID();
+
+ if ( method_exists( 'Jetpack', 'build_raw_urls' ) ) {
+ $site_slug = Jetpack::build_raw_urls( home_url() );
+ } elseif ( class_exists( 'WPCOM_Masterbar' ) && method_exists( 'WPCOM_Masterbar', 'get_calypso_site_slug' ) ) {
+ $site_slug = WPCOM_Masterbar::get_calypso_site_slug( get_current_blog_id() );
+ }
+
+ // Post-checkout: redirect back to the editor.
+ $redirect_to = add_query_arg(
+ array(
+ 'plan_upgraded' => 1,
+ ),
+ get_edit_post_link( $post_id )
+ );
+
+ $upgrade_url =
+ $plan_path_slug
+ ? add_query_arg(
+ 'redirect_to',
+ $redirect_to,
+ "https://wordpress.com/checkout/${site_slug}/${plan_path_slug}"
+ ) : '';
+
+ return self::render_component(
+ 'upgrade-nudge',
+ array(
+ 'planName' => $plan->product_name,
+ 'upgradeUrl' => $upgrade_url,
+ )
+ );
+ }
+}
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
index 96a47a08..3ade1c34 100644
--- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
@@ -1,4 +1,7 @@
<?php
+
+use Automattic\Jetpack\Status;
+
/**
* This is the base class for every Core API endpoint Jetpack uses.
*
@@ -196,7 +199,7 @@ class Jetpack_Core_API_Module_List_Endpoint {
if (
isset( $modules[ $slug ]['requires_connection'] )
&& $modules[ $slug ]['requires_connection']
- && Jetpack::is_development_mode()
+ && ( new Status() )->is_development_mode()
) {
$modules[ $slug ]['activated'] = false;
}
@@ -363,7 +366,7 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
if (
isset( $module['requires_connection'] )
&& $module['requires_connection']
- && Jetpack::is_development_mode()
+ && ( new Status() )->is_development_mode()
) {
$module['activated'] = false;
}
@@ -420,19 +423,16 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
foreach ( $settings as $setting => $properties ) {
switch ( $setting ) {
case 'lang_id':
- if ( defined( 'WPLANG' ) ) {
- // We can't affect this setting, so warn the client
- $response[ $setting ] = 'error_const';
- break;
- }
-
if ( ! current_user_can( 'install_languages' ) ) {
// The user doesn't have caps to install language packs, so warn the client
$response[ $setting ] = 'error_cap';
break;
}
- $value = get_option( 'WPLANG' );
+ $value = get_option( 'WPLANG', '' );
+ if ( empty( $value ) && defined( 'WPLANG' ) ) {
+ $value = WPLANG;
+ }
$response[ $setting ] = empty( $value ) ? 'en_US' : $value;
break;
@@ -645,7 +645,7 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint {
switch ( $option ) {
case 'lang_id':
- if ( defined( 'WPLANG' ) || ! current_user_can( 'install_languages' ) ) {
+ if ( ! current_user_can( 'install_languages' ) ) {
// We can't affect this setting
$updated = false;
break;
@@ -1646,7 +1646,8 @@ class Jetpack_Core_API_Module_Data_Endpoint {
'code' => 'success',
'message' => esc_html(
sprintf(
- __( 'Your site was successfully backed-up %s ago.', 'jetpack' ),
+ /* translators: placeholder is a unit of time (1 hour, 5 days, ...) */
+ esc_html__( 'Your site was successfully backed up %s ago.', 'jetpack' ),
human_time_diff(
$data->backups->last_backup,
current_time( 'timestamp' )
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
index 68327f51..c321f6ae 100644
--- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
@@ -1,12 +1,21 @@
-<?php
+<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
/**
- * This is the endpoint class for `/site` endpoints.
+ * List of /site core REST API endpoints used in Jetpack's dashboard.
*
+ * @package Jetpack
+ */
+
+use Automattic\Jetpack\Connection\Client;
+
+/**
+ * This is the endpoint class for `/site` endpoints.
*/
class Jetpack_Core_API_Site_Endpoint {
+
/**
* Returns the result of `/sites/%s/features` endpoint call.
+ *
* @return object $features has 'active' and 'available' properties each of which contain feature slugs.
* 'active' is a simple array of slugs that are active on the current plan.
* 'available' is an object with keys that represent feature slugs and values are arrays
@@ -14,11 +23,11 @@ class Jetpack_Core_API_Site_Endpoint {
*/
public static function get_features() {
- // Make the API request
- $request = sprintf( '/sites/%d/features', Jetpack_Options::get_option( 'id' ) );
- $response = Jetpack_Client::wpcom_json_api_request_as_blog( $request, '1.1' );
+ // Make the API request.
+ $request = sprintf( '/sites/%d/features', Jetpack_Options::get_option( 'id' ) );
+ $response = Client::wpcom_json_api_request_as_blog( $request, '1.1' );
- // Bail if there was an error or malformed response
+ // Bail if there was an error or malformed response.
if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
return new WP_Error(
'failed_to_fetch_data',
@@ -27,10 +36,10 @@ class Jetpack_Core_API_Site_Endpoint {
);
}
- // Decode the results
+ // Decode the results.
$results = json_decode( $response['body'], true );
- // Bail if there were no results or plan details returned
+ // Bail if there were no results or plan details returned.
if ( ! is_array( $results ) ) {
return new WP_Error(
'failed_to_fetch_data',
@@ -39,10 +48,52 @@ class Jetpack_Core_API_Site_Endpoint {
);
}
- return rest_ensure_response( array(
- 'code' => 'success',
+ return rest_ensure_response(
+ array(
+ 'code' => 'success',
'message' => esc_html__( 'Site features correctly received.', 'jetpack' ),
- 'data' => wp_remote_retrieve_body( $response ),
+ 'data' => wp_remote_retrieve_body( $response ),
+ )
+ );
+ }
+
+
+ /**
+ * Returns the result of `/sites/%s/purchases` endpoint call.
+ *
+ * @return array of site purchases.
+ */
+ public static function get_purchases() {
+ // Make the API request.
+ $request = sprintf( '/sites/%d/purchases', Jetpack_Options::get_option( 'id' ) );
+ $response = Client::wpcom_json_api_request_as_blog( $request, '1.1' );
+
+ // Bail if there was an error or malformed response.
+ if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
+ return new WP_Error(
+ 'failed_to_fetch_data',
+ esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
+ array( 'status' => 500 )
+ );
+ }
+
+ // Decode the results.
+ $results = json_decode( $response['body'], true );
+
+ // Bail if there were no results or purchase details returned.
+ if ( ! is_array( $results ) ) {
+ return new WP_Error(
+ 'failed_to_fetch_data',
+ esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
+ array( 'status' => 500 )
+ );
+ }
+
+ return rest_ensure_response(
+ array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'Site purchases correctly received.', 'jetpack' ),
+ 'data' => wp_remote_retrieve_body( $response ),
)
);
}
@@ -57,4 +108,159 @@ class Jetpack_Core_API_Site_Endpoint {
public static function can_request() {
return current_user_can( 'jetpack_manage_modules' );
}
+
+ /**
+ * Gets an array of data that show how Jetpack is currently being used to benefit the site.
+ *
+ * @since 7.7
+ *
+ * @return WP_REST_Response
+ */
+ public static function get_benefits() {
+ $benefits = array();
+
+ /*
+ * We get different benefits from Stats:
+ * - this year's visitors
+ * - Followers (only if subs module is active)
+ * - Sharing counts (not currently supported in Jetpack -- https://github.com/Automattic/jetpack/issues/844 )
+ */
+ $stats = null;
+ if ( function_exists( 'stats_get_from_restapi' ) ) {
+ $stats = stats_get_from_restapi( array( 'fields' => 'stats' ) );
+ }
+
+ // Yearly visitors.
+ if ( null !== $stats && $stats->stats->visitors > 0 ) {
+ $benefits[] = array(
+ 'name' => 'jetpack-stats',
+ 'title' => esc_html__( 'Site Stats', 'jetpack' ),
+ 'description' => esc_html__( 'Visitors tracked by Jetpack', 'jetpack' ),
+ 'value' => absint( $stats->stats->visitors ),
+ );
+ }
+
+ // Protect blocked logins.
+ if ( Jetpack::is_module_active( 'protect' ) ) {
+ $protect = get_site_option( 'jetpack_protect_blocked_attempts' );
+ if ( $protect > 0 ) {
+ $benefits[] = array(
+ 'name' => 'protect',
+ 'title' => esc_html__( 'Brute force protection', 'jetpack' ),
+ 'description' => esc_html__( 'The number of malicious login attempts blocked by Jetpack', 'jetpack' ),
+ 'value' => absint( $protect ),
+ );
+ }
+ }
+
+ // Number of followers.
+ if ( null !== $stats && $stats->stats->followers_blog > 0 && Jetpack::is_module_active( 'subscriptions' ) ) {
+ $benefits[] = array(
+ 'name' => 'subscribers',
+ 'title' => esc_html__( 'Subscribers', 'jetpack' ),
+ 'description' => esc_html__( 'People subscribed to your updates through Jetpack', 'jetpack' ),
+ 'value' => absint( $stats->stats->followers_blog ),
+ );
+ }
+
+ // VaultPress backups.
+ if ( Jetpack::is_plugin_active( 'vaultpress/vaultpress.php' ) && class_exists( 'VaultPress' ) ) {
+ $vaultpress = new VaultPress();
+ if ( $vaultpress->is_registered() ) {
+ $data = json_decode( base64_decode( $vaultpress->contact_service( 'plugin_data' ) ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
+ if ( $data && $data->features->backups && ! empty( $data->backups->stats ) && $data->backups->stats->revisions > 0 ) {
+ $benefits[] = array(
+ 'name' => 'jetpack-backup',
+ 'title' => esc_html__( 'Jetpack Backup', 'jetpack' ),
+ 'description' => esc_html__( 'The number of times Jetpack has backed up your site and kept it safe', 'jetpack' ),
+ 'value' => absint( $data->backups->stats->revisions ),
+ );
+ }
+ }
+ }
+
+ // Number of forms sent via a Jetpack contact form.
+ if ( Jetpack::is_module_active( 'contact-form' ) ) {
+ $contact_form_count = array_sum( get_object_vars( wp_count_posts( 'feedback' ) ) );
+ if ( $contact_form_count > 0 ) {
+ $benefits[] = array(
+ 'name' => 'contact-form-feedback',
+ 'title' => esc_html__( 'Contact Form Feedback', 'jetpack' ),
+ 'description' => esc_html__( 'Form submissions stored by Jetpack', 'jetpack' ),
+ 'value' => absint( $contact_form_count ),
+ );
+ }
+ }
+
+ // Number of images in the library if Photon is active.
+ if ( Jetpack::is_module_active( 'photon' ) ) {
+ $photon_count = array_reduce(
+ get_object_vars( wp_count_attachments( array( 'image/jpeg', 'image/png', 'image/gif', 'image/bmp' ) ) ),
+ function ( $i, $j ) {
+ return $i + $j;
+ }
+ );
+ if ( $photon_count > 0 ) {
+ $benefits[] = array(
+ 'name' => 'image-hosting',
+ 'title' => esc_html__( 'Image Hosting', 'jetpack' ),
+ 'description' => esc_html__( 'Super-fast, mobile-ready images served by Jetpack', 'jetpack' ),
+ 'value' => absint( $photon_count ),
+ );
+ }
+ }
+
+ // Number of VideoPress videos on the site.
+ $videopress_attachments = wp_count_attachments( 'video/videopress' );
+ if (
+ isset( $videopress_attachments->{'video/videopress'} )
+ && $videopress_attachments->{'video/videopress'} > 0
+ ) {
+ $benefits[] = array(
+ 'name' => 'video-hosting',
+ 'title' => esc_html__( 'Video Hosting', 'jetpack' ),
+ 'description' => esc_html__( 'Ad-free, lightning-fast videos delivered by Jetpack', 'jetpack' ),
+ 'value' => absint( $videopress_attachments->{'video/videopress'} ),
+ );
+ }
+
+ // Number of active Publicize connections.
+ if ( Jetpack::is_module_active( 'publicize' ) && class_exists( 'Publicize' ) ) {
+ $publicize = new Publicize();
+ $connections = $publicize->get_all_connections();
+
+ $number_of_connections = 0;
+ if ( is_array( $connections ) && ! empty( $connections ) ) {
+ $number_of_connections = count( $connections );
+ }
+
+ if ( $number_of_connections > 0 ) {
+ $benefits[] = array(
+ 'name' => 'publicize',
+ 'title' => esc_html__( 'Publicize', 'jetpack' ),
+ 'description' => esc_html__( 'Live social media site connections, powered by Jetpack', 'jetpack' ),
+ 'value' => absint( $number_of_connections ),
+ );
+ }
+ }
+
+ // Total number of shares.
+ if ( null !== $stats && $stats->stats->shares > 0 ) {
+ $benefits[] = array(
+ 'name' => 'sharing',
+ 'title' => esc_html__( 'Sharing', 'jetpack' ),
+ 'description' => esc_html__( 'The number of times visitors have shared your posts with the world using Jetpack', 'jetpack' ),
+ 'value' => absint( $stats->stats->shares ),
+ );
+ }
+
+ // Finally, return the whole list of benefits.
+ return rest_ensure_response(
+ array(
+ 'code' => 'success',
+ 'message' => esc_html__( 'Site benefits correctly received.', 'jetpack' ),
+ 'data' => wp_json_encode( $benefits ),
+ )
+ );
+ }
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php
index 354880ed..a6612b37 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php
@@ -1,5 +1,7 @@
<?php
+use Automattic\Jetpack\Connection\Client;
+
/**
* Mailchimp: Get Mailchimp Status.
* API to determine if current site has linked Mailchimp account and mailing list selected.
@@ -14,6 +16,7 @@ class WPCOM_REST_API_V2_Endpoint_Mailchimp extends WP_REST_Controller {
$this->wpcom_is_wpcom_only_endpoint = true;
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+
}
/**
@@ -30,6 +33,16 @@ class WPCOM_REST_API_V2_Endpoint_Mailchimp extends WP_REST_Controller {
),
)
);
+ register_rest_route(
+ $this->namespace,
+ $this->rest_base . '/groups',
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_mailchimp_groups' ),
+ ),
+ )
+ );
}
/**
@@ -67,13 +80,36 @@ class WPCOM_REST_API_V2_Endpoint_Mailchimp extends WP_REST_Controller {
403
);
}
- $connect_url = sprintf( 'https://wordpress.com/marketing/connections/%s', rawurlencode( $site_id ) );
+ $connect_url = sprintf( 'https://wordpress.com/marketing/connections/%s?mailchimp', rawurlencode( $site_id ) );
return array(
'code' => $this->is_connected() ? 'connected' : 'not_connected',
'connect_url' => $connect_url,
'site_id' => $site_id,
);
}
+
+ /**
+ * Get all Mailchimp groups for the accounted connected to the current blog
+ *
+ * @return mixed
+ * groups:array
+ * site_id:int
+ */
+ public function get_mailchimp_groups() {
+ $is_wpcom = ( defined( 'IS_WPCOM' ) && IS_WPCOM );
+ $site_id = $is_wpcom ? get_current_blog_id() : Jetpack_Options::get_option( 'id' );
+ if ( ! $site_id ) {
+ return new WP_Error(
+ 'unavailable_site_id',
+ __( 'Sorry, something is wrong with your Jetpack connection.', 'jetpack' ),
+ 403
+ );
+ }
+ $path = sprintf( '/sites/%d/mailchimp/groups', absint( $site_id ) );
+ $request = Client::wpcom_json_api_request_as_blog( $path );
+ $body = wp_remote_retrieve_body( $request );
+ return json_decode( $body );
+ }
}
wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Mailchimp' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-resolve-redirect.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-resolve-redirect.php
new file mode 100644
index 00000000..442a2efa
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-resolve-redirect.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * REST API endpoint for resolving URL redirects.
+ *
+ * @package Jetpack
+ * @since 8.0.0
+ */
+
+/**
+ * Resolve URL redirects.
+ *
+ * @since 8.0.0
+ */
+class WPCOM_REST_API_V2_Endpoint_Resolve_Redirect extends WP_REST_Controller {
+ /**
+ * Constructor.
+ */
+ public function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'resolve-redirect';
+ // This endpoint *does not* need to connect directly to Jetpack sites.
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ /**
+ * Register the route.
+ */
+ public function register_routes() {
+ // GET /sites/<blog_id>/resolve-redirect/<url> - Follow 301/302 redirects on a URL, and return the final destination.
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->rest_base . '/(?P<url>.+)',
+ array(
+ 'args' => array(
+ 'url' => array(
+ 'description' => __( 'The URL to check for redirects.', 'jetpack' ),
+ 'type' => 'string',
+ 'required' => 'true',
+ 'validate_callback' => 'wp_http_validate_url',
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'follow_redirect' ),
+ 'permission_callback' => 'is_user_logged_in',
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+ }
+
+ /**
+ * Follows 301/302 redirect for the passed URL, and returns the final destination.
+ *
+ * @param WP_REST_Request $request The REST API request data.
+ * @return WP_REST_Response The REST API response.
+ */
+ public function follow_redirect( $request ) {
+ $response = wp_safe_remote_get( $request['url'] );
+ if ( is_wp_error( $response ) ) {
+ return rest_ensure_response( '' );
+ }
+
+ $history = $response['http_response']->get_response_object()->history;
+ if ( ! $history ) {
+ return response_ensure_response( $request['url'] );
+ }
+
+ $location = $history[0]->headers->getValues( 'location' );
+ if ( ! $location ) {
+ return response_ensure_response( $request['url'] );
+ }
+
+ return rest_ensure_response( $location[0] );
+ }
+
+ /**
+ * Retrieves the comment's schema, conforming to JSON Schema.
+ *
+ * @return array
+ */
+ public function get_item_schema() {
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => 'resolve-redirect',
+ 'type' => 'string',
+ 'description' => __( 'The final destination of the URL being checked for redirects.', 'jetpack' ),
+ );
+
+ return $schema;
+ }
+}
+
+wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Resolve_Redirect' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php
index ec997739..028568db 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/memberships.php
@@ -6,6 +6,8 @@
* @since 7.3.0
*/
+use Automattic\Jetpack\Connection\Client;
+
/**
* Class WPCOM_REST_API_V2_Endpoint_Memberships
* This introduces V2 endpoints.
@@ -108,7 +110,7 @@ class WPCOM_REST_API_V2_Endpoint_Memberships extends WP_REST_Controller {
return $product->to_array();
} else {
$blog_id = Jetpack_Options::get_option( 'id' );
- $response = Jetpack_Client::wpcom_json_api_request_as_user(
+ $response = Client::wpcom_json_api_request_as_user(
"/sites/$blog_id/{$this->rest_base}/product",
'v2',
array(
@@ -141,21 +143,16 @@ class WPCOM_REST_API_V2_Endpoint_Memberships extends WP_REST_Controller {
/**
* Get a status of connection for the site. If this is Jetpack, pass the request to wpcom.
*
- * @return array|WP_Error
+ * @return WP_Error|array ['products','connected_account_id','connect_url','should_upgrade_to_access_memberships','upgrade_url']
*/
public function get_status() {
- $connected_account_id = Jetpack_Memberships::get_connected_account_id();
- $connect_url = '';
if ( ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) {
require_lib( 'memberships' );
$blog_id = get_current_blog_id();
- if ( ! $connected_account_id ) {
- $connect_url = get_memberships_connected_account_redirect( get_current_user_id(), $blog_id );
- }
- $products = get_memberships_plans( $blog_id );
+ return (array) get_memberships_settings_for_site( $blog_id );
} else {
$blog_id = Jetpack_Options::get_option( 'id' );
- $response = Jetpack_Client::wpcom_json_api_request_as_user(
+ $response = Client::wpcom_json_api_request_as_user(
"/sites/$blog_id/{$this->rest_base}/status",
'v2',
array(),
@@ -168,16 +165,11 @@ class WPCOM_REST_API_V2_Endpoint_Memberships extends WP_REST_Controller {
return new WP_Error( 'wpcom_connection_error', __( 'Could not connect to WordPress.com', 'jetpack' ), 404 );
}
$data = isset( $response['body'] ) ? json_decode( $response['body'], true ) : null;
- if ( ! $connected_account_id ) {
- $connect_url = empty( $data['connect_url'] ) ? '' : $data['connect_url'];
+ if ( 200 !== $response['response']['code'] && $data['code'] && $data['message'] ) {
+ return new WP_Error( $data['code'], $data['message'], 401 );
}
- $products = empty( $data['products'] ) ? array() : $data['products'];
+ return $data;
}
- return array(
- 'connected_account_id' => $connected_account_id,
- 'connect_url' => $connect_url,
- 'products' => $products,
- );
}
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php
index c1a712bd..47c95b26 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php
@@ -1,5 +1,7 @@
<?php
+use Automattic\Jetpack\Constants;
+
/**
* Subscribers: Get subscriber count
*
@@ -41,7 +43,7 @@ class WPCOM_REST_API_V2_Endpoint_Subscribers extends WP_REST_Controller {
*/
public function get_subscriber_count( $request ) {
// Get the most up to date subscriber count when request is not a test
- if ( ! Jetpack_Constants::is_defined( 'TESTING_IN_JETPACK' ) ) {
+ if ( ! Constants::is_defined( 'TESTING_IN_JETPACK' ) ) {
delete_transient( 'wpcom_subscribers_total' );
}
@@ -56,7 +58,7 @@ class WPCOM_REST_API_V2_Endpoint_Subscribers extends WP_REST_Controller {
if (
Jetpack::is_module_active( 'subscriptions' ) ||
- ( Jetpack_Constants::is_defined( 'TESTING_IN_JETPACK' ) && Jetpack_Constants::get_constant( 'TESTING_IN_JETPACK' ) )
+ ( Constants::is_defined( 'TESTING_IN_JETPACK' ) && Constants::get_constant( 'TESTING_IN_JETPACK' ) )
) {
wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Subscribers' );
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
index c4254a9d..21181d2c 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
@@ -23,9 +23,11 @@
* @since 6.8.0
*/
class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_V2_Field_Controller {
- protected $object_type = 'post';
+ protected $object_type = array( 'post' );
protected $field_name = 'jetpack_publicize_connections';
+ private $_meta_saved = array();
+
public $memoized_updates = array();
/**
@@ -34,7 +36,6 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
*/
public function register_fields() {
$this->object_type = get_post_types_by_support( 'publicize' );
-
foreach ( $this->object_type as $post_type ) {
// Adds meta support for those post types that don't already have it.
// Only runs during REST API requests, so it doesn't impact UI.
@@ -208,14 +209,18 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
}
$permission_check = $this->update_permission_check( $request['jetpack_publicize_connections'], $post, $request );
-
if ( is_wp_error( $permission_check ) ) {
return $permission_check;
}
-
// memoize
$this->get_meta_to_update( $request['jetpack_publicize_connections'], isset( $post->ID ) ? $post->ID : 0 );
+ if ( isset( $post->ID ) ) {
+ // Set the meta before we mark the post as published so that publicize works as expected.
+ // If this is not the case post end up on social media when they are marked as skipped.
+ $this->update( $request['jetpack_publicize_connections'], $post, $request );
+ }
+
return $post;
}
@@ -338,6 +343,9 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
* @param WP_REST_Request
*/
public function update( $requested_connections, $post, $request ) {
+ if ( isset( $this->_meta_saved[ $post->ID ] ) ) { // Make sure we only save it once - per request.
+ return;
+ }
foreach ( $this->get_meta_to_update( $requested_connections, $post->ID ) as $meta_key => $meta_value ) {
if ( is_null( $meta_value ) ) {
delete_post_meta( $post->ID, $meta_key );
@@ -345,6 +353,7 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
update_post_meta( $post->ID, $meta_key, $meta_value );
}
}
+ $this->_meta_saved[ $post->ID ] = true;
}
}
diff --git a/plugins/jetpack/_inc/lib/debugger/0-load.php b/plugins/jetpack/_inc/lib/debugger/0-load.php
index a3eaf4e6..ad069244 100644
--- a/plugins/jetpack/_inc/lib/debugger/0-load.php
+++ b/plugins/jetpack/_inc/lib/debugger/0-load.php
@@ -5,8 +5,6 @@
* @package Jetpack.
*/
-global $wp_version;
-
/* Jetpack Connection Testing Framework */
require_once 'class-jetpack-cxn-test-base.php';
/* Jetpack Connection Tests */
@@ -15,10 +13,9 @@ require_once 'class-jetpack-cxn-tests.php';
require_once 'class-jetpack-debug-data.php';
/* The "In-Plugin Debugger" admin page. */
require_once 'class-jetpack-debugger.php';
+/* General Debugging Functions */
+require_once 'debug-functions.php';
-if ( version_compare( $wp_version, '5.2-alpha', 'ge' ) ) {
- require_once 'debug-functions-for-php53.php';
- add_filter( 'debug_information', array( 'Jetpack_Debug_Data', 'core_debug_data' ) );
- add_filter( 'site_status_tests', 'jetpack_debugger_site_status_tests' );
- add_action( 'wp_ajax_health-check-jetpack-local_testing_suite', 'jetpack_debugger_ajax_local_testing_suite' );
-}
+add_filter( 'debug_information', array( 'Jetpack_Debug_Data', 'core_debug_data' ) );
+add_filter( 'site_status_tests', 'jetpack_debugger_site_status_tests' );
+add_action( 'wp_ajax_health-check-jetpack-local_testing_suite', 'jetpack_debugger_ajax_local_testing_suite' );
diff --git a/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-test-base.php b/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-test-base.php
index 56f21bc4..85da12d8 100644
--- a/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-test-base.php
+++ b/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-test-base.php
@@ -1,4 +1,6 @@
<?php
+use Automattic\Jetpack\Status;
+
/**
* Jetpack Connection Testing
*
@@ -319,7 +321,7 @@ class Jetpack_Cxn_Test_Base {
*/
public function output_results_for_cli( $type = 'all', $group = 'all' ) {
if ( defined( 'WP_CLI' ) && WP_CLI ) {
- if ( Jetpack::is_development_mode() ) {
+ if ( ( new Status() )->is_development_mode() ) {
WP_CLI::line( __( 'Jetpack is in Development Mode:', 'jetpack' ) );
WP_CLI::line( Jetpack::development_mode_trigger_text() );
}
diff --git a/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-tests.php b/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-tests.php
index 274d032b..6e3cccd6 100644
--- a/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-tests.php
+++ b/plugins/jetpack/_inc/lib/debugger/class-jetpack-cxn-tests.php
@@ -5,6 +5,10 @@
* @package Jetpack
*/
+use Automattic\Jetpack\Connection\Client;
+use Automattic\Jetpack\Status;
+use Automattic\Jetpack\Connection\Utils as Connection_Utils;
+
/**
* Class Jetpack_Cxn_Tests contains all of the actual tests.
*/
@@ -65,7 +69,19 @@ class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
* Is Jetpack even connected and supposed to be talking to WP.com?
*/
protected function helper_is_jetpack_connected() {
- return ( Jetpack::is_active() && ! Jetpack::is_development_mode() );
+ return ( Jetpack::is_active() && ! ( new Status() )->is_development_mode() );
+ }
+
+ /**
+ * Returns 30 for use with a filter.
+ *
+ * To allow time for WP.com to run upstream testing, this function exists to increase the http_request_timeout value
+ * to 30.
+ *
+ * @return int 30
+ */
+ public static function increase_timeout() {
+ return 30; // seconds.
}
/**
@@ -75,7 +91,7 @@ class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
$name = __FUNCTION__;
if ( $this->helper_is_jetpack_connected() ) {
$result = self::passing_test( $name );
- } elseif ( Jetpack::is_development_mode() ) {
+ } elseif ( ( new Status() )->is_development_mode() ) {
$result = self::skipped_test( $name, __( 'Jetpack is in Development Mode:', 'jetpack' ) . ' ' . Jetpack::development_mode_trigger_text(), __( 'Disable development mode.', 'jetpack' ) );
} else {
$result = self::failing_test( $name, __( 'Jetpack is not connected.', 'jetpack' ), 'cycle_connection' );
@@ -221,14 +237,16 @@ class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
protected function test__wpcom_connection_test() {
$name = __FUNCTION__;
- if ( ! Jetpack::is_active() || Jetpack::is_development_mode() || Jetpack::is_staging_site() || ! $this->pass ) {
+ if ( ! Jetpack::is_active() || ( new Status() )->is_development_mode() || Jetpack::is_staging_site() || ! $this->pass ) {
return self::skipped_test( $name );
}
- $response = Jetpack_Client::wpcom_json_api_request_as_blog(
+ add_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
+ $response = Client::wpcom_json_api_request_as_blog(
sprintf( '/jetpack-blogs/%d/test-connection', Jetpack_Options::get_option( 'id' ) ),
- Jetpack_Client::WPCOM_JSON_API_VERSION
+ Client::WPCOM_JSON_API_VERSION
);
+ remove_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
if ( is_wp_error( $response ) ) {
/* translators: %1$s is the error code, %2$s is the error message */
@@ -242,6 +260,10 @@ class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
return self::failing_test( $name, $message );
}
+ if ( 404 === wp_remote_retrieve_response_code( $response ) ) {
+ return self::skipped_test( $name, __( 'The WordPress.com API returned a 404 error.', 'jetpack' ) );
+ }
+
$result = json_decode( $body );
$is_connected = (bool) $result->connected;
$message = $result->message . ': ' . wp_remote_retrieve_response_code( $response );
@@ -313,28 +335,52 @@ class Jetpack_Cxn_Tests extends Jetpack_Cxn_Test_Base {
*
* Intentionally added last as it will be skipped if any local failed conditions exist.
*
+ * @since 7.1.0
+ * @since 7.9.0 Timeout waiting for a WP.com response no longer fails the test. Test is marked skipped instead.
+ *
* @return array Test results.
*/
protected function last__wpcom_self_test() {
$name = 'test__wpcom_self_test';
- if ( ! Jetpack::is_active() || Jetpack::is_development_mode() || Jetpack::is_staging_site() || ! $this->pass ) {
+
+ if ( ! Jetpack::is_active() || ( new Status() )->is_development_mode() || Jetpack::is_staging_site() || ! $this->pass ) {
return self::skipped_test( $name );
}
$self_xml_rpc_url = site_url( 'xmlrpc.php' );
- $testsite_url = Jetpack::fix_url_for_bad_hosts( JETPACK__API_BASE . 'testsite/1/?url=' );
+ $testsite_url = Connection_Utils::fix_url_for_bad_hosts( JETPACK__API_BASE . 'testsite/1/?url=' );
- add_filter( 'http_request_timeout', array( 'Jetpack_Debugger', 'jetpack_increase_timeout' ) );
+ add_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
$response = wp_remote_get( $testsite_url . $self_xml_rpc_url );
- remove_filter( 'http_request_timeout', array( 'Jetpack_Debugger', 'jetpack_increase_timeout' ) );
+ remove_filter( 'http_request_timeout', array( 'Jetpack_Cxn_Tests', 'increase_timeout' ) );
+
+ $error_msg = wp_kses(
+ sprintf(
+ /* translators: Placeholder is a link to site's Jetpack debug page. */
+ __(
+ '<a target="_blank" rel="noopener noreferrer" href="%s">Visit the Jetpack.com debug page</a> for more information or <a target="_blank" rel="noopener noreferrer" href="https://jetpack.com/contact-support/">contact support</a>.',
+ 'jetpack'
+ ),
+ esc_url( add_query_arg( 'url', rawurlencode( site_url() ), 'https://jetpack.com/support/debug/' ) )
+ ),
+ array(
+ 'a' => array(
+ 'href' => array(),
+ 'target' => array(),
+ 'rel' => array(),
+ ),
+ )
+ );
if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
return self::passing_test( $name );
+ } elseif ( is_wp_error( $response ) && false !== strpos( $response->get_error_message(), 'cURL error 28' ) ) { // Timeout.
+ return self::skipped_test( $name, __( 'The test timed out which may sometimes indicate a failure or may be a false failure.', 'jetpack' ) );
} else {
- return self::failing_test( $name, __( 'Jetpack.com detected an error.', 'jetpack' ), __( 'Visit the Jetpack.com debugging page for more information or contact support.', 'jetpack' ) ); // @todo direct links.
+ return self::failing_test( $name, __( 'Jetpack.com detected an error on the WPcom Self Test.', 'jetpack' ), $error_msg );
}
}
}
diff --git a/plugins/jetpack/_inc/lib/debugger/class-jetpack-debug-data.php b/plugins/jetpack/_inc/lib/debugger/class-jetpack-debug-data.php
index 31e38790..f128d38d 100644
--- a/plugins/jetpack/_inc/lib/debugger/class-jetpack-debug-data.php
+++ b/plugins/jetpack/_inc/lib/debugger/class-jetpack-debug-data.php
@@ -5,6 +5,11 @@
* @package jetpack
*/
+use Automattic\Jetpack\Constants;
+use Automattic\Jetpack\Sync\Modules;
+use Automattic\Jetpack\Sync\Functions;
+use Automattic\Jetpack\Sync\Sender;
+
/**
* Class Jetpack_Debug_Data
*
@@ -89,6 +94,10 @@ class Jetpack_Debug_Data {
* @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()
+ ? 'https://jetpack.com/contact-support/beta-group/'
+ : 'https://jetpack.com/contact-support/';
+
$jetpack = array(
'jetpack' => array(
'label' => __( 'Jetpack', 'jetpack' ),
@@ -98,7 +107,7 @@ class Jetpack_Debug_Data {
'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_html( 'https://jetpack.com/contact-support/' ),
+ esc_url( $support_url ),
__( '(opens in a new tab)', 'jetpack' )
),
'fields' => self::debug_data(),
@@ -169,25 +178,20 @@ class Jetpack_Debug_Data {
*
* If a token does not contain a period, then it is malformed and we report it as such.
*/
- $user_id = get_current_user_id();
- $user_tokens = Jetpack_Options::get_option( 'user_tokens' );
- $blog_token = Jetpack_Options::get_option( 'blog_token' );
- $user_token = null;
- if ( is_array( $user_tokens ) && array_key_exists( $user_id, $user_tokens ) ) {
- $user_token = $user_tokens[ $user_id ];
- }
- unset( $user_tokens );
+ $user_id = get_current_user_id();
+ $blog_token = Jetpack_Data::get_access_token();
+ $user_token = Jetpack_Data::get_access_token( $user_id );
$tokenset = '';
if ( $blog_token ) {
$tokenset = 'Blog ';
- $blog_key = substr( $blog_token, 0, strpos( $blog_token, '.' ) );
+ $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, 0, strpos( $user_token, '.' ) );
+ $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.';
}
@@ -271,14 +275,7 @@ class Jetpack_Debug_Data {
);
/** Sync Debug Information */
- /** Load Sync modules */
- require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-modules.php';
- /** Load Sync sender */
- require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-sender.php';
- /** Load Sync functions */
- require_once JETPACK__PLUGIN_DIR . 'sync/class.jetpack-sync-functions.php';
-
- $sync_module = Jetpack_Sync_Modules::get_module( 'full-sync' );
+ $sync_module = Modules::get_module( 'full-sync' );
if ( $sync_module ) {
$sync_statuses = $sync_module->get_status();
$human_readable_sync_status = array();
@@ -294,7 +291,7 @@ class Jetpack_Debug_Data {
);
}
- $queue = Jetpack_Sync_Sender::get_instance()->get_sync_queue();
+ $queue = Sender::get_instance()->get_sync_queue();
$debug_info['sync_size'] = array(
'label' => 'Sync Queue Size',
@@ -307,7 +304,7 @@ class Jetpack_Debug_Data {
'private' => false,
);
- $full_sync_queue = Jetpack_Sync_Sender::get_instance()->get_full_sync_queue();
+ $full_sync_queue = Sender::get_instance()->get_full_sync_queue();
$debug_info['full_sync_size'] = array(
'label' => 'Full Sync Queue Size',
@@ -326,10 +323,10 @@ class Jetpack_Debug_Data {
* Must follow sync debug since it depends on sync functionality.
*/
$idc_urls = array(
- 'home' => Jetpack_Sync_Functions::home_url(),
- 'siteurl' => Jetpack_Sync_Functions::site_url(),
- 'WP_HOME' => Jetpack_Constants::is_defined( 'WP_HOME' ) ? Jetpack_Constants::get_constant( 'WP_HOME' ) : '',
- 'WP_SITEURL' => Jetpack_Constants::is_defined( 'WP_SITEURL' ) ? Jetpack_Constants::get_constant( 'WP_SITEURL' ) : '',
+ 'home' => Functions::home_url(),
+ 'siteurl' => Functions::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(
diff --git a/plugins/jetpack/_inc/lib/debugger/class-jetpack-debugger.php b/plugins/jetpack/_inc/lib/debugger/class-jetpack-debugger.php
index e7038902..afbbb4d1 100644
--- a/plugins/jetpack/_inc/lib/debugger/class-jetpack-debugger.php
+++ b/plugins/jetpack/_inc/lib/debugger/class-jetpack-debugger.php
@@ -1,60 +1,38 @@
<?php
+
+use Automattic\Jetpack\Status;
+
/**
* Jetpack Debugger functionality allowing for self-service diagnostic information via the legacy jetpack debugger.
*
* @package jetpack
*/
-/** Ensure the Jetpack_Debug_Data class is available. It should be via the library loaded, but defense is good. */
-require_once 'class-jetpack-debug-data.php';
-
/**
* Class Jetpack_Debugger
*
* A namespacing class for functionality related to the legacy in-plugin diagnostic tooling.
*/
class Jetpack_Debugger {
-
- /**
- * Determine the active plan and normalize it for the debugger results.
- *
- * @return string The plan slug prepended with "JetpackPlan"
- */
- private static function what_jetpack_plan() {
- // Specifically not deprecating this function since it modifies the output of the Jetpack_Debug_Data::what_jetpack_plan return.
- return 'JetpackPlan' . Jetpack_Debug_Data::what_jetpack_plan();
- }
-
- /**
- * Convert seconds to human readable time.
- *
- * A dedication function instead of using Core functionality to allow for output in seconds.
- *
- * @deprecated 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 ) {
- _deprecated_function( 'Jetpack_Debugger::seconds_to_time', 'Jetpack 7.3.0', 'Jeptack_Debug_Data::seconds_to_time' );
- return Jetpack_Debug_Data::seconds_to_time( $seconds );
- }
-
/**
* Returns 30 for use with a filter.
*
* To allow time for WP.com to run upstream testing, this function exists to increase the http_request_timeout value
* to 30.
*
+ * @deprecated 8.0.0
+ *
* @return int 30
*/
public static function jetpack_increase_timeout() {
+ _deprecated_function( __METHOD__, 'jetpack-8.0', 'Jetpack_Cxn_Tests::increase_timeout' );
return 30; // seconds.
}
/**
* 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' ) ) ) {
@@ -74,23 +52,13 @@ class Jetpack_Debugger {
* Handles output to the browser for the in-plugin debugger.
*/
public static function jetpack_debug_display_handler() {
- global $wp_version;
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'jetpack' ) );
}
- $data = Jetpack_Debug_Data::debug_data();
- $debug_info = '';
- foreach ( $data as $datum ) {
- $debug_info .= $datum['label'] . ': ' . $datum['value'] . "\r\n";
- }
-
- $debug_info .= "\r\n" . esc_html( 'PHP_VERSION: ' . PHP_VERSION );
- $debug_info .= "\r\n" . esc_html( 'WORDPRESS_VERSION: ' . $GLOBALS['wp_version'] );
- $debug_info .= "\r\n" . esc_html( 'SITE_URL: ' . site_url() );
- $debug_info .= "\r\n" . esc_html( 'HOME_URL: ' . home_url() );
-
- $debug_info .= "\r\n\r\nTEST RESULTS:\r\n\r\n";
+ $support_url = Jetpack::is_development_version()
+ ? 'https://jetpack.com/contact-support/beta-group/'
+ : 'https://jetpack.com/contact-support/';
$cxntests = new Jetpack_Cxn_Tests();
?>
@@ -101,20 +69,23 @@ class Jetpack_Debugger {
<?php
if ( $cxntests->pass() ) {
echo '<div class="jetpack-tests-succeed">' . esc_html__( 'Your Jetpack setup looks a-okay!', 'jetpack' ) . '</div>';
- $debug_info .= "All tests passed.\r\n";
- $debug_info .= print_r( $cxntests->raw_results(), true ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
} else {
$failures = $cxntests->list_fails();
foreach ( $failures as $fail ) {
echo '<div class="jetpack-test-error">';
echo '<p><a class="jetpack-test-heading" href="#">' . esc_html( $fail['message'] );
echo '<span class="noticon noticon-collapse"></span></a></p>';
- echo '<p class="jetpack-test-details">' . esc_html( $fail['resolution'] ) . '</p>';
+ echo '<p class="jetpack-test-details">' . wp_kses(
+ $fail['resolution'],
+ array(
+ 'a' => array(
+ 'href' => array(),
+ 'target' => array(),
+ 'rel' => array(),
+ ),
+ )
+ ) . '</p>';
echo '</div>';
-
- $debug_info .= "FAILED TESTS!\r\n";
- $debug_info .= $fail['name'] . ': ' . $fail['message'] . "\r\n";
- $debug_info .= print_r( $cxntests->raw_results(), true ); //phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r
}
}
?>
@@ -140,9 +111,9 @@ class Jetpack_Debugger {
),
)
),
- 'http://jetpack.com/support/getting-started-with-jetpack/known-issues/',
- 'http://jetpack.com/support/getting-started-with-jetpack/known-issues/',
- 'http://jetpack.com/support/',
+ 'https://jetpack.com/support/getting-started-with-jetpack/known-issues/',
+ 'https://jetpack.com/support/getting-started-with-jetpack/known-issues/',
+ 'https://jetpack.com/support/',
'https://wordpress.org/support/plugin/jetpack'
);
?>
@@ -214,32 +185,17 @@ class Jetpack_Debugger {
<p><b><em><?php esc_html_e( 'Ask us for help!', 'jetpack' ); ?></em></b>
<?php
/**
- * Offload to new WordPress debug data in WP 5.2+
- *
- * @todo remove fallback when 5.2 is the minimum supported.
+ * Offload to new WordPress debug data.
*/
- if ( version_compare( $wp_version, '5.2-alpha', '>=' ) ) {
echo sprintf(
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() ) )
),
- 'https://jetpack.com/contact-support/',
+ esc_url( $support_url ),
esc_url( admin_url() . 'site-health.php?tab=debug' )
);
- $hide_debug = true;
- } else { // Versions before 5.2, fallback.
- echo sprintf(
- wp_kses(
- /* translators: URL for Jetpack support. */
- __( '<a href="%s">Contact our Happiness team</a>. When you do, please include the full debug information below.', 'jetpack' ),
- array( 'a' => array( 'href' => array() ) )
- ),
- 'https://jetpack.com/contact-support/'
- );
- $hide_debug = false;
- }
?>
</p>
<hr />
@@ -278,7 +234,7 @@ class Jetpack_Debugger {
<?php
if (
current_user_can( 'jetpack_manage_modules' )
- && ( Jetpack::is_development_mode() || Jetpack::is_active() )
+ && ( ( new Status() )->is_development_mode() || Jetpack::is_active() )
) {
printf(
wp_kses(
@@ -294,18 +250,6 @@ class Jetpack_Debugger {
}
?>
</div>
- <hr />
- <?php
- if ( ! $hide_debug ) {
- ?>
- <div id="toggle_debug_info"><?php esc_html_e( 'Advanced Debug Results', 'jetpack' ); ?></div>
- <div id="debug_info_div">
- <h4><?php esc_html_e( 'Debug Info', 'jetpack' ); ?></h4>
- <div id="debug_info"><pre><?php echo esc_html( $debug_info ); ?></pre></div>
- </div>
- <?php
- }
- ?>
</div>
<?php
}
diff --git a/plugins/jetpack/_inc/lib/debugger/debug-functions-for-php53.php b/plugins/jetpack/_inc/lib/debugger/debug-functions.php
index a32d9fee..a32d9fee 100644
--- a/plugins/jetpack/_inc/lib/debugger/debug-functions-for-php53.php
+++ b/plugins/jetpack/_inc/lib/debugger/debug-functions.php
diff --git a/plugins/jetpack/_inc/lib/icalendar-reader.php b/plugins/jetpack/_inc/lib/icalendar-reader.php
index f7e047f9..998f4c13 100644
--- a/plugins/jetpack/_inc/lib/icalendar-reader.php
+++ b/plugins/jetpack/_inc/lib/icalendar-reader.php
@@ -90,17 +90,7 @@ class iCalendarReader {
}
// get timezone offset from the timezone name.
- $timezone_name = get_option( 'timezone_string' );
- if ( $timezone_name ) {
- $timezone = new DateTimeZone( $timezone_name );
- $timezone_offset_interval = false;
- } else {
- // If the timezone isn't set then the GMT offset must be set.
- // generate a DateInterval object from the timezone offset
- $gmt_offset = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
- $timezone_offset_interval = date_interval_create_from_date_string( "{$gmt_offset} seconds" );
- $timezone = new DateTimeZone( 'UTC' );
- }
+ $timezone = wp_timezone();
$offsetted_events = array();
@@ -115,11 +105,6 @@ class iCalendarReader {
$end_time = new DateTime( $end_time, $this->timezone );
$end_time->setTimeZone( $timezone );
- if ( $timezone_offset_interval ) {
- $start_time->add( $timezone_offset_interval );
- $end_time->add( $timezone_offset_interval );
- }
-
$event['DTSTART'] = $start_time->format( 'YmdHis\Z' );
$event['DTEND'] = $end_time->format( 'YmdHis\Z' );
}
@@ -895,7 +880,7 @@ class iCalendarReader {
* @return array
*/
function icalendar_get_events( $url = '', $count = 5 ) {
- // Find your calendar's address http://support.google.com/calendar/bin/answer.py?hl=en&answer=37103
+ // Find your calendar's address https://support.google.com/calendar/bin/answer.py?hl=en&answer=37103
$ical = new iCalendarReader();
return $ical->get_events( $url, $count );
}
diff --git a/plugins/jetpack/_inc/lib/markdown/extra.php b/plugins/jetpack/_inc/lib/markdown/extra.php
index fd85a3c8..1f8f854d 100644
--- a/plugins/jetpack/_inc/lib/markdown/extra.php
+++ b/plugins/jetpack/_inc/lib/markdown/extra.php
@@ -806,7 +806,7 @@ class Markdown_Parser {
if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
return $matches[0];
- $level = $matches[2]{0} == '=' ? 1 : 2;
+ $level = $matches[2][0] == '=' ? 1 : 2;
$block = "<h$level>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
}
@@ -1102,7 +1102,7 @@ class Markdown_Parser {
} else {
# Other closing marker: close one em or strong and
# change current token state to match the other
- $token_stack[0] = str_repeat($token{0}, 3-$token_len);
+ $token_stack[0] = str_repeat($token[0], 3-$token_len);
$tag = $token_len == 2 ? "strong" : "em";
$span = $text_stack[0];
$span = $this->runSpanGamut($span);
@@ -1127,7 +1127,7 @@ class Markdown_Parser {
} else {
# Reached opening three-char emphasis marker. Push on token
# stack; will be handled by the special condition above.
- $em = $token{0};
+ $em = $token[0];
$strong = "$em$em";
array_unshift($token_stack, $token);
array_unshift($text_stack, '');
@@ -1467,9 +1467,9 @@ class Markdown_Parser {
# Handle $token provided by parseSpan by determining its nature and
# returning the corresponding value that should replace it.
#
- switch ($token{0}) {
+ switch ($token[0]) {
case "\\":
- return $this->hashPart("&#". ord($token{1}). ";");
+ return $this->hashPart("&#". ord($token[1]). ";");
case "`":
# Search for end marker in remaining text.
if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
@@ -1690,9 +1690,9 @@ class MarkdownExtra_Parser extends Markdown_Parser {
$classes = array();
$id = false;
foreach ($elements as $element) {
- if ($element{0} == '.') {
+ if ($element[0] == '.') {
$classes[] = substr($element, 1);
- } else if ($element{0} == '#') {
+ } else if ($element[0] == '#') {
if ($id === false) $id = substr($element, 1);
}
}
@@ -1955,7 +1955,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Check for: Indented code block.
#
- else if ($tag{0} == "\n" || $tag{0} == " ") {
+ else if ($tag[0] == "\n" || $tag[0] == " ") {
# Indented code block: pass it unchanged, will be handled
# later.
$parsed .= $tag;
@@ -1964,7 +1964,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Check for: Code span marker
# Note: need to check this after backtick fenced code blocks
#
- else if ($tag{0} == "`") {
+ else if ($tag[0] == "`") {
# Find corresponding end marker.
$tag_re = preg_quote($tag);
if (preg_match('{^(?>.+?|\n(?!\n))*?(?<!`)'.$tag_re.'(?!`)}',
@@ -2002,7 +2002,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# HTML Comments, processing instructions.
#
else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
- $tag{1} == '!' || $tag{1} == '?')
+ $tag[1] == '!' || $tag[1] == '?')
{
# Need to parse tag and following text using the HTML parser.
# (don't check for markdown attribute)
@@ -2021,8 +2021,8 @@ class MarkdownExtra_Parser extends Markdown_Parser {
#
# Increase/decrease nested tag count.
#
- if ($tag{1} == '/') $depth--;
- else if ($tag{strlen($tag)-2} != '/') $depth++;
+ if ($tag[1] == '/') $depth--;
+ else if ($tag[strlen($tag)-2] != '/') $depth++;
if ($depth < 0) {
#
@@ -2126,7 +2126,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# first character as filtered to prevent an infinite loop in the
# parent function.
#
- return array($original_text{0}, substr($original_text, 1));
+ return array($original_text[0], substr($original_text, 1));
}
$block_text .= $parts[0]; # Text before current tag.
@@ -2138,7 +2138,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# Comments and Processing Instructions.
#
if (preg_match('{^</?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
- $tag{1} == '!' || $tag{1} == '?')
+ $tag[1] == '!' || $tag[1] == '?')
{
# Just add the tag to the block as if it was text.
$block_text .= $tag;
@@ -2149,8 +2149,8 @@ class MarkdownExtra_Parser extends Markdown_Parser {
# the tag's name match base tag's.
#
if (preg_match('{^</?'.$base_tag_name_re.'\b}', $tag)) {
- if ($tag{1} == '/') $depth--;
- else if ($tag{strlen($tag)-2} != '/') $depth++;
+ if ($tag[1] == '/') $depth--;
+ else if ($tag[strlen($tag)-2] != '/') $depth++;
}
#
@@ -2508,7 +2508,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
function _doHeaders_callback_setext($matches) {
if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
return $matches[0];
- $level = $matches[3]{0} == '=' ? 1 : 2;
+ $level = $matches[3][0] == '=' ? 1 : 2;
$attr = $this->doExtraAttributes("h$level", $dummy =& $matches[2]);
$block = "<h$level$attr>".$this->runSpanGamut($matches[1])."</h$level>";
return "\n" . $this->hashBlock($block) . "\n\n";
@@ -2826,7 +2826,7 @@ class MarkdownExtra_Parser extends Markdown_Parser {
array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock);
if ($classname != "") {
- if ($classname{0} == '.')
+ if ($classname[0] == '.')
$classname = substr($classname, 1);
$attr_str = ' class="'.$this->code_class_prefix.$classname.'"';
} else {
diff --git a/plugins/jetpack/_inc/lib/markdown/gfm.php b/plugins/jetpack/_inc/lib/markdown/gfm.php
index 081e1a11..c382b427 100644
--- a/plugins/jetpack/_inc/lib/markdown/gfm.php
+++ b/plugins/jetpack/_inc/lib/markdown/gfm.php
@@ -389,7 +389,7 @@ class WPCom_GHF_Markdown_Parser extends MarkdownExtra_Parser {
$classname =& $matches[2];
$codeblock = preg_replace_callback('/^\n+/', array( $this, '_doFencedCodeBlocks_newlines' ), $matches[4] );
- if ( $classname{0} == '.' )
+ if ( $classname[0] == '.' )
$classname = substr( $classname, 1 );
$codeblock = esc_html( $codeblock );
diff --git a/plugins/jetpack/_inc/lib/plans.php b/plugins/jetpack/_inc/lib/plans.php
new file mode 100644
index 00000000..1fa3503e
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/plans.php
@@ -0,0 +1,75 @@
+<?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
+/**
+ * Plans Library
+ *
+ * Fetch plans data from WordPress.com.
+ *
+ * Not to be confused with the `Jetpack_Plan` (singular)
+ * class, which stores and syncs data about the site's _current_ plan.
+ *
+ * @package Jetpack
+ */
+class Jetpack_Plans {
+ /**
+ * Get a list of all available plans from WordPress.com
+ *
+ * @since 7.7.0
+ *
+ * @return array The plans list
+ */
+ public static function get_plans() {
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ if ( ! class_exists( 'Store_Product_List' ) ) {
+ require WP_CONTENT_DIR . '/admin-plugins/wpcom-billing/store-product-list.php';
+ }
+
+ return Store_Product_List::get_active_plans_v1_5();
+ }
+
+ // We're on Jetpack, so it's safe to use this namespace.
+ $request = Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user(
+ '/plans?_locale=' . get_user_locale(),
+ // We're using version 1.5 of the endpoint rather than the default version 2
+ // since the latter only returns Jetpack Plans, but we're also interested in
+ // WordPress.com plans, for consumers of this method that run on WP.com.
+ '1.5',
+ array(
+ 'method' => 'GET',
+ 'headers' => array(
+ 'X-Forwarded-For' => Jetpack::current_user_ip( true ),
+ ),
+ ),
+ null,
+ 'rest'
+ );
+
+ $body = wp_remote_retrieve_body( $request );
+ if ( 200 === wp_remote_retrieve_response_code( $request ) ) {
+ return json_decode( $body );
+ } else {
+ return $body;
+ }
+ }
+
+ /**
+ * Get plan information for a plan given its slug
+ *
+ * @since 7.7.0
+ *
+ * @param string $plan_slug Plan slug.
+ *
+ * @return object The plan object
+ */
+ public static function get_plan( $plan_slug ) {
+ $plans = self::get_plans();
+ if ( ! is_array( $plans ) ) {
+ return;
+ }
+
+ foreach ( $plans as $plan ) {
+ if ( $plan_slug === $plan->product_slug ) {
+ return $plan;
+ }
+ }
+ }
+}
diff --git a/plugins/jetpack/_inc/lib/tonesque.php b/plugins/jetpack/_inc/lib/tonesque.php
index 17158e3d..0e148e5c 100644
--- a/plugins/jetpack/_inc/lib/tonesque.php
+++ b/plugins/jetpack/_inc/lib/tonesque.php
@@ -1,13 +1,13 @@
<?php
/*
Plugin Name: Tonesque
-Plugin URI: http://automattic.com/
+Plugin URI: https://automattic.com/
Description: Grab an average color representation from an image.
Version: 1.0
Author: Automattic, Matias Ventura
-Author URI: http://automattic.com/
+Author URI: https://automattic.com/
License: GNU General Public License v2 or later
-License URI: http://www.gnu.org/licenses/gpl-2.0.html
+License URI: https://www.gnu.org/licenses/gpl-2.0.html
*/
class Tonesque {
@@ -203,13 +203,13 @@ class Tonesque {
switch ( $type ) {
case 'rgb' :
- $color = implode( $c->toRgbInt(), ',' );
+ $color = implode( ',', $c->toRgbInt() );
break;
case 'hex' :
$color = $c->toHex();
break;
case 'hsv' :
- $color = implode( $c->toHsvInt(), ',' );
+ $color = implode( ',', $c->toHsvInt() );
break;
default:
return $color = $c->toHex();
@@ -231,7 +231,7 @@ class Tonesque {
return false;
$c = $this->color->getMaxContrastColor();
- return implode( $c->toRgbInt(), ',' );
+ return implode( ',', $c->toRgbInt() );
}
};
diff --git a/plugins/jetpack/_inc/lib/tracks/class.tracks-client.php b/plugins/jetpack/_inc/lib/tracks/class.tracks-client.php
deleted file mode 100644
index b83c94f1..00000000
--- a/plugins/jetpack/_inc/lib/tracks/class.tracks-client.php
+++ /dev/null
@@ -1,191 +0,0 @@
-<?php
-
-/**
- * Jetpack_Tracks_Client
- * @autounit nosara tracks-client
- *
- * Send Tracks events on behalf of a user
- *
- * Example Usage:
-```php
- require( dirname(__FILE__).'path/to/tracks/class.tracks-client' );
-
- $result = Jetpack_Tracks_Client::record_event( array(
- '_en' => $event_name, // required
- '_ui' => $user_id, // required unless _ul is provided
- '_ul' => $user_login, // required unless _ui is provided
-
- // Optional, but recommended
- '_ts' => $ts_in_ms, // Default: now
- '_via_ip' => $client_ip, // we use it for geo, etc.
-
- // Possibly useful to set some context for the event
- '_via_ua' => $client_user_agent,
- '_via_url' => $client_url,
- '_via_ref' => $client_referrer,
-
- // For user-targeted tests
- 'abtest_name' => $abtest_name,
- 'abtest_variation' => $abtest_variation,
-
- // Your application-specific properties
- 'custom_property' => $some_value,
- ) );
-
- if ( is_wp_error( $result ) ) {
- // Handle the error in your app
- }
-```
- */
-
-require_once( dirname(__FILE__).'/class.tracks-client.php' );
-
-class Jetpack_Tracks_Client {
- const PIXEL = 'https://pixel.wp.com/t.gif';
- const BROWSER_TYPE = 'php-agent';
- const USER_AGENT_SLUG = 'tracks-client';
- const VERSION = '0.3';
-
- /**
- * record_event
- * @param mixed $event Event object to send to Tracks. An array will be cast to object. Required.
- * Properties are included directly in the pixel query string after light validation.
- * @return mixed True on success, WP_Error on failure
- */
- static function record_event( $event ) {
- if ( ! Jetpack::jetpack_tos_agreed() || ! empty( $_COOKIE['tk_opt-out'] ) ) {
- return false;
- }
-
- if ( ! $event instanceof Jetpack_Tracks_Event ) {
- $event = new Jetpack_Tracks_Event( $event );
- }
- if ( is_wp_error( $event ) ) {
- return $event;
- }
-
- $pixel = $event->build_pixel_url( $event );
-
- if ( ! $pixel ) {
- return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 );
- }
-
- return self::record_pixel( $pixel );
- }
-
- /**
- * Synchronously request the pixel
- */
- static function record_pixel( $pixel ) {
- // Add the Request Timestamp and URL terminator just before the HTTP request.
- $pixel .= '&_rt=' . self::build_timestamp() . '&_=_';
-
- $response = wp_remote_get( $pixel, array(
- 'blocking' => true, // The default, but being explicit here :)
- 'timeout' => 1,
- 'redirection' => 2,
- 'httpversion' => '1.1',
- 'user-agent' => self::get_user_agent(),
- ) );
-
- if ( is_wp_error( $response ) ) {
- return $response;
- }
-
- $code = isset( $response['response']['code'] ) ? $response['response']['code'] : 0;
-
- if ( $code !== 200 ) {
- return new WP_Error( 'request_failed', 'Tracks pixel request failed', $code );
- }
-
- return true;
- }
-
- static function get_user_agent() {
- return Jetpack_Tracks_Client::USER_AGENT_SLUG . '-v' . Jetpack_Tracks_Client::VERSION;
- }
-
- /**
- * Build an event and return its tracking URL
- * @deprecated Call the `build_pixel_url` method on a Jetpack_Tracks_Event object instead.
- * @param array $event Event keys and values
- * @return string URL of a tracking pixel
- */
- static function build_pixel_url( $event ) {
- $_event = new Jetpack_Tracks_Event( $event );
- return $_event->build_pixel_url();
- }
-
- /**
- * Validate input for a tracks event.
- * @deprecated Instantiate a Jetpack_Tracks_Event object instead
- * @param array $event Event keys and values
- * @return mixed Validated keys and values or WP_Error on failure
- */
- private static function validate_and_sanitize( $event ) {
- $_event = new Jetpack_Tracks_Event( $event );
- if ( is_wp_error( $_event ) ) {
- return $_event;
- }
- return get_object_vars( $_event );
- }
-
- // Milliseconds since 1970-01-01
- static function build_timestamp() {
- $ts = round( microtime( true ) * 1000 );
- return number_format( $ts, 0, '', '' );
- }
-
- /**
- * Grabs the user's anon id from cookies, or generates and sets a new one
- *
- * @return string An anon id for the user
- */
- static function get_anon_id() {
- static $anon_id = null;
-
- if ( ! isset( $anon_id ) ) {
-
- // Did the browser send us a cookie?
- if ( isset( $_COOKIE[ 'tk_ai' ] ) && preg_match( '#^[A-Za-z0-9+/=]{24}$#', $_COOKIE[ 'tk_ai' ] ) ) {
- $anon_id = $_COOKIE[ 'tk_ai' ];
- } else {
-
- $binary = '';
-
- // Generate a new anonId and try to save it in the browser's cookies
- // Note that base64-encoding an 18 character string generates a 24-character anon id
- for ( $i = 0; $i < 18; ++$i ) {
- $binary .= chr( mt_rand( 0, 255 ) );
- }
-
- $anon_id = 'jetpack:' . base64_encode( $binary );
-
- if ( ! headers_sent()
- && ! ( defined( 'REST_REQUEST' ) && REST_REQUEST )
- && ! ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST )
- ) {
- setcookie( 'tk_ai', $anon_id );
- }
- }
- }
-
- return $anon_id;
- }
-
- /**
- * Gets the WordPress.com user's Tracks identity, if connected.
- *
- * @return array|bool
- */
- static function get_connected_user_tracks_identity() {
- if ( ! $user_data = Jetpack::get_connected_user_data() ) {
- return false;
- }
-
- return array(
- 'userid' => $user_data['ID'],
- 'username' => $user_data['login'],
- );
- }
-}
diff --git a/plugins/jetpack/_inc/lib/tracks/class.tracks-event.php b/plugins/jetpack/_inc/lib/tracks/class.tracks-event.php
deleted file mode 100644
index fb86e0ba..00000000
--- a/plugins/jetpack/_inc/lib/tracks/class.tracks-event.php
+++ /dev/null
@@ -1,149 +0,0 @@
-<?php
-
-/**
- * @autounit nosara tracks-client
- *
- * Example Usage:
-```php
- require_once( dirname(__FILE__) . 'path/to/tracks/class.tracks-event' );
-
- $event = new Jetpack_Tracks_Event( array(
- '_en' => $event_name, // required
- '_ui' => $user_id, // required unless _ul is provided
- '_ul' => $user_login, // required unless _ui is provided
-
- // Optional, but recommended
- '_via_ip' => $client_ip, // for geo, etc.
-
- // Possibly useful to set some context for the event
- '_via_ua' => $client_user_agent,
- '_via_url' => $client_url,
- '_via_ref' => $client_referrer,
-
- // For user-targeted tests
- 'abtest_name' => $abtest_name,
- 'abtest_variation' => $abtest_variation,
-
- // Your application-specific properties
- 'custom_property' => $some_value,
- ) );
-
- if ( is_wp_error( $event->error ) ) {
- // Handle the error in your app
- }
-
- $bump_and_redirect_pixel = $event->build_signed_pixel_url();
-```
- */
-
-require_once( dirname(__FILE__) . '/class.tracks-client.php' );
-
-class Jetpack_Tracks_Event {
- const EVENT_NAME_REGEX = '/^(([a-z0-9]+)_){2}([a-z0-9_]+)$/';
- const PROP_NAME_REGEX = '/^[a-z_][a-z0-9_]*$/';
- public $error;
-
- function __construct( $event ) {
- $_event = self::validate_and_sanitize( $event );
- if ( is_wp_error( $_event ) ) {
- $this->error = $_event;
- return;
- }
-
- foreach( $_event as $key => $value ) {
- $this->{$key} = $value;
- }
- }
-
- function record() {
- return Jetpack_Tracks_Client::record_event( $this );
- }
-
- /**
- * Annotate the event with all relevant info.
- * @param mixed $event Object or (flat) array
- * @return mixed The transformed event array or WP_Error on failure.
- */
- static function validate_and_sanitize( $event ) {
- $event = (object) $event;
-
- // Required
- if ( ! $event->_en ) {
- return new WP_Error( 'invalid_event', 'A valid event must be specified via `_en`', 400 );
- }
-
- // delete non-routable addresses otherwise geoip will discard the record entirely
- if ( property_exists( $event, '_via_ip' ) && preg_match( '/^192\.168|^10\./', $event->_via_ip ) ) {
- unset($event->_via_ip);
- }
-
- $validated = array(
- 'browser_type' => Jetpack_Tracks_Client::BROWSER_TYPE,
- '_aua' => Jetpack_Tracks_Client::get_user_agent(),
- );
-
- $_event = (object) array_merge( (array) $event, $validated );
-
- // If you want to blacklist property names, do it here.
-
- // Make sure we have an event timestamp.
- if ( ! isset( $_event->_ts ) ) {
- $_event->_ts = Jetpack_Tracks_Client::build_timestamp();
- }
-
- return $_event;
- }
-
- /**
- * Build a pixel URL that will send a Tracks event when fired.
- * On error, returns an empty string ('').
- *
- * @return string A pixel URL or empty string ('') if there were invalid args.
- */
- function build_pixel_url() {
- if ( $this->error ) {
- return '';
- }
-
- $args = get_object_vars( $this );
-
- // Request Timestamp and URL Terminator must be added just before the HTTP request or not at all.
- unset( $args['_rt'] );
- unset( $args['_'] );
-
- $validated = self::validate_and_sanitize( $args );
-
- if ( is_wp_error( $validated ) )
- return '';
-
- return Jetpack_Tracks_Client::PIXEL . '?' . http_build_query( $validated );
- }
-
- static function event_name_is_valid( $name ) {
- return preg_match( Jetpack_Tracks_Event::EVENT_NAME_REGEX, $name );
- }
-
- static function prop_name_is_valid( $name ) {
- return preg_match( Jetpack_Tracks_Event::PROP_NAME_REGEX, $name );
- }
-
- static function scrutinize_event_names( $event ) {
- if ( ! Jetpack_Tracks_Event::event_name_is_valid( $event->_en ) ) {
- return;
- }
-
- $whitelisted_key_names = array(
- 'anonId',
- 'Browser_Type',
- );
-
- foreach ( array_keys( (array) $event ) as $key ) {
- if ( in_array( $key, $whitelisted_key_names ) ) {
- continue;
- }
- if ( ! Jetpack_Tracks_Event::prop_name_is_valid( $key ) ) {
- return;
- }
- }
- }
-}
diff --git a/plugins/jetpack/_inc/lib/tracks/client.php b/plugins/jetpack/_inc/lib/tracks/client.php
deleted file mode 100644
index bd92d272..00000000
--- a/plugins/jetpack/_inc/lib/tracks/client.php
+++ /dev/null
@@ -1,130 +0,0 @@
-<?php
-/**
- * PHP Tracks Client
- * @autounit nosara tracks-client
- * Example Usage:
- *
-```php
- include( plugin_dir_path( __FILE__ ) . 'lib/tracks/client.php');
- $result = jetpack_tracks_record_event( $user, $event_name, $properties );
-
- if ( is_wp_error( $result ) ) {
- // Handle the error in your app
- }
-```
- */
-
-// Load the client classes
-require_once( dirname(__FILE__) . '/class.tracks-event.php' );
-require_once( dirname(__FILE__) . '/class.tracks-client.php' );
-
-// Now, let's export a sprinkling of syntactic sugar!
-
-/**
- * Procedurally (vs. Object-oriented), track an event object (or flat array)
- * NOTE: Use this only when the simpler jetpack_tracks_record_event() function won't work for you.
- * @param \Jetpack_Tracks_Event $event The event object.
- * @return \Jetpack_Tracks_Event|\WP_Error
- */
-function jetpack_tracks_record_event_raw( $event ) {
- return Jetpack_Tracks_Client::record_event( $event );
-}
-
-/**
- * Procedurally build a Tracks Event Object.
- * NOTE: Use this only when the simpler jetpack_tracks_record_event() function won't work for you.
- * @param $identity WP_user object
- * @param string $event_name The name of the event
- * @param array $properties Custom properties to send with the event
- * @param int $event_timestamp_millis The time in millis since 1970-01-01 00:00:00 when the event occurred
- * @return \Jetpack_Tracks_Event|\WP_Error
- */
-function jetpack_tracks_build_event_obj( $user, $event_name, $properties = array(), $event_timestamp_millis = false ) {
-
- $identity = jetpack_tracks_get_identity( $user->ID );
-
- $properties['user_lang'] = $user->get( 'WPLANG' );
-
- $blog_details = array(
- 'blog_lang' => isset( $properties['blog_lang'] ) ? $properties['blog_lang'] : get_bloginfo( 'language' )
- );
-
- $timestamp = ( $event_timestamp_millis !== false ) ? $event_timestamp_millis : round( microtime( true ) * 1000 );
- $timestamp_string = is_string( $timestamp ) ? $timestamp : number_format( $timestamp, 0, '', '' );
-
- return new Jetpack_Tracks_Event( array_merge( $blog_details, (array) $properties, $identity, array(
- '_en' => $event_name,
- '_ts' => $timestamp_string
- ) ) );
-}
-
-/*
- * Get the identity to send to tracks.
- *
- * @param int $user_id The user id of the local user
- * @return array $identity
- */
-function jetpack_tracks_get_identity( $user_id ) {
-
- // Meta is set, and user is still connected. Use WPCOM ID
- $wpcom_id = get_user_meta( $user_id, 'jetpack_tracks_wpcom_id', true );
- if ( $wpcom_id && Jetpack::is_user_connected( $user_id ) ) {
- return array(
- '_ut' => 'wpcom:user_id',
- '_ui' => $wpcom_id
- );
- }
-
- // User is connected, but no meta is set yet. Use WPCOM ID and set meta.
- if ( Jetpack::is_user_connected( $user_id ) ) {
- $wpcom_user_data = Jetpack::get_connected_user_data( $user_id );
- update_user_meta( $user_id, 'jetpack_tracks_wpcom_id', $wpcom_user_data['ID'] );
-
- return array(
- '_ut' => 'wpcom:user_id',
- '_ui' => $wpcom_user_data['ID']
- );
- }
-
- // User isn't linked at all. Fall back to anonymous ID.
- $anon_id = get_user_meta( $user_id, 'jetpack_tracks_anon_id', true );
- if ( ! $anon_id ) {
- $anon_id = Jetpack_Tracks_Client::get_anon_id();
- add_user_meta( $user_id, 'jetpack_tracks_anon_id', $anon_id, false );
- }
-
- if ( ! isset( $_COOKIE[ 'tk_ai' ] ) && ! headers_sent() ) {
- setcookie( 'tk_ai', $anon_id );
- }
-
- return array(
- '_ut' => 'anon',
- '_ui' => $anon_id
- );
-
-}
-
-/**
- * Record an event in Tracks - this is the preferred way to record events from PHP.
- *
- * @param mixed $identity username, user_id, or WP_user object
- * @param string $event_name The name of the event
- * @param array $properties Custom properties to send with the event
- * @param int $event_timestamp_millis The time in millis since 1970-01-01 00:00:00 when the event occurred
- * @return bool true for success | \WP_Error if the event pixel could not be fired
- */
-function jetpack_tracks_record_event( $user, $event_name, $properties = array(), $event_timestamp_millis = false ) {
-
- // We don't want to track user events during unit tests/CI runs.
- if ( $user instanceof WP_User && 'wptests_capabilities' === $user->cap_key ) {
- return false;
- }
-
- $event_obj = jetpack_tracks_build_event_obj( $user, $event_name, $properties, $event_timestamp_millis );
-
- if ( is_wp_error( $event_obj->error ) ) {
- return $event_obj->error;
- }
-
- return $event_obj->record();
-}
diff --git a/plugins/jetpack/_inc/lib/tracks/tracks-ajax.js b/plugins/jetpack/_inc/lib/tracks/tracks-ajax.js
index 911275bd..98a9aaac 100644
--- a/plugins/jetpack/_inc/lib/tracks/tracks-ajax.js
+++ b/plugins/jetpack/_inc/lib/tracks/tracks-ajax.js
@@ -1,7 +1,7 @@
/* global jpTracksAJAX, jQuery */
( function( $, jpTracksAJAX ) {
window.jpTracksAJAX = window.jpTracksAJAX || {};
- const debugSet = localStorage.getItem( 'debug' ) === 'dops:analytics';
+ var debugSet = localStorage.getItem( 'debug' ) === 'dops:analytics';
window.jpTracksAJAX.record_ajax_event = function( eventName, eventType, eventProp ) {
var data = {
diff --git a/plugins/jetpack/_inc/lib/tracks/tracks-callables.js b/plugins/jetpack/_inc/lib/tracks/tracks-callables.js
index d4e53af6..4e033d2c 100644
--- a/plugins/jetpack/_inc/lib/tracks/tracks-callables.js
+++ b/plugins/jetpack/_inc/lib/tracks/tracks-callables.js
@@ -8,6 +8,9 @@
// Load tracking scripts
window._tkq = window._tkq || [];
+var _user;
+var debug = console.error; // eslint-disable-line no-console
+
function buildQuerystring( group, name ) {
var uriComponent = '';
diff --git a/plugins/jetpack/_inc/lib/widgets.php b/plugins/jetpack/_inc/lib/widgets.php
index 3f072b75..8bdd7b76 100644
--- a/plugins/jetpack/_inc/lib/widgets.php
+++ b/plugins/jetpack/_inc/lib/widgets.php
@@ -557,11 +557,15 @@ class Jetpack_Widgets {
// Add a Tracks event for non-Headstart activity.
if ( ! defined( 'HEADSTART' ) ) {
- jetpack_require_lib( 'tracks/client' );
- jetpack_tracks_record_event( wp_get_current_user(), 'wpcom_widgets_activate_widget', array(
- 'widget' => $id_base,
- 'settings' => json_encode( $settings ),
- ) );
+ $tracking = new Automattic\Jetpack\Tracking();
+ $tracking->tracks_record_event(
+ wp_get_current_user(),
+ 'wpcom_widgets_activate_widget',
+ array(
+ 'widget' => $id_base,
+ 'settings' => wp_json_encode( $settings ),
+ )
+ );
}
return self::get_widget_by_id( $widget_id );