updated plugin Jetpack Protect version 4.0.0

This commit is contained in:
2025-04-29 21:19:56 +00:00
committed by Gitium
parent eb9181b250
commit ebd40ef928
265 changed files with 11864 additions and 3987 deletions

View File

@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 4.0.0 - 2025-03-24
### Changed
- Scanner: add threat count to tab [#40056]
- Scanner: animated the "scan in progress" placeholder image [#39825]
- General: indicate compatibility with the upcoming version of WordPress - 6.7. [#39786]
- General: Update package dependencies. [#42511]
### Removed
- Firewall: removed "new" badge from tab. [#41902]
- General: Update minimum PHP version to 7.2. [#40147]
- General: Update minimum WordPress version to 6.6. [#40146]
## 3.1.1 - 2024-10-17
### Changed
- Firewall: Fix backwards compatibility for sites running standalone mode with outdated packages autoloaded.
## 3.1.0 - 2024-10-15
### Added
- Firewall: Adds stat cards showing recent block counts [#35739]
- Auto-Fixers: Adds handling for long-running fixers [#39301]
### Changed
- Firewall: added help text for IP list formatting rules [#39448]
- Updated package dependencies. [#39707]
### Removed
- Security Scanning: disabled database threat category [#39467]
### Fixed
- Minor fixes and improvements.
## 3.0.2 - 2024-09-06 ## 3.0.2 - 2024-09-06
### Changed ### Changed
- Internal updates. - Internal updates.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1 +1 @@
<?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'moment', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '8d3412963d3c47f0ac0a'); <?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'moment', 'react', 'react-dom', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '5a27a9f58fb4802d8a58');

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,7 +7,7 @@
*/ */
/** /**
* React Router DOM v6.2.2 * @remix-run/router v1.21.0
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *
@ -18,7 +18,18 @@
*/ */
/** /**
* React Router v6.2.2 * React Router DOM v6.28.1
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router v6.28.1
* *
* Copyright (c) Remix Software Inc. * Copyright (c) Remix Software Inc.
* *

File diff suppressed because one or more lines are too long

View File

@ -5,24 +5,24 @@
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"automattic/jetpack-assets": "^2.3.7", "automattic/jetpack-assets": "^4.0.14",
"automattic/jetpack-admin-ui": "^0.4.5", "automattic/jetpack-admin-ui": "^0.5.7",
"automattic/jetpack-autoloader": "^3.1.0", "automattic/jetpack-autoloader": "^5.0.5",
"automattic/jetpack-composer-plugin": "^2.0.3", "automattic/jetpack-composer-plugin": "^4.0.4",
"automattic/jetpack-config": "^2.0.4", "automattic/jetpack-config": "^3.0.1",
"automattic/jetpack-my-jetpack": "^4.35.3", "automattic/jetpack-my-jetpack": "^5.9.1",
"automattic/jetpack-plugins-installer": "^0.4.3", "automattic/jetpack-plugins-installer": "^0.5.4",
"automattic/jetpack-sync": "^3.10.0", "automattic/jetpack-sync": "^4.9.2",
"automattic/jetpack-transport-helper": "^0.2.4", "automattic/jetpack-transport-helper": "^0.3.1",
"automattic/jetpack-plans": "^0.4.10", "automattic/jetpack-plans": "^0.6.1",
"automattic/jetpack-waf": "^0.18.5", "automattic/jetpack-waf": "^0.23.8",
"automattic/jetpack-status": "^4.0.1", "automattic/jetpack-status": "^5.0.10",
"automattic/jetpack-protect-status": "^0.1.5" "automattic/jetpack-protect-status": "^0.5.8"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"automattic/wordbless": "0.4.2" "automattic/phpunit-select-config": "^1.0.1"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -31,7 +31,10 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -45,9 +48,7 @@
"watch": [ "watch": [
"Composer\\Config::disableProcessTimeout", "Composer\\Config::disableProcessTimeout",
"pnpm run watch" "pnpm run watch"
], ]
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
}, },
"repositories": [], "repositories": [],
"minimum-stability": "dev", "minimum-stability": "dev",
@ -71,6 +72,6 @@
"automattic/jetpack-autoloader": true, "automattic/jetpack-autoloader": true,
"automattic/jetpack-composer-plugin": true "automattic/jetpack-composer-plugin": true
}, },
"autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ3_0_2" "autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ4_0_0"
} }
} }

View File

@ -3,7 +3,7 @@
* Plugin Name: Jetpack Protect * Plugin Name: Jetpack Protect
* Plugin URI: https://wordpress.org/plugins/jetpack-protect * Plugin URI: https://wordpress.org/plugins/jetpack-protect
* Description: Security tools that keep your site safe and sound, from posts to plugins. * Description: Security tools that keep your site safe and sound, from posts to plugins.
* Version: 3.0.2 * Version: 4.0.0
* Author: Automattic - Jetpack Security team * Author: Automattic - Jetpack Security team
* Author URI: https://jetpack.com/protect/ * Author URI: https://jetpack.com/protect/
* License: GPLv2 or later * License: GPLv2 or later
@ -29,10 +29,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit( 0 );
} }
define( 'JETPACK_PROTECT_VERSION', '3.0.2' ); define( 'JETPACK_PROTECT_VERSION', '4.0.0' );
define( 'JETPACK_PROTECT_DIR', plugin_dir_path( __FILE__ ) ); define( 'JETPACK_PROTECT_DIR', plugin_dir_path( __FILE__ ) );
define( 'JETPACK_PROTECT_ROOT_FILE', __FILE__ ); define( 'JETPACK_PROTECT_ROOT_FILE', __FILE__ );
define( 'JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH', plugin_basename( __FILE__ ) ); define( 'JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH', plugin_basename( __FILE__ ) );
@ -118,7 +118,7 @@ function jetpack_protect_plugin_activation( $plugin ) {
( new \Automattic\Jetpack\Paths() )->is_current_request_activating_plugin_from_plugins_screen( JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH ) ( new \Automattic\Jetpack\Paths() )->is_current_request_activating_plugin_from_plugins_screen( JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH )
) { ) {
wp_safe_redirect( esc_url( admin_url( 'admin.php?page=jetpack-protect' ) ) ); wp_safe_redirect( esc_url( admin_url( 'admin.php?page=jetpack-protect' ) ) );
exit; exit( 0 );
} }
} }

View File

@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.0.4] - 2025-03-21
### Changed
- Internal updates.
## [3.0.3] - 2025-03-12
### Changed
- Internal updates.
## [3.0.2] - 2025-03-05
### Changed
- Internal updates.
## [3.0.1] - 2025-02-24
### Changed
- Update dependencies.
## [3.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [2.0.4] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [2.0.3] - 2024-09-30
### Fixed
- Added a check for function presence to avoid fatal errors. [#39581]
## [2.0.2] - 2024-08-23 ## [2.0.2] - 2024-08-23
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -139,6 +167,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Creates the MC Stats package - Creates the MC Stats package
[3.0.4]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.3...v3.0.4
[3.0.3]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.2...v3.0.3
[3.0.2]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.1...v3.0.2
[3.0.1]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v3.0.0...v3.0.1
[3.0.0]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.4...v3.0.0
[2.0.4]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.3...v2.0.4
[2.0.3]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.1...v2.0.2 [2.0.2]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.1...v2.0.2
[2.0.1]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.0...v2.0.1 [2.0.1]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v2.0.0...v2.0.1
[2.0.0]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v1.4.22...v2.0.0 [2.0.0]: https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v1.4.22...v2.0.0

View File

@ -4,11 +4,12 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -20,7 +21,10 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -35,7 +39,7 @@
"link-template": "https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-a8c-mc-stats/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "2.0.x-dev" "dev-trunk": "3.0.x-dev"
} }
} }
} }

View File

@ -158,7 +158,8 @@ class A8c_Mc_Stats {
public function build_stats_url( $args ) { public function build_stats_url( $args ) {
$defaults = array( $defaults = array(
'v' => 'wpcom2', 'v' => 'wpcom2',
'rand' => md5( wp_rand( 0, 999 ) . time() ), // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_rand -- There can be a case where pluggables are not yet loaded.
'rand' => md5( ( function_exists( 'wp_rand' ) ? wp_rand( 0, 999 ) : rand( 0, 999 ) ) . time() ),
); );
$args = wp_parse_args( $args, $defaults ); $args = wp_parse_args( $args, $defaults );
$gifname = true === $this->use_transparent_pixel ? 'b.gif' : 'g.gif'; $gifname = true === $this->use_transparent_pixel ? 'b.gif' : 'g.gif';

View File

@ -5,6 +5,42 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.5.7] - 2025-03-21
### Changed
- Internal updates.
## [0.5.6] - 2025-03-17
### Changed
- Internal updates.
## [0.5.5] - 2025-03-12
### Changed
- Internal updates.
## [0.5.4] - 2025-03-05
### Changed
- Internal updates.
## [0.5.3] - 2025-02-24
### Changed
- Update dependencies.
## [0.5.2] - 2025-02-03
### Added
- Add `remove_menu` method to `Admin_Menu` class. [#41422]
## [0.5.1] - 2024-11-25
### Changed
- Update dependencies. [#40286]
## [0.5.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.4.6] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [0.4.5] - 2024-09-05 ## [0.4.5] - 2024-09-05
### Changed ### Changed
- Jetpack menu: only register Jetpack admin page for contributor roles and above. [#39081] - Jetpack menu: only register Jetpack admin page for contributor roles and above. [#39081]
@ -160,6 +196,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Fixing menu visibility issues. - Fixing menu visibility issues.
[0.5.7]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.6...0.5.7
[0.5.6]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.5...0.5.6
[0.5.5]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.4...0.5.5
[0.5.4]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.3...0.5.4
[0.5.3]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.2...0.5.3
[0.5.2]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.1...0.5.2
[0.5.1]: https://github.com/Automattic/jetpack-admin-ui/compare/0.5.0...0.5.1
[0.5.0]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.6...0.5.0
[0.4.6]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.5...0.4.6
[0.4.5]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.4...0.4.5 [0.4.5]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.4...0.4.5
[0.4.4]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.3...0.4.4 [0.4.4]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.3...0.4.4
[0.4.3]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.2...0.4.3 [0.4.3]: https://github.com/Automattic/jetpack-admin-ui/compare/0.4.2...0.4.3

View File

@ -4,13 +4,14 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"automattic/jetpack-logo": "^2.0.4", "automattic/jetpack-logo": "^3.0.4",
"automattic/wordbless": "dev-master" "automattic/jetpack-test-environment": "@dev",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -22,13 +23,14 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
], ]
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
@ -40,7 +42,7 @@
"link-template": "https://github.com/Automattic/jetpack-admin-ui/compare/${old}...${new}" "link-template": "https://github.com/Automattic/jetpack-admin-ui/compare/${old}...${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "0.4.x-dev" "dev-trunk": "0.5.x-dev"
}, },
"version-constants": { "version-constants": {
"::PACKAGE_VERSION": "src/class-admin-menu.php" "::PACKAGE_VERSION": "src/class-admin-menu.php"

View File

@ -13,7 +13,7 @@ namespace Automattic\Jetpack\Admin_UI;
*/ */
class Admin_Menu { class Admin_Menu {
const PACKAGE_VERSION = '0.4.5'; const PACKAGE_VERSION = '0.5.7';
/** /**
* Whether this class has been initialized * Whether this class has been initialized
@ -173,6 +173,26 @@ class Admin_Menu {
return 'jetpack_page_' . $menu_slug; return 'jetpack_page_' . $menu_slug;
} }
/**
* Removes an already added submenu
*
* @param string $menu_slug The slug of the submenu to remove.
*
* @return array|false The removed submenu on success, false if not found.
*/
public static function remove_menu( $menu_slug ) {
foreach ( self::$menu_items as $index => $menu_item ) {
if ( $menu_item['menu_slug'] === $menu_slug ) {
unset( self::$menu_items[ $index ] );
return $menu_item;
}
}
return false;
}
/** /**
* Gets the slug for the first item under the Jetpack top level menu * Gets the slug for the first item under the Jetpack top level menu
* *

View File

@ -1,3 +0,0 @@
module.exports = {
extends: [ require.resolve( 'jetpack-js-tools/eslintrc/react' ) ],
};

View File

@ -5,6 +5,101 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [4.0.14] - 2025-03-21
### Changed
- Internal updates.
## [4.0.13] - 2025-03-18
### Changed
- Update dependencies. [#42545]
## [4.0.12] - 2025-03-17
### Changed
- Internal updates.
## [4.0.11] - 2025-03-12
### Changed
- Internal updates.
## [4.0.10] - 2025-03-05
### Changed
- Internal updates.
## [4.0.9] - 2025-03-03
### Changed
- Update package dependencies. [#42163]
## [4.0.8] - 2025-02-24
### Added
- User data: Add permissions to the current user object. [#41859]
## [4.0.7] - 2025-02-17
### Changed
- Update dependencies.
## [4.0.6] - 2025-02-11
### Changed
- Update dependencies.
## [4.0.5] - 2025-02-05
### Changed
- Updated package dependencies. [#41491]
## [4.0.4] - 2025-02-03
### Changed
- Updated package dependencies. [#41286]
## [4.0.3] - 2025-01-20
### Changed
- Updated package dependencies. [#41099]
## [4.0.2] - 2024-12-16
### Changed
- Updated package dependencies. [#40564]
## [4.0.1] - 2024-12-04
### Changed
- Updated package dependencies. [#40363]
## [4.0.0] - 2024-11-25
### Changed
- Updated package dependencies. [#40258] [#40288]
### Removed
- Remove JSX runtime polyfill, now that we've dropped support for WordPress < 6.6. [#40200]
## [3.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [2.3.14] - 2024-11-11
### Changed
- Updated package dependencies. [#39999]
## [2.3.13] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [2.3.12] - 2024-10-29
### Changed
- Internal updates.
## [2.3.11] - 2024-10-29
### Fixed
- Fixed the outdated JS build for script-data [#39937]
## [2.3.10] - 2024-10-10
### Changed
- Updated package dependencies.
## [2.3.9] - 2024-10-07
### Changed
- Updated package dependencies. [#39594]
## [2.3.8] - 2024-09-10
### Changed
- Updated package dependencies. [#39302]
## [2.3.7] - 2024-09-05 ## [2.3.7] - 2024-09-05
### Changed ### Changed
- Internal updates. - Internal updates.
@ -497,6 +592,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Statically access asset tools - Statically access asset tools
[4.0.14]: https://github.com/Automattic/jetpack-assets/compare/v4.0.13...v4.0.14
[4.0.13]: https://github.com/Automattic/jetpack-assets/compare/v4.0.12...v4.0.13
[4.0.12]: https://github.com/Automattic/jetpack-assets/compare/v4.0.11...v4.0.12
[4.0.11]: https://github.com/Automattic/jetpack-assets/compare/v4.0.10...v4.0.11
[4.0.10]: https://github.com/Automattic/jetpack-assets/compare/v4.0.9...v4.0.10
[4.0.9]: https://github.com/Automattic/jetpack-assets/compare/v4.0.8...v4.0.9
[4.0.8]: https://github.com/Automattic/jetpack-assets/compare/v4.0.7...v4.0.8
[4.0.7]: https://github.com/Automattic/jetpack-assets/compare/v4.0.6...v4.0.7
[4.0.6]: https://github.com/Automattic/jetpack-assets/compare/v4.0.5...v4.0.6
[4.0.5]: https://github.com/Automattic/jetpack-assets/compare/v4.0.4...v4.0.5
[4.0.4]: https://github.com/Automattic/jetpack-assets/compare/v4.0.3...v4.0.4
[4.0.3]: https://github.com/Automattic/jetpack-assets/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/Automattic/jetpack-assets/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/Automattic/jetpack-assets/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/Automattic/jetpack-assets/compare/v3.0.0...v4.0.0
[3.0.0]: https://github.com/Automattic/jetpack-assets/compare/v2.3.14...v3.0.0
[2.3.14]: https://github.com/Automattic/jetpack-assets/compare/v2.3.13...v2.3.14
[2.3.13]: https://github.com/Automattic/jetpack-assets/compare/v2.3.12...v2.3.13
[2.3.12]: https://github.com/Automattic/jetpack-assets/compare/v2.3.11...v2.3.12
[2.3.11]: https://github.com/Automattic/jetpack-assets/compare/v2.3.10...v2.3.11
[2.3.10]: https://github.com/Automattic/jetpack-assets/compare/v2.3.9...v2.3.10
[2.3.9]: https://github.com/Automattic/jetpack-assets/compare/v2.3.8...v2.3.9
[2.3.8]: https://github.com/Automattic/jetpack-assets/compare/v2.3.7...v2.3.8
[2.3.7]: https://github.com/Automattic/jetpack-assets/compare/v2.3.6...v2.3.7 [2.3.7]: https://github.com/Automattic/jetpack-assets/compare/v2.3.6...v2.3.7
[2.3.6]: https://github.com/Automattic/jetpack-assets/compare/v2.3.5...v2.3.6 [2.3.6]: https://github.com/Automattic/jetpack-assets/compare/v2.3.5...v2.3.6
[2.3.5]: https://github.com/Automattic/jetpack-assets/compare/v2.3.4...v2.3.5 [2.3.5]: https://github.com/Automattic/jetpack-assets/compare/v2.3.4...v2.3.5

View File

@ -1 +1 @@
<?php return array('dependencies' => array(), 'version' => '0274966690f87adbeccb'); <?php return array('dependencies' => array(), 'version' => '7f1c9fc474dccfef702f');

View File

@ -1 +1 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JetpackScriptDataModule=t():e.JetpackScriptDataModule=t()}(self,(()=>(()=>{var e={729:(e,t,r)=>{"use strict";r.r(t),r.d(t,{getActiveFeatures:()=>a.mH,getAdminUrl:()=>a.hT,getJetpackAdminPageUrl:()=>a.oQ,getMyJetpackUrl:()=>a.e5,getScriptData:()=>a.au,getSiteData:()=>a.sV});var o=r(428),n={};for(const e in o)"default"!==e&&(n[e]=()=>o[e]);r.d(t,n);var a=r(336)},428:()=>{},336:(e,t,r)=>{"use strict";function o(){return window.JetpackScriptData}function n(){return o().site}function a(e=""){return`${o().site.admin_url}${e}`}function i(e=""){return a(`admin.php?page=jetpack${e}`)}function u(e=""){return a(`admin.php?page=my-jetpack${e}`)}function p(){return o().site.plan?.features?.active??[]}r.d(t,{au:()=>o,e5:()=>u,hT:()=>a,mH:()=>p,oQ:()=>i,sV:()=>n})}},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={exports:{}};return e[o](a,a.exports,r),a.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var o={};return(()=>{"use strict";r.r(o);var e=r(729),t={};for(const r in e)"default"!==r&&(t[r]=()=>e[r]);r.d(o,t)})(),o})())); !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.JetpackScriptDataModule=t():e.JetpackScriptDataModule=t()}(globalThis,(()=>(()=>{"use strict";var e={729:(e,t,r)=>{r.d(t,{$8:()=>n.$8,IT:()=>n.IT,L2:()=>n.L2,Sy:()=>n.Sy,au:()=>n.au,d9:()=>n.d9,d_:()=>n.d_,e5:()=>n.e5,hT:()=>n.hT,lI:()=>n.lI,mH:()=>n.mH,oQ:()=>n.oQ,sV:()=>n.sV});var n=r(336)},336:(e,t,r)=>{function n(){return window.JetpackScriptData}function o(){return n().site}function i(e=""){return`${n().site.admin_url}${e}`}function u(e=""){return i(`admin.php?page=jetpack${e}`)}function a(e=""){return i(`admin.php?page=my-jetpack${e}`)}function c(){return n().site.plan?.features?.active??[]}function s(e){return c().includes(e)}function p(){return"wpcom"===n().site?.host}function d(){return"atomic"===n().site?.host}function f(){return"woa"===n().site?.host}function l(){return p()||f()}function m(){return"unknown"===n()?.site?.host}function S(e){return n().user.current_user.capabilities[e]}r.d(t,{$8:()=>l,IT:()=>s,L2:()=>m,Sy:()=>p,au:()=>n,d9:()=>d,d_:()=>S,e5:()=>a,hT:()=>i,lI:()=>f,mH:()=>c,oQ:()=>u,sV:()=>o})}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};r.r(n),r.d(n,{currentUserCan:()=>o.d_,getActiveFeatures:()=>o.mH,getAdminUrl:()=>o.hT,getJetpackAdminPageUrl:()=>o.oQ,getMyJetpackUrl:()=>o.e5,getScriptData:()=>o.au,getSiteData:()=>o.sV,isAtomicSite:()=>o.d9,isJetpackSelfHostedSite:()=>o.L2,isSimpleSite:()=>o.Sy,isWoASite:()=>o.lI,isWpcomPlatformSite:()=>o.$8,siteHasFeature:()=>o.IT});var o=r(729);return n})()));

View File

@ -1,2 +0,0 @@
/*! For license information please see react-jsx-runtime.js.LICENSE.txt */
(()=>{"use strict";var r={572:(r,e,t)=>{var o=t(609),n=Symbol.for("react.element"),s=Symbol.for("react.fragment"),a=Object.prototype.hasOwnProperty,f=o.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,p={key:!0,ref:!0,__self:!0,__source:!0};function _(r,e,t){var o,s={},_=null,i=null;for(o in void 0!==t&&(_=""+t),void 0!==e.key&&(_=""+e.key),void 0!==e.ref&&(i=e.ref),e)a.call(e,o)&&!p.hasOwnProperty(o)&&(s[o]=e[o]);if(r&&r.defaultProps)for(o in e=r.defaultProps)void 0===s[o]&&(s[o]=e[o]);return{$$typeof:n,type:r,key:_,ref:i,props:s,_owner:f.current}}e.Fragment=s,e.jsx=_,e.jsxs=_},48:(r,e,t)=>{r.exports=t(572)},609:r=>{r.exports=window.React}},e={},t=function t(o){var n=e[o];if(void 0!==n)return n.exports;var s=e[o]={exports:{}};return r[o](s,s.exports,t),s.exports}(48);window.ReactJSXRuntime=t})();

View File

@ -1,9 +0,0 @@
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

View File

@ -4,14 +4,15 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-constants": "^2.0.4" "automattic/jetpack-constants": "^3.0.5"
}, },
"require-dev": { "require-dev": {
"brain/monkey": "2.6.1", "brain/monkey": "^2.6.2",
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0" "wikimedia/testing-access-wrapper": "^1.0 || ^2.0 || ^3.0",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -32,8 +33,9 @@
"pnpm run build-production" "pnpm run build-production"
], ],
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
], ],
"test-coverage": "pnpm concurrently --names php,js 'php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\"' 'pnpm:test-coverage'",
"test-js": [ "test-js": [
"pnpm run test" "pnpm run test"
], ],
@ -51,7 +53,7 @@
"link-template": "https://github.com/Automattic/jetpack-assets/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-assets/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "2.3.x-dev" "dev-trunk": "4.0.x-dev"
} }
} }
} }

View File

@ -537,12 +537,6 @@ class Assets {
$wp_scripts->add( 'wp-jp-i18n-state', false, array( 'wp-deprecated', $handle ) ); $wp_scripts->add( 'wp-jp-i18n-state', false, array( 'wp-deprecated', $handle ) );
$wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.deprecated( "wp-jp-i18n-state", { alternative: "wp-jp-i18n-loader" } );' ); $wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.deprecated( "wp-jp-i18n-state", { alternative: "wp-jp-i18n-loader" } );' );
$wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.jpI18nState = wp.jpI18nLoader.state;' ); $wp_scripts->add_inline_script( 'wp-jp-i18n-state', 'wp.jpI18nState = wp.jpI18nLoader.state;' );
// Register the React JSX runtime script - used as a polyfill until we can update JSX transforms. See https://github.com/Automattic/jetpack/issues/38424.
// @todo Remove this when we drop support for WordPress 6.5, as well as the script inclusion in test_wp_default_scripts_hook.
$jsx_url = self::normalize_path( plugins_url( '../build/react-jsx-runtime.js', __FILE__ ) );
$wp_scripts->add( 'react-jsx-runtime', $jsx_url, array( 'react' ), '18.3.1', true );
$wp_scripts->add_data( 'react-jsx-runtime', 'group', 1 );
} }
// endregion . // endregion .

View File

@ -215,6 +215,10 @@ class Script_Data {
return array( return array(
'display_name' => $current_user->display_name, 'display_name' => $current_user->display_name,
'id' => $current_user->ID, 'id' => $current_user->ID,
'capabilities' => array(
'manage_options' => current_user_can( 'manage_options' ),
'manage_modules' => current_user_can( 'jetpack_manage_modules' ),
),
); );
} }
} }

View File

@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.6] - 2025-03-24
### Changed
- Internal updates.
## [0.3.5] - 2025-03-12
### Changed
- Internal updates.
## [0.3.4] - 2025-03-10
### Changed
- Internal updates.
## [0.3.3] - 2025-02-24
### Changed
- Update dependencies.
## [0.3.2] - 2025-02-03
### Changed
- Internal updates.
## [0.3.1] - 2024-11-25
### Changed
- Update dependencies. [#40286]
## [0.3.0] - 2024-11-14
### Changed
- Backup: Add next daily backup schedule time on admin page. [#39914]
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.2.8] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [0.2.7] - 2024-08-26 ## [0.2.7] - 2024-08-26
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -41,6 +76,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed ### Fixed
- Initial release (improved helper script installer logging). [#34297] - Initial release (improved helper script installer logging). [#34297]
[0.3.6]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.5...v0.3.6
[0.3.5]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.4...v0.3.5
[0.3.4]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.8...v0.3.0
[0.2.8]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.7...v0.2.8
[0.2.7]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.6...v0.2.7 [0.2.7]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.6...v0.2.7
[0.2.6]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.5...v0.2.6 [0.2.6]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.5...v0.2.6
[0.2.5]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.4...v0.2.5 [0.2.5]: https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v0.2.4...v0.2.5

View File

@ -4,12 +4,13 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"automattic/wordbless": "@dev" "automattic/jetpack-test-environment": "@dev",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -21,13 +22,14 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
], ]
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
@ -38,7 +40,7 @@
"link-template": "https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-backup-helper-script-manager/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "0.2.x-dev" "dev-trunk": "0.3.x-dev"
} }
}, },
"config": { "config": {

View File

@ -9,7 +9,7 @@
// order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide // order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide
// to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin // to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin
// are installed, or in some other cases). // are installed, or in some other cases).
namespace Automattic\Jetpack\Backup\V0004; namespace Automattic\Jetpack\Backup\V0005;
use Exception; use Exception;
use WP_Error; use WP_Error;

View File

@ -9,7 +9,7 @@
// order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide // order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide
// to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin // to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin
// are installed, or in some other cases). // are installed, or in some other cases).
namespace Automattic\Jetpack\Backup\V0004; namespace Automattic\Jetpack\Backup\V0005;
/** /**
* Manage installation, deletion and cleanup of Helper Scripts to assist with backing up Jetpack Sites. * Manage installation, deletion and cleanup of Helper Scripts to assist with backing up Jetpack Sites.

View File

@ -8,7 +8,7 @@
// order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide // order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide
// to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin // to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin
// are installed, or in some other cases). // are installed, or in some other cases).
namespace Automattic\Jetpack\Backup\V0004; namespace Automattic\Jetpack\Backup\V0005;
use Exception; use Exception;
use Throwable; use Throwable;

View File

@ -5,6 +5,58 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.3.9] - 2025-03-21
### Changed
- Internal updates.
## [0.3.8] - 2025-03-12
### Changed
- Internal updates.
## [0.3.7] - 2025-03-05
### Changed
- Internal updates.
## [0.3.6] - 2025-02-24
### Changed
- Update dependencies.
## [0.3.5] - 2025-02-03
### Fixed
- Code: Remove extra params on function calls. [#41263]
## [0.3.4] - 2025-01-23
### Changed
- Internal updates.
## [0.3.3] - 2024-12-23
### Fixed
- General: Fixed not parsing error responses from WordPress.com properly. [#40660]
## [0.3.2] - 2024-11-28
### Fixed
- Cachable: Make the expiry overridable by child classes. [#40339]
## [0.3.1] - 2024-11-25
### Changed
- Updated dependencies. [#40286]
## [0.3.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.2.14] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [0.2.13] - 2024-10-29
### Changed
- Internal updates.
## [0.2.12] - 2024-09-23
### Changed
- Update dependencies.
## [0.2.11] - 2024-09-05 ## [0.2.11] - 2024-09-05
### Changed ### Changed
- Update dependencies. - Update dependencies.
@ -73,6 +125,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- Introduce new package. [#31163] - Introduce new package. [#31163]
[0.3.9]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.8...v0.3.9
[0.3.8]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.7...v0.3.8
[0.3.7]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.6...v0.3.7
[0.3.6]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.5...v0.3.6
[0.3.5]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.4...v0.3.5
[0.3.4]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.3...v0.3.4
[0.3.3]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.2...v0.3.3
[0.3.2]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.1...v0.3.2
[0.3.1]: https://github.com/Automattic/jetpack-boost-core/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.14...v0.3.0
[0.2.14]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.13...v0.2.14
[0.2.13]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.12...v0.2.13
[0.2.12]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.11...v0.2.12
[0.2.11]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.10...v0.2.11 [0.2.11]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.10...v0.2.11
[0.2.10]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.9...v0.2.10 [0.2.10]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.9...v0.2.10
[0.2.9]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.8...v0.2.9 [0.2.9]: https://github.com/Automattic/jetpack-boost-core/compare/v0.2.8...v0.2.9

View File

@ -4,13 +4,13 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-connection": "^4.0.0" "automattic/jetpack-connection": "^6.7.7"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"automattic/wordbless": "dev-master" "automattic/phpunit-select-config": "^1.0.1"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -19,23 +19,17 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
], ]
"build-production": "echo 'Add your build step to composer.json, please!'",
"build-development": "echo 'Add your build step to composer.json, please!'",
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
"config": {
"allow-plugins": {
"roots/wordpress-core-installer": true
}
},
"extra": { "extra": {
"mirror-repo": "Automattic/jetpack-boost-core", "mirror-repo": "Automattic/jetpack-boost-core",
"changelogger": { "changelogger": {
@ -43,7 +37,7 @@
}, },
"autotagger": true, "autotagger": true,
"branch-alias": { "branch-alias": {
"dev-trunk": "0.2.x-dev" "dev-trunk": "0.3.x-dev"
}, },
"textdomain": "jetpack-boost-core" "textdomain": "jetpack-boost-core"
}, },

View File

@ -55,6 +55,7 @@ class Boost_API {
* @return array|\WP_Error * @return array|\WP_Error
*/ */
public static function get( $path, $query = array(), $args = null ) { public static function get( $path, $query = array(), $args = null ) {
// @phan-suppress-next-line PhanParamTooMany -- By default this is WPCOM_Boost_API_Client, which accepts an extra param.
return self::get_api_client()->get( $path, $query, self::merge_args( $args ) ); return self::get_api_client()->get( $path, $query, self::merge_args( $args ) );
} }
@ -67,6 +68,7 @@ class Boost_API {
* @return mixed * @return mixed
*/ */
public static function post( $path, $payload = array(), $args = null ) { public static function post( $path, $payload = array(), $args = null ) {
// @phan-suppress-next-line PhanParamTooMany -- By default this is WPCOM_Boost_API_Client, which accepts an extra param.
return self::get_api_client()->post( $path, $payload, self::merge_args( $args ) ); return self::get_api_client()->post( $path, $payload, self::merge_args( $args ) );
} }

View File

@ -14,8 +14,9 @@ abstract class Cacheable implements \JsonSerializable {
/** /**
* Default cache expiry. * Default cache expiry.
* Can be overridden by child classes.
*/ */
const DEFAULT_EXPIRY = 300; // 5 minutes. protected const DEFAULT_EXPIRY = 300; // 5 minutes.
/** /**
* The ID of this object, if cached as a transient. * The ID of this object, if cached as a transient.
@ -31,7 +32,11 @@ abstract class Cacheable implements \JsonSerializable {
* *
* @return mixed|void * @return mixed|void
*/ */
public function store( $expiry = self::DEFAULT_EXPIRY ) { public function store( $expiry = null ) {
if ( null === $expiry ) {
$expiry = static::DEFAULT_EXPIRY;
}
if ( ! $this->cache_id ) { if ( ! $this->cache_id ) {
$this->cache_id = $this->generate_cache_id(); $this->cache_id = $this->generate_cache_id();
} }

View File

@ -133,11 +133,26 @@ class Utils {
$code $code
); );
/*
* Normalize error responses from WordPress.com.
*
* When WordPress.com returns an error from Boost Cloud, the body contains
* statusCode and error. When it returns a WP_Error, it contains code and message.
*/
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$err_code = empty( $data['statusCode'] ) ? 'http_error' : $data['statusCode']; if ( isset( $data['statusCode'] ) && isset( $data['error'] ) ) {
$message = empty( $data['error'] ) ? $default_message : $data['error']; // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$data_code = $data['statusCode'];
$data_message = $data['error'];
} elseif ( isset( $data['code'] ) && isset( $data['message'] ) ) {
$data_code = $data['code'];
$data_message = $data['message'];
}
return new \WP_Error( $err_code, $message ); $error_code = empty( $data_code ) ? 'http_error' : $data_code;
$message = empty( $data_message ) ? $default_message : $data_message;
return new \WP_Error( $error_code, $message );
} }
return $data; return $data;

View File

@ -5,6 +5,42 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.6] - 2025-03-21
### Changed
- Internal updates.
## [0.4.5] - 2025-03-18
### Changed
- Internal updates.
## [0.4.4] - 2025-03-17
### Changed
- Internal updates.
## [0.4.3] - 2025-03-12
### Changed
- Internal updates.
## [0.4.2] - 2025-02-24
### Changed
- Internal updates.
## [0.4.1] - 2025-01-23
### Changed
- Internal updates.
## [0.4.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.3.14] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [0.3.13] - 2024-10-29
### Changed
- Internal updates.
## [0.3.12] - 2024-08-26 ## [0.3.12] - 2024-08-26
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -88,6 +124,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add a new package for Boost Speed Score [#30914] - Add a new package for Boost Speed Score [#30914]
- Add a new argument to `Speed_Score` to identify where the request was made from (e.g. 'boost-plugin', 'jetpack-dashboard', etc). [#31012] - Add a new argument to `Speed_Score` to identify where the request was made from (e.g. 'boost-plugin', 'jetpack-dashboard', etc). [#31012]
[0.4.6]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.5...v0.4.6
[0.4.5]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.4...v0.4.5
[0.4.4]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.3...v0.4.4
[0.4.3]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.2...v0.4.3
[0.4.2]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.1...v0.4.2
[0.4.1]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.14...v0.4.0
[0.3.14]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.13...v0.3.14
[0.3.13]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.12...v0.3.13
[0.3.12]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.11...v0.3.12 [0.3.12]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.11...v0.3.12
[0.3.11]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.10...v0.3.11 [0.3.11]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.10...v0.3.11
[0.3.10]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.9...v0.3.10 [0.3.10]: https://github.com/Automattic/jetpack-boost-speed-score/compare/v0.3.9...v0.3.10

View File

@ -4,9 +4,10 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6", "automattic/jetpack-changelogger": "^6.0.2",
"brain/monkey": "^2.6" "brain/monkey": "^2.6",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"autoload-dev": { "autoload-dev": {
"psr-4": { "psr-4": {
@ -14,8 +15,8 @@
} }
}, },
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-boost-core": "^0.2.9" "automattic/jetpack-boost-core": "^0.3.9"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -24,23 +25,17 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
], ]
"build-production": "echo 'Add your build step to composer.json, please!'",
"build-development": "echo 'Add your build step to composer.json, please!'",
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
}, },
"minimum-stability": "dev", "minimum-stability": "dev",
"prefer-stable": true, "prefer-stable": true,
"config": {
"allow-plugins": {
"roots/wordpress-core-installer": true
}
},
"extra": { "extra": {
"mirror-repo": "Automattic/jetpack-boost-speed-score", "mirror-repo": "Automattic/jetpack-boost-speed-score",
"changelogger": { "changelogger": {
@ -48,7 +43,7 @@
}, },
"autotagger": true, "autotagger": true,
"branch-alias": { "branch-alias": {
"dev-trunk": "0.3.x-dev" "dev-trunk": "0.4.x-dev"
}, },
"textdomain": "jetpack-boost-speed-score", "textdomain": "jetpack-boost-speed-score",
"version-constants": { "version-constants": {

View File

@ -23,7 +23,7 @@ if ( ! defined( 'JETPACK_BOOST_REST_PREFIX' ) ) {
*/ */
class Speed_Score { class Speed_Score {
const PACKAGE_VERSION = '0.3.12'; const PACKAGE_VERSION = '0.4.6';
/** /**
* Array of module slugs that are currently active and can impact speed score. * Array of module slugs that are currently active and can impact speed score.

View File

@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.0.1] - 2025-02-24
### Changed
- Update dependencies.
## [3.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [2.0.4] - 2024-06-24 ## [2.0.4] - 2024-06-24
### Changed ### Changed
- Internal updates. - Internal updates.
@ -208,6 +216,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Trying to add deterministic initialization. - Trying to add deterministic initialization.
[3.0.1]: https://github.com/Automattic/jetpack-config/compare/v3.0.0...v3.0.1
[3.0.0]: https://github.com/Automattic/jetpack-config/compare/v2.0.4...v3.0.0
[2.0.4]: https://github.com/Automattic/jetpack-config/compare/v2.0.3...v2.0.4 [2.0.4]: https://github.com/Automattic/jetpack-config/compare/v2.0.3...v2.0.4
[2.0.3]: https://github.com/Automattic/jetpack-config/compare/v2.0.2...v2.0.3 [2.0.3]: https://github.com/Automattic/jetpack-config/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/Automattic/jetpack-config/compare/v2.0.1...v2.0.2 [2.0.2]: https://github.com/Automattic/jetpack-config/compare/v2.0.1...v2.0.2

View File

@ -4,10 +4,10 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"automattic/jetpack-changelogger": "^4.2.4", "automattic/jetpack-changelogger": "^6.0.0",
"automattic/jetpack-connection": "@dev", "automattic/jetpack-connection": "@dev",
"automattic/jetpack-import": "@dev", "automattic/jetpack-import": "@dev",
"automattic/jetpack-jitm": "@dev", "automattic/jetpack-jitm": "@dev",
@ -40,7 +40,7 @@
"link-template": "https://github.com/Automattic/jetpack-config/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-config/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "2.0.x-dev" "dev-trunk": "3.0.x-dev"
}, },
"dependencies": { "dependencies": {
"test-only": [ "test-only": [

View File

@ -1,3 +0,0 @@
module.exports = {
extends: [ require.resolve( 'jetpack-js-tools/eslintrc/react' ) ],
};

View File

@ -5,6 +5,189 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [6.8.1] - 2025-03-24
### Changed
- Update dependencies.
## [6.8.0] - 2025-03-24
### Added
- Add support for provider-specific authentication. [#42602]
## [6.7.7] - 2025-03-21
### Changed
- Internal updates.
## [6.7.6] - 2025-03-18
### Changed
- Update package dependencies. [#42511]
## [6.7.5] - 2025-03-17
### Changed
- Internal updates.
## [6.7.4] - 2025-03-12
### Changed
- Update package dependencies. [#42384]
## [6.7.3] - 2025-03-10
### Changed
- Internal updates.
## [6.7.2] - 2025-03-06
### Changed
- Update dependencies.
## [6.7.1] - 2025-03-05
### Changed
- Internal updates.
## [6.7.0] - 2025-03-03
### Added
- Add 'isRegistered' flag to connection data endpoint. [#42123]
- Add the 'is_signed_with_user_token()' method for REST authentication. [#39432]
- Allow cookie auth for user provisioning. [#42086]
### Changed
- Update package dependencies. [#42163]
### Removed
- Remove excessive check in fetching current user ID in user provisioning. [#42106]
- Remove register_nonce from site connection. [#42076]
## [6.6.0] - 2025-02-24
### Added
- Warn that disconnecting owner account will disconnect all other users first. [#41923]
### Changed
- Move the API endpoint for unlinking the user to the automattic/jetpack-connection package. [#41398]
## [6.5.0] - 2025-02-17
### Changed
- Display connection status on Users page independent of the SSO module. [#41794]
### Fixed
- Make sure wpcom_id is a string before passing it over as _ui. [#41787]
## [6.4.1] - 2025-02-11
### Changed
- Update dependencies.
## [6.4.0] - 2025-02-10
### Changed
- Tracks: Add site type to events [#41307]
- Updated package dependencies. [#41491]
## [6.3.2] - 2025-02-03
### Changed
- Updated package dependencies. [#41286]
### Fixed
- Code: Remove extra params on function calls. [#41263]
## [6.3.1] - 2025-01-27
### Changed
- Internal updates.
## [6.3.0] - 2025-01-20
### Changed
- Code: Use function-style exit() and die() with a default status code of 0. [#41167]
- Move WPCOM_REST_API_Proxy_Request trait to the connection package. [#41023]
- Updated package dependencies. [#41099]
### Fixed
- Add heartbeat deactivation on site disconnection. [#41117]
## [6.2.2] - 2025-01-06
### Added
- Added tests to increase code coverage. [#39963]
### Changed
- Updated package dependencies. [#40831]
## [6.2.1] - 2024-12-16
### Changed
- Updated package dependencies. [#40564]
## [6.2.0] - 2024-12-09
### Added
- Added a mechanism to use callbacks for package options. [#40474]
- REST user provisioning with an app password. [#40447]
## [6.1.1] - 2024-12-04
### Changed
- Updated package dependencies. [#40363]
## [6.1.0] - 2024-11-25
### Added
- Allow using application password for site registration. [#40233]
### Changed
- Updated dependencies. [#40286]
- Updated package dependencies. [#40258] [#40288]
## [6.0.1] - 2024-11-18
### Fixed
- Work around a WP user caching bug (https://core.trac.wordpress.org/ticket/62003). [#40188]
## [6.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [5.1.7] - 2024-11-11
### Changed
- Updated package dependencies. [#39999] [#40060]
## [5.1.6] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [5.1.5] - 2024-10-25
### Changed
- Internal updates.
## [5.1.4] - 2024-10-21
### Changed
- SSO: optimize 'admin_notices' action callback. [#39811]
## [5.1.3] - 2024-10-10
### Changed
- Updated package dependencies.
## [5.1.2] - 2024-10-07
### Changed
- Adjust conditions to optimize admin notices callback. [#39650]
- Initialize assets in wp-admin only. [#39604]
- Updated package dependencies. [#39594]
## [5.1.1] - 2024-09-30
### Changed
- In 'connect_url_redirect' hook, redirect to 'redirect_after_auth` url if already connected (for connect_after_checkout flow). [#39573]
- My Jetpack Welcome Flow: Display default recommendations upfront first, then offer optional survey for customized recommendations. [#39485]
## [5.1.0] - 2024-09-25
### Changed
- Jetpack Connection - REST API: Allow site-level authentication on POST requests to 'jetpack/v4/connection' [#39503]
## [5.0.0] - 2024-09-23
### Removed
- Connection: Removed deprecated features_enabled method [#39475]
- Connection: Removed deprecated method features_available [#39442]
## [4.0.4] - 2024-09-18
### Changed
- SSO tooltip: Use anchor element's document instead of the global `document`. [#39364]
## [4.0.3] - 2024-09-16
### Removed
- Remove deprecated code from connected plugins component. [#39375]
### Fixed
- Fix the connected plugins option on multisites. [#39355]
## [4.0.2] - 2024-09-10
### Changed
- Updated package dependencies. [#39302]
## [4.0.1] - 2024-09-06 ## [4.0.1] - 2024-09-06
### Removed ### Removed
- Removed throwing of warning if a given Jetpack options does not exist [#39270] - Removed throwing of warning if a given Jetpack options does not exist [#39270]
@ -1187,6 +1370,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Separate the connection library into its own package. - Separate the connection library into its own package.
[6.8.1]: https://github.com/Automattic/jetpack-connection/compare/v6.8.0...v6.8.1
[6.8.0]: https://github.com/Automattic/jetpack-connection/compare/v6.7.7...v6.8.0
[6.7.7]: https://github.com/Automattic/jetpack-connection/compare/v6.7.6...v6.7.7
[6.7.6]: https://github.com/Automattic/jetpack-connection/compare/v6.7.5...v6.7.6
[6.7.5]: https://github.com/Automattic/jetpack-connection/compare/v6.7.4...v6.7.5
[6.7.4]: https://github.com/Automattic/jetpack-connection/compare/v6.7.3...v6.7.4
[6.7.3]: https://github.com/Automattic/jetpack-connection/compare/v6.7.2...v6.7.3
[6.7.2]: https://github.com/Automattic/jetpack-connection/compare/v6.7.1...v6.7.2
[6.7.1]: https://github.com/Automattic/jetpack-connection/compare/v6.7.0...v6.7.1
[6.7.0]: https://github.com/Automattic/jetpack-connection/compare/v6.6.0...v6.7.0
[6.6.0]: https://github.com/Automattic/jetpack-connection/compare/v6.5.0...v6.6.0
[6.5.0]: https://github.com/Automattic/jetpack-connection/compare/v6.4.1...v6.5.0
[6.4.1]: https://github.com/Automattic/jetpack-connection/compare/v6.4.0...v6.4.1
[6.4.0]: https://github.com/Automattic/jetpack-connection/compare/v6.3.2...v6.4.0
[6.3.2]: https://github.com/Automattic/jetpack-connection/compare/v6.3.1...v6.3.2
[6.3.1]: https://github.com/Automattic/jetpack-connection/compare/v6.3.0...v6.3.1
[6.3.0]: https://github.com/Automattic/jetpack-connection/compare/v6.2.2...v6.3.0
[6.2.2]: https://github.com/Automattic/jetpack-connection/compare/v6.2.1...v6.2.2
[6.2.1]: https://github.com/Automattic/jetpack-connection/compare/v6.2.0...v6.2.1
[6.2.0]: https://github.com/Automattic/jetpack-connection/compare/v6.1.1...v6.2.0
[6.1.1]: https://github.com/Automattic/jetpack-connection/compare/v6.1.0...v6.1.1
[6.1.0]: https://github.com/Automattic/jetpack-connection/compare/v6.0.1...v6.1.0
[6.0.1]: https://github.com/Automattic/jetpack-connection/compare/v6.0.0...v6.0.1
[6.0.0]: https://github.com/Automattic/jetpack-connection/compare/v5.1.7...v6.0.0
[5.1.7]: https://github.com/Automattic/jetpack-connection/compare/v5.1.6...v5.1.7
[5.1.6]: https://github.com/Automattic/jetpack-connection/compare/v5.1.5...v5.1.6
[5.1.5]: https://github.com/Automattic/jetpack-connection/compare/v5.1.4...v5.1.5
[5.1.4]: https://github.com/Automattic/jetpack-connection/compare/v5.1.3...v5.1.4
[5.1.3]: https://github.com/Automattic/jetpack-connection/compare/v5.1.2...v5.1.3
[5.1.2]: https://github.com/Automattic/jetpack-connection/compare/v5.1.1...v5.1.2
[5.1.1]: https://github.com/Automattic/jetpack-connection/compare/v5.1.0...v5.1.1
[5.1.0]: https://github.com/Automattic/jetpack-connection/compare/v5.0.0...v5.1.0
[5.0.0]: https://github.com/Automattic/jetpack-connection/compare/v4.0.4...v5.0.0
[4.0.4]: https://github.com/Automattic/jetpack-connection/compare/v4.0.3...v4.0.4
[4.0.3]: https://github.com/Automattic/jetpack-connection/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/Automattic/jetpack-connection/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/Automattic/jetpack-connection/compare/v4.0.0...v4.0.1 [4.0.1]: https://github.com/Automattic/jetpack-connection/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/Automattic/jetpack-connection/compare/v3.0.0...v4.0.0 [4.0.0]: https://github.com/Automattic/jetpack-connection/compare/v3.0.0...v4.0.0
[3.0.0]: https://github.com/Automattic/jetpack-connection/compare/v2.12.5...v3.0.0 [3.0.0]: https://github.com/Automattic/jetpack-connection/compare/v2.12.5...v3.0.0

View File

@ -5,6 +5,11 @@
* @package automattic/jetpack-connection * @package automattic/jetpack-connection
*/ */
if ( function_exists( 'is_admin' ) && ! is_admin() && ( ! defined( 'IS_WPCOM' ) || ! IS_WPCOM ) ) {
// Don't initialize the assets in the frontend on self-hosted and WoA.
return;
}
// If WordPress's plugin API is available already, use it. If not, // If WordPress's plugin API is available already, use it. If not,
// drop data into `$wp_filter` for `WP_Hook::build_preinitialized_hooks()`. // drop data into `$wp_filter` for `WP_Hook::build_preinitialized_hooks()`.
if ( function_exists( 'add_action' ) ) { if ( function_exists( 'add_action' ) ) {

View File

@ -4,20 +4,21 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-a8c-mc-stats": "^2.0.2", "automattic/jetpack-a8c-mc-stats": "^3.0.4",
"automattic/jetpack-admin-ui": "^0.4.5", "automattic/jetpack-admin-ui": "^0.5.7",
"automattic/jetpack-assets": "^2.3.7", "automattic/jetpack-assets": "^4.0.14",
"automattic/jetpack-constants": "^2.0.4", "automattic/jetpack-constants": "^3.0.5",
"automattic/jetpack-roles": "^2.0.3", "automattic/jetpack-roles": "^3.0.5",
"automattic/jetpack-status": "^4.0.1", "automattic/jetpack-status": "^5.0.10",
"automattic/jetpack-redirect": "^2.0.4" "automattic/jetpack-redirect": "^3.0.5"
}, },
"require-dev": { "require-dev": {
"automattic/wordbless": "@dev", "automattic/jetpack-test-environment": "@dev",
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"brain/monkey": "2.6.1", "brain/monkey": "^2.6.2",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -41,10 +42,11 @@
"pnpm run build" "pnpm run build"
], ],
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
] ]
@ -62,7 +64,7 @@
"link-template": "https://github.com/Automattic/jetpack-connection/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-connection/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "4.0.x-dev" "dev-trunk": "6.8.x-dev"
}, },
"dependencies": { "dependencies": {
"test-only": [ "test-only": [

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-url'), 'version' => 'f6bce0e6b8e0527839ee'); <?php return array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '286b93b23b84729b30b9');

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
<?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives', 'wp-url'), 'version' => '633f5b84c0735e749fc1'); <?php return array('dependencies' => array('jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'c64bcd54b1a8ca23f813');

View File

@ -1 +1 @@
<?php return array('dependencies' => array(), 'version' => '04d208524c748ec232f3'); <?php return array('dependencies' => array('wp-polyfill'), 'version' => '15315caa8ea669cf4372');

View File

@ -1 +1 @@
document.addEventListener("DOMContentLoaded",(function(){function t(){this.querySelector(".jetpack-sso-invitation-tooltip").style.display="block"}function e(t){document.activeElement!==t.target&&(this.querySelector(".jetpack-sso-invitation-tooltip").style.display="none")}document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.sso-disconnected-user)").forEach((function(t){t.innerHTML+=" [?]";const e=document.createElement("span");e.classList.add("jetpack-sso-invitation-tooltip","jetpack-sso-th-tooltip");const n=window.Jetpack_SSOTooltip.tooltipString;function o(){t.appendChild(e),e.style.display="block"}function i(){document.activeElement!==t&&t.removeChild(e)}e.innerHTML+=n,t.addEventListener("mouseenter",o),t.addEventListener("focus",o),t.addEventListener("mouseleave",i),t.addEventListener("blur",i)})),document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.jetpack-sso-status-column)").forEach((function(n){n.addEventListener("mouseenter",t),n.addEventListener("focus",t),n.addEventListener("mouseleave",e),n.addEventListener("blur",e)}))})); document.addEventListener("DOMContentLoaded",(function(){function t(){this.querySelector(".jetpack-sso-invitation-tooltip").style.display="block"}function e(t){t.target.ownerDocument.activeElement!==t.target&&(this.querySelector(".jetpack-sso-invitation-tooltip").style.display="none")}document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.sso-disconnected-user)").forEach((function(t){t.innerHTML+=" [?]";const e=document.createElement("span");e.classList.add("jetpack-sso-invitation-tooltip");const n=window.Jetpack_SSOTooltip.tooltipString;function o(){t.appendChild(e),e.style.display="block"}function i(){t.ownerDocument.activeElement!==t&&t.removeChild(e)}e.innerHTML+=n,t.addEventListener("mouseenter",o),t.addEventListener("focus",o),t.addEventListener("mouseleave",i),t.addEventListener("blur",i)})),document.querySelectorAll(".jetpack-sso-invitation-tooltip-icon:not(.jetpack-sso-status-column)").forEach((function(n){n.addEventListener("mouseenter",t),n.addEventListener("focus",t),n.addEventListener("mouseleave",e),n.addEventListener("blur",e)}))}));

View File

@ -0,0 +1 @@
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '53f1c19b5a564105c882');

View File

@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",(function(){document.querySelectorAll(".jetpack-connection-tooltip").forEach((function(o){o.textContent=window.jetpackConnectionTooltips.columnTooltip}))}));

View File

@ -16,7 +16,7 @@ use Automattic\Jetpack\Connection\Manager;
* Disable direct access. * Disable direct access.
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit( 0 );
} }
if ( ! class_exists( IXR_Client::class ) ) { if ( ! class_exists( IXR_Client::class ) ) {

View File

@ -127,6 +127,7 @@ class Jetpack_Options {
'dismissed_welcome_banner', // (bool) Determines if the welcome banner has been dismissed or not. 'dismissed_welcome_banner', // (bool) Determines if the welcome banner has been dismissed or not.
'recommendations_evaluation', // (object) Catalog of recommended modules with corresponding score following successful site evaluation in Welcome Banner. 'recommendations_evaluation', // (object) Catalog of recommended modules with corresponding score following successful site evaluation in Welcome Banner.
'dismissed_recommendations', // (bool) Determines if the recommendations have been dismissed or not. 'dismissed_recommendations', // (bool) Determines if the recommendations have been dismissed or not.
'recommendations_first_run', // (bool) Determines if the current recommendations are the initial default auto-loaded ones (without user input).
'historically_active_modules', // (array) List of installed plugins/enabled modules that have at one point in time been active and working 'historically_active_modules', // (array) List of installed plugins/enabled modules that have at one point in time been active and working
); );
} }

View File

@ -80,7 +80,7 @@ class Jetpack_Tracks_Client {
return $event; return $event;
} }
$pixel = $event->build_pixel_url( $event ); $pixel = $event->build_pixel_url();
if ( ! $pixel ) { if ( ! $pixel ) {
return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 ); return new WP_Error( 'invalid_pixel', 'cannot generate tracks pixel for given input', 400 );

View File

@ -823,42 +823,6 @@ class Jetpack_XMLRPC_Server {
return false; return false;
} }
/**
* Deprecated: This method is no longer part of the Connection package and now lives on the Jetpack plugin.
*
* Returns what features are available. Uses the slug of the module files.
*
* @deprecated since 1.25.0
* @see Jetpack_XMLRPC_Methods::features_available() in the Jetpack plugin
*
* @return array
*/
public function features_available() {
_deprecated_function( __METHOD__, '1.25.0', 'Jetpack_XMLRPC_Methods::features_available()' );
if ( class_exists( 'Jetpack_XMLRPC_Methods' ) ) {
return Jetpack_XMLRPC_Methods::features_available();
}
return array();
}
/**
* Deprecated: This method is no longer part of the Connection package and now lives on the Jetpack plugin.
*
* Returns what features are enabled. Uses the slug of the modules files.
*
* @deprecated since 1.25.0
* @see Jetpack_XMLRPC_Methods::features_enabled() in the Jetpack plugin
*
* @return array
*/
public function features_enabled() {
_deprecated_function( __METHOD__, '1.25.0', 'Jetpack_XMLRPC_Methods::features_enabled()' );
if ( class_exists( 'Jetpack_XMLRPC_Methods' ) ) {
return Jetpack_XMLRPC_Methods::features_enabled();
}
return array();
}
/** /**
* Deprecated: This method is no longer part of the Connection package and now lives on the Jetpack plugin. * Deprecated: This method is no longer part of the Connection package and now lives on the Jetpack plugin.
* *

View File

@ -25,6 +25,9 @@ class Connection_Assets {
/** /**
* Register assets. * Register assets.
*
* NOTICE: Please think twice before including Connection scripts in the frontend.
* Those scripts are intended to be used in WP admin area.
*/ */
public static function register_assets() { public static function register_assets() {

View File

@ -40,7 +40,7 @@ class Connection_Notice {
* @return void * @return void
*/ */
public function initialize_notices( $screen ) { public function initialize_notices( $screen ) {
if ( ! in_array( if ( in_array(
$screen->id, $screen->id,
array( array(
'jetpack_page_akismet-key-config', 'jetpack_page_akismet-key-config',
@ -48,6 +48,19 @@ class Connection_Notice {
), ),
true true
) ) { ) ) {
return;
}
/*
* phpcs:disable WordPress.Security.NonceVerification.Recommended
*
* This function is firing within wp-admin and checks (below) if it is in the midst of a deletion on the users
* page. Nonce will be already checked by WordPress, so we do not need to check ourselves.
*/
if ( isset( $screen->base ) && 'users' === $screen->base
&& isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action']
) {
add_action( 'admin_notices', array( $this, 'delete_user_update_connection_owner_notice' ) ); add_action( 'admin_notices', array( $this, 'delete_user_update_connection_owner_notice' ) );
} }
} }
@ -57,23 +70,6 @@ class Connection_Notice {
* the connection owner. * the connection owner.
*/ */
public function delete_user_update_connection_owner_notice() { public function delete_user_update_connection_owner_notice() {
global $current_screen;
/*
* phpcs:disable WordPress.Security.NonceVerification.Recommended
*
* This function is firing within wp-admin and checks (below) if it is in the midst of a deletion on the users
* page. Nonce will be already checked by WordPress, so we do not need to check ourselves.
*/
if ( ! isset( $current_screen->base ) || 'users' !== $current_screen->base ) {
return;
}
if ( ! isset( $_REQUEST['action'] ) || 'delete' !== $_REQUEST['action'] ) {
return;
}
// Get connection owner or bail. // Get connection owner or bail.
$connection_manager = new Manager(); $connection_manager = new Manager();
$connection_owner_id = $connection_manager->get_connection_owner_id(); $connection_owner_id = $connection_manager->get_connection_owner_id();

View File

@ -691,7 +691,7 @@ class Error_Handler {
/** /**
* Fires inside the admin_notices hook just before displaying the error message for a broken connection. * Fires inside the admin_notices hook just before displaying the error message for a broken connection.
* *
* If you want to disable the default message from being displayed, return an emtpy value in the jetpack_connection_error_notice_message filter. * If you want to disable the default message from being displayed, return an empty value in the jetpack_connection_error_notice_message filter.
* *
* @since 8.9.0 * @since 8.9.0
* *

View File

@ -80,6 +80,20 @@ class Manager {
*/ */
private static $disconnected_users = array(); private static $disconnected_users = array();
/**
* Cached connection status.
*
* @var bool|null True if the site is connected, false if not, null if not determined yet.
*/
private static $is_connected = null;
/**
* Tracks whether connection status invalidation hooks have been added.
*
* @var bool
*/
private static $connection_invalidators_added = false;
/** /**
* Initialize the object. * Initialize the object.
* Make sure to call the "Configure" first. * Make sure to call the "Configure" first.
@ -123,7 +137,9 @@ class Manager {
add_filter( 'shutdown', array( new Package_Version_Tracker(), 'maybe_update_package_versions' ) ); add_filter( 'shutdown', array( new Package_Version_Tracker(), 'maybe_update_package_versions' ) );
} }
add_action( 'rest_api_init', array( $manager, 'initialize_rest_api_registration_connector' ) ); // This runs on priority 11 - at least one api method in the connection package is set to override a previously
// existing method from the Jetpack plugin. Running later than Jetpack's api init ensures the override is successful.
add_action( 'rest_api_init', array( $manager, 'initialize_rest_api_registration_connector' ), 11 );
( new Nonce_Handler() )->init_schedule(); ( new Nonce_Handler() )->init_schedule();
@ -140,6 +156,8 @@ class Manager {
add_action( 'deleted_user', array( $manager, 'disconnect_user_force' ), 9, 1 ); add_action( 'deleted_user', array( $manager, 'disconnect_user_force' ), 9, 1 );
add_action( 'remove_user_from_blog', array( $manager, 'disconnect_user_force' ), 9, 1 ); add_action( 'remove_user_from_blog', array( $manager, 'disconnect_user_force' ), 9, 1 );
$manager->add_connection_status_invalidation_hooks();
// Set up package version hook. // Set up package version hook.
add_filter( 'jetpack_package_versions', __NAMESPACE__ . '\Package_Version::send_package_version_to_tracker' ); add_filter( 'jetpack_package_versions', __NAMESPACE__ . '\Package_Version::send_package_version_to_tracker' );
@ -157,6 +175,28 @@ class Manager {
Partner::init(); Partner::init();
} }
/**
* Adds hooks to invalidate the memoized connection status.
*/
private function add_connection_status_invalidation_hooks() {
if ( self::$connection_invalidators_added ) {
return;
}
// Force is_connected() to recompute after important actions.
add_action( 'jetpack_site_registered', array( $this, 'reset_connection_status' ) );
add_action( 'jetpack_site_disconnected', array( $this, 'reset_connection_status' ) );
add_action( 'jetpack_sync_register_user', array( $this, 'reset_connection_status' ) );
add_action( 'pre_update_jetpack_option_id', array( $this, 'reset_connection_status' ) );
add_action( 'pre_update_jetpack_option_blog_token', array( $this, 'reset_connection_status' ) );
add_action( 'pre_update_jetpack_option_user_token', array( $this, 'reset_connection_status' ) );
add_action( 'pre_update_jetpack_option_user_tokens', array( $this, 'reset_connection_status' ) );
// phpcs:ignore WPCUT.SwitchBlog.SwitchBlog -- wpcom flags **every** use of switch_blog, apparently expecting valid instances to ignore or suppress the sniff.
add_action( 'switch_blog', array( $this, 'reset_connection_status' ) );
self::$connection_invalidators_added = true;
}
/** /**
* Sets up the XMLRPC request handlers. * Sets up the XMLRPC request handlers.
* *
@ -172,7 +212,7 @@ class Manager {
$deprecated, $deprecated,
$has_connected_owner, $has_connected_owner,
$is_signed, $is_signed,
Jetpack_XMLRPC_Server $xmlrpc_server = null ?Jetpack_XMLRPC_Server $xmlrpc_server = null
) { ) {
add_filter( 'xmlrpc_blog_options', array( $this, 'xmlrpc_options' ), 1000, 2 ); add_filter( 'xmlrpc_blog_options', array( $this, 'xmlrpc_options' ), 1000, 2 );
if ( $deprecated !== null ) { if ( $deprecated !== null ) {
@ -280,7 +320,7 @@ class Manager {
nocache_headers(); nocache_headers();
$wp_xmlrpc_server->serve_request(); $wp_xmlrpc_server->serve_request();
exit; exit( 0 );
} }
/** /**
@ -415,8 +455,9 @@ class Manager {
if ( if (
empty( $token_key ) empty( $token_key )
|| || empty( $version )
empty( $version ) || (string) $jetpack_api_version !== $version ) { || (string) $jetpack_api_version !== $version
) {
return new \WP_Error( 'malformed_token', 'Malformed token in request', compact( 'signature_details', 'error_type' ) ); return new \WP_Error( 'malformed_token', 'Malformed token in request', compact( 'signature_details', 'error_type' ) );
} }
@ -596,9 +637,31 @@ class Manager {
* @return bool * @return bool
*/ */
public function is_connected() { public function is_connected() {
if ( self::$is_connected === null ) {
if ( ! self::$connection_invalidators_added ) {
$this->add_connection_status_invalidation_hooks();
}
$has_blog_id = (bool) \Jetpack_Options::get_option( 'id' ); $has_blog_id = (bool) \Jetpack_Options::get_option( 'id' );
if ( $has_blog_id ) {
$has_blog_token = (bool) $this->get_tokens()->get_access_token(); $has_blog_token = (bool) $this->get_tokens()->get_access_token();
return $has_blog_id && $has_blog_token; self::$is_connected = ( $has_blog_id && $has_blog_token );
} else {
// Short-circuit, no need to check for tokens if there's no blog ID.
self::$is_connected = false;
}
}
return self::$is_connected;
}
/**
* Resets the memoized connection status.
* This will force the connection status to be recomputed on the next check.
*
* @since 5.0.0
*/
public function reset_connection_status() {
self::$is_connected = null;
} }
/** /**
@ -875,25 +938,54 @@ class Manager {
// Using wp_redirect intentionally because we're redirecting outside. // Using wp_redirect intentionally because we're redirecting outside.
wp_redirect( $this->get_authorization_url( $user, $redirect_url ) ); // phpcs:ignore WordPress.Security.SafeRedirect wp_redirect( $this->get_authorization_url( $user, $redirect_url ) ); // phpcs:ignore WordPress.Security.SafeRedirect
exit(); exit( 0 );
} }
/** /**
* Force user disconnect. * Force user disconnect.
* *
* @param int $user_id Local (external) user ID. * @param int $user_id Local (external) user ID.
* @param bool $disconnect_all_users Whether to disconnect all users before disconnecting the primary user.
* *
* @return bool * @return bool
*/ */
public function disconnect_user_force( $user_id ) { public function disconnect_user_force( $user_id, $disconnect_all_users = false ) {
if ( ! (int) $user_id ) { if ( ! (int) $user_id ) {
// Missing user ID. // Missing user ID.
return false; return false;
} }
// If we are disconnecting the primary user we may need to disconnect all other users first
if ( $user_id === $this->get_connection_owner_id() && $disconnect_all_users && ! $this->disconnect_all_users_except_primary() ) {
return false;
}
return $this->disconnect_user( $user_id, true, true ); return $this->disconnect_user( $user_id, true, true );
} }
/**
* Disconnects all users except the primary user.
*
* @return bool
*/
public function disconnect_all_users_except_primary() {
$all_connected_users = $this->get_connected_users();
foreach ( $all_connected_users as $user ) {
// Skip the primary.
if ( $user->ID === $this->get_connection_owner_id() ) {
continue;
}
$disconnected = $this->disconnect_user( $user->ID, false, true );
// If we fail to disconnect any user, we should not proceed with disconnecting the primary user.
if ( ! $disconnected ) {
return false;
}
}
return true;
}
/** /**
* Unlinks the current user from the linked WordPress.com user. * Unlinks the current user from the linked WordPress.com user.
* *
@ -1505,6 +1597,16 @@ class Manager {
// With site connections in mind, non-admin users can connect their account only if a connection owner exists. // With site connections in mind, non-admin users can connect their account only if a connection owner exists.
$caps = $this->has_connected_owner() ? array( 'read' ) : array( 'manage_options' ); $caps = $this->has_connected_owner() ? array( 'read' ) : array( 'manage_options' );
break; break;
case 'jetpack_unlink_user':
$is_offline_mode = ( new Status() )->is_offline_mode();
if ( $is_offline_mode ) {
$caps = array( 'do_not_allow' );
break;
}
// Non-admins can always disconnect
$caps = array( 'read' );
break;
} }
return $caps; return $caps;
} }
@ -1561,12 +1663,17 @@ class Manager {
return $cached_date; return $cached_date;
} }
/**
* We don't use the 'ID' field, but need it to overcome a WP caching bug: https://core.trac.wordpress.org/ticket/62003
*
* @todo Remote the 'ID' field from users fetching when the issue is fixed and Jetpack-supported WP versions move beyond it.
*/
$earliest_registered_users = get_users( $earliest_registered_users = get_users(
array( array(
'role' => 'administrator', 'role' => 'administrator',
'orderby' => 'user_registered', 'orderby' => 'user_registered',
'order' => 'ASC', 'order' => 'ASC',
'fields' => array( 'user_registered' ), 'fields' => array( 'ID', 'user_registered' ),
'number' => 1, 'number' => 1,
) )
); );
@ -2125,6 +2232,8 @@ class Manager {
( new Nonce_Handler() )->clean_all(); ( new Nonce_Handler() )->clean_all();
Heartbeat::init()->deactivate();
/** /**
* Fires before a site is disconnected. * Fires before a site is disconnected.
* *

View File

@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Connection;
*/ */
class Package_Version { class Package_Version {
const PACKAGE_VERSION = '4.0.1'; const PACKAGE_VERSION = '6.8.1';
const PACKAGE_SLUG = 'connection'; const PACKAGE_SLUG = 'connection';

View File

@ -15,7 +15,7 @@ use Jetpack_Options;
* Disable direct access. * Disable direct access.
*/ */
if ( ! defined( 'ABSPATH' ) ) { if ( ! defined( 'ABSPATH' ) ) {
exit; exit( 0 );
} }
/** /**

View File

@ -17,14 +17,6 @@ class Plugin_Storage {
const ACTIVE_PLUGINS_OPTION_NAME = 'jetpack_connection_active_plugins'; const ACTIVE_PLUGINS_OPTION_NAME = 'jetpack_connection_active_plugins';
/**
* Options where disabled plugins were stored
*
* @deprecated since 1.39.0.
* @var string
*/
const PLUGINS_DISABLED_OPTION_NAME = 'jetpack_connection_disabled_plugins';
/** /**
* Transient name used as flag to indicate that the active connected plugins list needs refreshing. * Transient name used as flag to indicate that the active connected plugins list needs refreshing.
*/ */
@ -93,13 +85,9 @@ class Plugin_Storage {
* Even if you don't use Jetpack Config, it may be introduced later by other plugins, * Even if you don't use Jetpack Config, it may be introduced later by other plugins,
* so please make sure not to run the method too early in the code. * so please make sure not to run the method too early in the code.
* *
* @since 1.39.0 deprecated the $connected_only argument.
*
* @param null $deprecated null plugins that were explicitly disconnected. Deprecated, there's no such a thing as disconnecting only specific plugins anymore.
*
* @return array|WP_Error * @return array|WP_Error
*/ */
public static function get_all( $deprecated = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable public static function get_all() {
$maybe_error = self::ensure_configured(); $maybe_error = self::ensure_configured();
if ( $maybe_error instanceof WP_Error ) { if ( $maybe_error instanceof WP_Error ) {
@ -144,7 +132,10 @@ class Plugin_Storage {
} }
if ( is_multisite() && get_current_blog_id() !== self::$current_blog_id ) { if ( is_multisite() && get_current_blog_id() !== self::$current_blog_id ) {
if ( self::$current_blog_id ) {
// If blog ID got changed, pull the list of active plugins for that blog from the database.
self::$plugins = (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ); self::$plugins = (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() );
}
self::$current_blog_id = get_current_blog_id(); self::$current_blog_id = get_current_blog_id();
} }
@ -234,43 +225,6 @@ class Plugin_Storage {
} }
} }
/**
* Add the plugin to the set of disconnected ones.
*
* @deprecated since 1.39.0.
*
* @param string $slug Plugin slug.
*
* @return bool
*/
public static function disable_plugin( $slug ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return true;
}
/**
* Remove the plugin from the set of disconnected ones.
*
* @deprecated since 1.39.0.
*
* @param string $slug Plugin slug.
*
* @return bool
*/
public static function enable_plugin( $slug ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return true;
}
/**
* Get all plugins that were disconnected by user.
*
* @deprecated since 1.39.0.
*
* @return array
*/
public static function get_all_disabled_plugins() { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return array();
}
/** /**
* Update active plugins option with current list of active plugins on WPCOM. * Update active plugins option with current list of active plugins on WPCOM.
* This is a fallback to ensure this option is always up to date on WPCOM in case * This is a fallback to ensure this option is always up to date on WPCOM in case

View File

@ -31,6 +31,13 @@ class Plugin {
*/ */
private $slug; private $slug;
/**
* Users Connection Admin instance.
*
* @var Users_Connection_Admin
*/
private $users_connection_admin;
/** /**
* Initialize the plugin manager. * Initialize the plugin manager.
* *
@ -38,6 +45,9 @@ class Plugin {
*/ */
public function __construct( $slug ) { public function __construct( $slug ) {
$this->slug = $slug; $this->slug = $slug;
// Initialize Users_Connection_Admin
$this->users_connection_admin = new Users_Connection_Admin();
} }
/** /**
@ -87,36 +97,4 @@ class Plugin {
return ! $plugins || ( array_key_exists( $this->slug, $plugins ) && 1 === count( $plugins ) ); return ! $plugins || ( array_key_exists( $this->slug, $plugins ) && 1 === count( $plugins ) );
} }
/**
* Add the plugin to the set of disconnected ones.
*
* @deprecated since 1.39.0.
*
* @return bool
*/
public function disable() {
return true;
}
/**
* Remove the plugin from the set of disconnected ones.
*
* @deprecated since 1.39.0.
*
* @return bool
*/
public function enable() {
return true;
}
/**
* Whether this plugin is allowed to use the connection.
*
* @deprecated since 11.0
* @return bool
*/
public function is_enabled() {
return true;
}
} }

View File

@ -219,4 +219,17 @@ class Rest_Authentication {
return true === $instance->rest_authentication_status && 'blog' === $instance->rest_authentication_type; return true === $instance->rest_authentication_status && 'blog' === $instance->rest_authentication_type;
} }
/**
* Whether the request was signed with a user token.
*
* @since 6.7.0
*
* @return bool True if the request was signed with a valid user token, false otherwise.
*/
public static function is_signed_with_user_token() {
$instance = self::init();
return true === $instance->rest_authentication_status && 'user' === $instance->rest_authentication_type;
}
} }

View File

@ -167,6 +167,20 @@ class REST_Connector {
) )
); );
// Disconnect/unlink user from WordPress.com servers.
// this endpoint is set to override the older endpoint that was previously in the Jetpack plugin
// Override is here in case an older version of the Jetpack plugin is installed alongside an updated standalone
register_rest_route(
'jetpack/v4',
'/connection/user',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => __CLASS__ . '::unlink_user',
'permission_callback' => __CLASS__ . '::unlink_user_permission_callback',
),
true // override other implementations
);
// We are only registering this route if Jetpack-the-plugin is not active or it's version is ge 10.0-alpha. // We are only registering this route if Jetpack-the-plugin is not active or it's version is ge 10.0-alpha.
// The reason for doing so is to avoid conflicts between the Connection package and // The reason for doing so is to avoid conflicts between the Connection package and
// older versions of Jetpack, registering the same route twice. // older versions of Jetpack, registering the same route twice.
@ -218,11 +232,6 @@ class REST_Connector {
'description' => __( 'Indicates where the registration action was triggered for tracking/segmentation purposes', 'jetpack-connection' ), 'description' => __( 'Indicates where the registration action was triggered for tracking/segmentation purposes', 'jetpack-connection' ),
'type' => 'string', 'type' => 'string',
), ),
'registration_nonce' => array(
'description' => __( 'The registration nonce', 'jetpack-connection' ),
'type' => 'string',
'required' => true,
),
'redirect_uri' => array( 'redirect_uri' => array(
'description' => __( 'URI of the admin page where the user should be redirected after connection flow', 'jetpack-connection' ), 'description' => __( 'URI of the admin page where the user should be redirected after connection flow', 'jetpack-connection' ),
'type' => 'string', 'type' => 'string',
@ -252,6 +261,34 @@ class REST_Connector {
) )
); );
// Provider-specific authorization URL endpoint
register_rest_route(
'jetpack/v4',
'/connection/authorize_url/(?P<provider>[a-zA-Z]+)',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'connection_authorize_url_provider' ),
'permission_callback' => __CLASS__ . '::user_connection_data_permission_check',
'args' => array(
'provider' => array(
'description' => __( 'Authentication provider (google, github, apple, link)', 'jetpack-connection' ),
'type' => 'string',
'required' => true,
'enum' => array( 'google', 'github', 'apple', 'link' ),
),
'redirect_uri' => array(
'description' => __( 'URI of the admin page where the user should be redirected after connection flow', 'jetpack-connection' ),
'type' => 'string',
),
'email_address' => array(
'description' => __( 'Email address for magic link authentication', 'jetpack-connection' ),
'type' => 'string',
'format' => 'email',
),
),
)
);
register_rest_route( register_rest_route(
'jetpack/v4', 'jetpack/v4',
'/user-token', '/user-token',
@ -340,9 +377,15 @@ class REST_Connector {
* *
* @return WP_Error|array * @return WP_Error|array
*/ */
public static function remote_provision( WP_REST_Request $request ) { public function remote_provision( WP_REST_Request $request ) {
$request_data = $request->get_params();
if ( current_user_can( 'jetpack_connect_user' ) ) {
$request_data['local_user'] = get_current_user_id();
}
$xmlrpc_server = new Jetpack_XMLRPC_Server(); $xmlrpc_server = new Jetpack_XMLRPC_Server();
$result = $xmlrpc_server->remote_provision( $request ); $result = $xmlrpc_server->remote_provision( $request_data );
if ( is_a( $result, 'IXR_Error' ) ) { if ( is_a( $result, 'IXR_Error' ) ) {
$result = new WP_Error( $result->code, $result->message ); $result = new WP_Error( $result->code, $result->message );
@ -394,9 +437,15 @@ class REST_Connector {
/** /**
* Remote provision endpoint permission check. * Remote provision endpoint permission check.
* *
* @param WP_REST_Request $request The request object.
*
* @return true|WP_Error * @return true|WP_Error
*/ */
public function remote_provision_permission_check() { public function remote_provision_permission_check( WP_REST_Request $request ) {
if ( empty( $request['local_user'] ) && current_user_can( 'jetpack_connect_user' ) ) {
return true;
}
return Rest_Authentication::is_signed_with_blog_token() return Rest_Authentication::is_signed_with_blog_token()
? true ? true
: new WP_Error( 'invalid_permission_remote_provision', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) ); : new WP_Error( 'invalid_permission_remote_provision', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
@ -545,15 +594,36 @@ class REST_Connector {
* *
* @since 1.30.1 * @since 1.30.1
* *
* @return bool|WP_Error True if user is able to disconnect the site. * @since 5.1.0 Modified the permission check to accept requests signed with blog tokens.
*
* @return bool|WP_Error True if user is able to disconnect the site or the request is signed with a blog token (aka a direct request from WPCOM).
*/ */
public static function disconnect_site_permission_check() { public static function disconnect_site_permission_check() {
if ( current_user_can( 'jetpack_disconnect' ) ) { if ( current_user_can( 'jetpack_disconnect' ) ) {
return true; return true;
} }
return Rest_Authentication::is_signed_with_blog_token()
? true
: new WP_Error( 'invalid_user_permission_jetpack_disconnect', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
}
/**
* Verify that a user can use the /connection/user endpoint. Has to be a registered user and be currently linked.
*
* @since 6.3.3
*
* @return bool|WP_Error True if user is able to unlink.
*/
public static function unlink_user_permission_callback() {
// This is a mapped capability
// phpcs:ignore WordPress.WP.Capabilities.Unknown
if ( current_user_can( 'jetpack_unlink_user' ) && ( new Manager() )->is_user_connected( get_current_user_id() ) ) {
return true;
}
return new WP_Error( return new WP_Error(
'invalid_user_permission_jetpack_disconnect', 'invalid_user_permission_unlink_user',
self::get_user_permissions_error_msg(), self::get_user_permissions_error_msg(),
array( 'status' => rest_authorization_required_code() ) array( 'status' => rest_authorization_required_code() )
); );
@ -607,11 +677,15 @@ class REST_Connector {
'id' => $current_user->ID, 'id' => $current_user->ID,
'blogId' => $blog_id, 'blogId' => $blog_id,
'wpcomUser' => $wpcom_user_data, 'wpcomUser' => $wpcom_user_data,
'gravatar' => get_avatar_url( $current_user->ID, 64, 'mm', '', array( 'force_display' => true ) ), 'gravatar' => get_avatar_url( $current_user->ID ),
'permissions' => array( 'permissions' => array(
'connect' => current_user_can( 'jetpack_connect' ), 'connect' => current_user_can( 'jetpack_connect' ),
'connect_user' => current_user_can( 'jetpack_connect_user' ), 'connect_user' => current_user_can( 'jetpack_connect_user' ),
// This is a mapped capability
// phpcs:ignore WordPress.WP.Capabilities.Unknown
'unlink_user' => current_user_can( 'jetpack_unlink_user' ),
'disconnect' => current_user_can( 'jetpack_disconnect' ), 'disconnect' => current_user_can( 'jetpack_disconnect' ),
'manage_options' => current_user_can( 'manage_options' ),
), ),
); );
@ -627,6 +701,7 @@ class REST_Connector {
$response = array( $response = array(
'currentUser' => $current_user_connection_data, 'currentUser' => $current_user_connection_data,
'connectionOwner' => $owner_display_name, 'connectionOwner' => $owner_display_name,
'isRegistered' => $connection->is_connected(),
); );
if ( $rest_response ) { if ( $rest_response ) {
@ -781,9 +856,10 @@ class REST_Connector {
} }
/** /**
* The endpoint tried to partially or fully reconnect the website to WP.com. * The endpoint tried to connect Jetpack site to WPCOM.
* *
* @since 1.7.0 * @since 1.7.0
* @since 6.7.0 No longer needs `registration_nonce`.
* @since-jetpack 7.7.0 * @since-jetpack 7.7.0
* *
* @param \WP_REST_Request $request The request sent to the WP REST API. * @param \WP_REST_Request $request The request sent to the WP REST API.
@ -791,10 +867,6 @@ class REST_Connector {
* @return \WP_REST_Response|WP_Error * @return \WP_REST_Response|WP_Error
*/ */
public function connection_register( $request ) { public function connection_register( $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-connection' ), array( 'status' => 403 ) );
}
if ( isset( $request['from'] ) ) { if ( isset( $request['from'] ) ) {
$this->connection->add_register_request_param( 'from', (string) $request['from'] ); $this->connection->add_register_request_param( 'from', (string) $request['from'] );
} }
@ -930,6 +1002,51 @@ class REST_Connector {
); );
} }
/**
* Unlinks current user from the WordPress.com Servers.
*
* @since 6.3.3
*
* @param WP_REST_Request $request The request sent to the WP REST API.
*
* @return bool|WP_Error True if user successfully unlinked.
*/
public static function unlink_user( $request ) {
if ( ! isset( $request['linked'] ) || false !== $request['linked'] ) {
return new WP_Error( 'invalid_param', esc_html__( 'Invalid Parameter', 'jetpack-connection' ), array( 'status' => 404 ) );
}
// If the user is also connection owner, we need to disconnect all users. Since disconnecting all users is a destructive action, we need to pass a parameter to confirm the action.
$disconnect_all_users = false;
if ( ( new Manager() )->get_connection_owner_id() === get_current_user_id() ) {
if ( isset( $request['disconnect-all-users'] ) && false !== $request['disconnect-all-users'] ) {
$disconnect_all_users = true;
} else {
return new WP_Error( 'unlink_user_failed', esc_html__( 'Unable to unlink the connection owner.', 'jetpack-connection' ), array( 'status' => 400 ) );
}
}
// Allow admins to force a disconnect by passing the "force" parameter
// This allows an admin to disconnect themselves
if ( isset( $request['force'] ) && false !== $request['force'] && current_user_can( 'manage_options' ) && ( new Manager( 'jetpack' ) )->disconnect_user_force( get_current_user_id(), $disconnect_all_users ) ) {
return rest_ensure_response(
array(
'code' => 'success',
)
);
} elseif ( ( new Manager( 'jetpack' ) )->disconnect_user() ) {
return rest_ensure_response(
array(
'code' => 'success',
)
);
}
return new WP_Error( 'unlink_user_failed', esc_html__( 'Was not able to unlink the user. Please try again.', 'jetpack-connection' ), array( 'status' => 400 ) );
}
/** /**
* Verify that the API client is allowed to replace user token. * Verify that the API client is allowed to replace user token.
* *
@ -1021,4 +1138,53 @@ class REST_Connector {
? true ? true
: new WP_Error( 'invalid_permission_connection_check', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) ); : new WP_Error( 'invalid_permission_connection_check', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
} }
/**
* Provider-specific authorization URL endpoint
*
* @param WP_REST_Request $request The request sent to the WP REST API.
*
* @return \WP_REST_Response|WP_Error
*/
public function connection_authorize_url_provider( $request ) {
$provider = $request['provider'];
$redirect_uri = $request['redirect_uri'] ?? '';
// Validate magic link parameters if provider is 'link'
if ( 'link' === $provider ) {
if ( empty( $request['email_address'] ) ) {
return new WP_Error(
'missing_email',
__( 'Email address is required for magic link authentication.', 'jetpack-connection' ),
array( 'status' => 400 )
);
}
// Sanitize email address
$email = sanitize_email( $request['email_address'] );
if ( ! is_email( $email ) ) {
return new WP_Error(
'invalid_email',
__( 'Invalid email address format.', 'jetpack-connection' ),
array( 'status' => 400 )
);
}
}
$authorize_url = ( new Authorize_Redirect( $this->connection ) )->build_authorize_url(
$redirect_uri,
false,
false,
$provider,
array(
'email_address' => $email ?? '',
)
);
return rest_ensure_response(
array(
'authorizeUrl' => $authorize_url,
)
);
}
} }

View File

@ -282,7 +282,7 @@ class Tracking {
// Meta is set, and user is still connected. Use WPCOM ID. // Meta is set, and user is still connected. Use WPCOM ID.
$wpcom_id = get_user_meta( $user_id, 'jetpack_tracks_wpcom_id', true ); $wpcom_id = get_user_meta( $user_id, 'jetpack_tracks_wpcom_id', true );
if ( $wpcom_id && $this->connection->is_user_connected( $user_id ) ) { if ( $wpcom_id && is_string( $wpcom_id ) && $this->connection->is_user_connected( $user_id ) ) {
return array( return array(
'_ut' => 'wpcom:user_id', '_ut' => 'wpcom:user_id',
'_ui' => $wpcom_id, '_ui' => $wpcom_id,
@ -292,13 +292,17 @@ class Tracking {
// User is connected, but no meta is set yet. Use WPCOM ID and set meta. // User is connected, but no meta is set yet. Use WPCOM ID and set meta.
if ( $this->connection->is_user_connected( $user_id ) ) { if ( $this->connection->is_user_connected( $user_id ) ) {
$wpcom_user_data = $this->connection->get_connected_user_data( $user_id ); $wpcom_user_data = $this->connection->get_connected_user_data( $user_id );
update_user_meta( $user_id, 'jetpack_tracks_wpcom_id', $wpcom_user_data['ID'] ); $wpcom_id = $wpcom_user_data['ID'] ?? null;
if ( is_string( $wpcom_id ) ) {
update_user_meta( $user_id, 'jetpack_tracks_wpcom_id', $wpcom_id );
return array( return array(
'_ut' => 'wpcom:user_id', '_ut' => 'wpcom:user_id',
'_ui' => $wpcom_user_data['ID'], '_ui' => $wpcom_id,
); );
} }
}
// User isn't linked at all. Fall back to anonymous ID. // User isn't linked at all. Fall back to anonymous ID.
$anon_id = get_user_meta( $user_id, 'jetpack_tracks_anon_id', true ); $anon_id = get_user_meta( $user_id, 'jetpack_tracks_anon_id', true );

View File

@ -0,0 +1,175 @@
<?php
/**
* Handles the WordPress.com account column in the users list table.
*
* @package automattic/jetpack-connection
*/
namespace Automattic\Jetpack\Connection;
use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Status\Host;
/**
* Class Users_Connection_Admin
*/
class Users_Connection_Admin {
/**
* The column ID used for the WordPress.com account column.
*
* @var string
*/
const COLUMN_ID = 'user_jetpack';
/**
* Constructor.
*/
public function __construct() {
// Only set up hooks if we're in the admin area and user has proper permissions
add_action( 'init', array( $this, 'init' ) );
}
/**
* Initialize the admin functionality if conditions are met.
*/
public function init() {
if ( ! is_admin() || ! current_user_can( 'manage_options' ) || ( new Host() )->is_wpcom_simple() ) {
return;
}
add_filter( 'manage_users_columns', array( $this, 'add_connection_column' ) );
add_filter( 'manage_users_custom_column', array( $this, 'render_connection_column' ), 9, 3 ); // Priority 9 to run before SSO
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'admin_print_styles-users.php', array( $this, 'add_connection_column_styles' ) );
}
/**
* Add the connection column to the users list table.
*
* @param array $columns The current columns.
* @return array Modified columns.
*/
public function add_connection_column( $columns ) {
$columns[ self::COLUMN_ID ] = sprintf(
'<span class="jetpack-connection-tooltip-icon" role="tooltip" tabindex="0" aria-label="%2$s: %1$s">
%1$s
<span class="jetpack-connection-tooltip"></span>
</span>',
esc_html__( 'WordPress.com account', 'jetpack-connection' ),
esc_attr__( 'Tooltip', 'jetpack-connection' )
);
return $columns;
}
/**
* Render the connection column content.
*
* @param string $output Custom column output.
* @param string $column_name Column name.
* @param int $user_id ID of the currently-listed user.
* @return string
*/
public function render_connection_column( $output, $column_name, $user_id ) {
if ( self::COLUMN_ID !== $column_name ) {
return $output;
}
if ( ( new Manager() )->is_user_connected( $user_id ) ) {
return sprintf(
'<span title="%1$s" class="jetpack-connection-status">%2$s</span>',
esc_attr__( 'This user has connected their WordPress.com account.', 'jetpack-connection' ),
esc_html__( 'Connected', 'jetpack-connection' )
);
}
return $output;
}
/**
* Enqueue scripts and styles.
*
* @param string $hook The current admin page.
*/
public function enqueue_scripts( $hook ) {
if ( 'users.php' !== $hook ) {
return;
}
Assets::register_script(
'jetpack-users-connection',
'../dist/jetpack-users-connection.js',
__FILE__,
array(
'strategy' => 'defer',
'in_footer' => true,
'enqueue' => true,
'version' => Package_Version::PACKAGE_VERSION,
'deps' => array( 'wp-i18n' ),
)
);
wp_localize_script(
'jetpack-users-connection',
'jetpackConnectionTooltips',
array(
'columnTooltip' => esc_html__( 'Connecting a WordPress.com account unlocks Jetpacks full suite of features including secure logins.', 'jetpack-connection' ),
)
);
}
/**
* Add styles for the connection column.
*/
public function add_connection_column_styles() {
?>
<style>
.jetpack-connection-tooltip-icon {
position: relative;
cursor: pointer;
}
/* Add [?] icon using pseudo-element, only in column header */
th.manage-column .jetpack-connection-tooltip-icon::after {
content: '[?]';
color: #3c434a;
font-size: 1em;
margin-left: 4px;
}
.jetpack-connection-tooltip {
position: absolute;
background: #f6f7f7;
top: -85px;
width: 250px;
padding: 7px;
color: #3c434a;
font-size: .75rem;
line-height: 17px;
text-align: left;
margin: 0;
display: none;
border-radius: 4px;
font-family: sans-serif;
box-shadow: 5px 10px 10px rgba(0, 0, 0, 0.1);
left: -170px;
}
.column-user_jetpack {
width: 140px;
}
/* Show tooltip on hover and focus */
.jetpack-connection-tooltip-icon:hover .jetpack-connection-tooltip,
.jetpack-connection-tooltip-icon:focus-within .jetpack-connection-tooltip {
display: block;
}
</style>
<?php
}
/**
* Get the column ID. Allows other classes to reference the same column.
*
* @return string
*/
public static function get_column_id() {
return self::COLUMN_ID;
}
}

View File

@ -163,7 +163,7 @@ class Webhooks {
* @return never * @return never
*/ */
protected function do_exit() { protected function do_exit() {
exit; exit( 0 );
} }
/** /**
@ -199,6 +199,10 @@ class Webhooks {
wp_safe_redirect( $redirect ); wp_safe_redirect( $redirect );
$this->do_exit(); $this->do_exit();
} else { } else {
if ( 'connect-after-checkout' === $from && $redirect ) {
wp_safe_redirect( $redirect );
$this->do_exit();
}
$connect_url = add_query_arg( $connect_url = add_query_arg(
array( array(
'from' => $from, 'from' => $from,

View File

@ -162,17 +162,21 @@ class UI {
$consumer_chosen = null; $consumer_chosen = null;
$consumer_url_length = 0; $consumer_url_length = 0;
foreach ( $consumers as &$consumer ) {
foreach ( $consumers as $consumer ) {
if ( empty( $consumer['admin_page'] ) || ! is_string( $consumer['admin_page'] ) ) { if ( empty( $consumer['admin_page'] ) || ! is_string( $consumer['admin_page'] ) ) {
continue; continue;
} }
if ( isset( $consumer['customContent'] ) && is_callable( $consumer['customContent'] ) ) {
$consumer['customContent'] = call_user_func( $consumer['customContent'] );
}
if ( isset( $_SERVER['REQUEST_URI'] ) && str_starts_with( filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ) ), $consumer['admin_page'] ) && strlen( $consumer['admin_page'] ) > $consumer_url_length ) { if ( isset( $_SERVER['REQUEST_URI'] ) && str_starts_with( filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ) ), $consumer['admin_page'] ) && strlen( $consumer['admin_page'] ) > $consumer_url_length ) {
$consumer_chosen = $consumer; $consumer_chosen = $consumer;
$consumer_url_length = strlen( $consumer['admin_page'] ); $consumer_url_length = strlen( $consumer['admin_page'] );
} }
} }
unset( $consumer );
static::$consumers = $consumer_chosen ? $consumer_chosen : array_shift( $consumers ); static::$consumers = $consumer_chosen ? $consumer_chosen : array_shift( $consumers );

View File

@ -191,7 +191,7 @@ class SSO {
Helpers::delete_connection_for_user( $current_user->ID ); Helpers::delete_connection_for_user( $current_user->ID );
wp_logout(); wp_logout();
wp_safe_redirect( wp_login_url() ); wp_safe_redirect( wp_login_url() );
exit; exit( 0 );
} }
} }
@ -491,7 +491,7 @@ class SSO {
$tracking->record_user_event( 'sso_login_redirect_success' ); $tracking->record_user_event( 'sso_login_redirect_success' );
wp_safe_redirect( $sso_url ); wp_safe_redirect( $sso_url );
exit; exit( 0 );
} }
} elseif ( Helpers::display_sso_form_for_action( $action ) ) { } elseif ( Helpers::display_sso_form_for_action( $action ) ) {
@ -509,7 +509,7 @@ class SSO {
$sso_url = $this->get_sso_url_or_die( $reauth ); $sso_url = $this->get_sso_url_or_die( $reauth );
$tracking->record_user_event( 'sso_login_redirect_bypass_success' ); $tracking->record_user_event( 'sso_login_redirect_bypass_success' );
wp_safe_redirect( $sso_url ); wp_safe_redirect( $sso_url );
exit; exit( 0 );
} }
$this->display_sso_login_form(); $this->display_sso_login_form();
@ -622,7 +622,7 @@ class SSO {
<?php if ( $display_name && $gravatar ) : ?> <?php if ( $display_name && $gravatar ) : ?>
<a rel="nofollow" class="jetpack-sso-wrap__reauth" href="<?php echo esc_url( $this->build_sso_button_url( array( 'force_reauth' => '1' ) ) ); ?>"> <a rel="nofollow" class="jetpack-sso-wrap__reauth" href="<?php echo esc_url( $this->build_sso_button_url( array( 'force_reauth' => '1' ) ) ); ?>">
<?php esc_html_e( 'Log in as a different WordPress.com user', 'jetpack-connection' ); ?> <?php esc_html_e( 'Log in with another WordPress.com account', 'jetpack-connection' ); ?>
</a> </a>
<?php else : ?> <?php else : ?>
<p> <p>
@ -969,7 +969,7 @@ class SSO {
admin_url() admin_url()
) )
); );
exit; exit( 0 );
} }
add_filter( 'allowed_redirect_hosts', array( Helpers::class, 'allowed_redirect_hosts' ) ); add_filter( 'allowed_redirect_hosts', array( Helpers::class, 'allowed_redirect_hosts' ) );
@ -977,7 +977,7 @@ class SSO {
/** This filter is documented in core/src/wp-login.php */ /** This filter is documented in core/src/wp-login.php */
apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user ) apply_filters( 'login_redirect', $redirect_to, $_request_redirect_to, $user )
); );
exit; exit( 0 );
} }
add_filter( 'jetpack_sso_default_to_sso_login', '__return_false' ); add_filter( 'jetpack_sso_default_to_sso_login', '__return_false' );
@ -1207,7 +1207,7 @@ class SSO {
add_filter( 'allowed_redirect_hosts', array( Helpers::class, 'allowed_redirect_hosts' ) ); add_filter( 'allowed_redirect_hosts', array( Helpers::class, 'allowed_redirect_hosts' ) );
wp_safe_redirect( $connect_url ); wp_safe_redirect( $connect_url );
exit; exit( 0 );
} }
/** /**

View File

@ -11,6 +11,7 @@ use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Connection\Client; use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager; use Automattic\Jetpack\Connection\Manager;
use Automattic\Jetpack\Connection\Package_Version; use Automattic\Jetpack\Connection\Package_Version;
use Automattic\Jetpack\Connection\Users_Connection_Admin as Base_Admin;
use Automattic\Jetpack\Roles; use Automattic\Jetpack\Roles;
use Automattic\Jetpack\Status\Host; use Automattic\Jetpack\Status\Host;
use Automattic\Jetpack\Tracking; use Automattic\Jetpack\Tracking;
@ -21,7 +22,7 @@ use WP_User_Query;
/** /**
* Jetpack sso user admin class. * Jetpack sso user admin class.
*/ */
class User_Admin { class User_Admin extends Base_Admin {
/** /**
* Instance of WP_User_Query. * Instance of WP_User_Query.
* *
@ -56,16 +57,20 @@ class User_Admin {
add_action( 'user_new_form', array( $this, 'render_custom_email_message_form_field' ), 1 ); add_action( 'user_new_form', array( $this, 'render_custom_email_message_form_field' ), 1 );
add_action( 'delete_user_form', array( $this, 'render_invitations_notices_for_deleted_users' ) ); add_action( 'delete_user_form', array( $this, 'render_invitations_notices_for_deleted_users' ) );
add_action( 'delete_user', array( $this, 'revoke_user_invite' ) ); add_action( 'delete_user', array( $this, 'revoke_user_invite' ) );
add_filter( 'manage_users_columns', array( $this, 'jetpack_user_connected_th' ) );
add_filter( 'manage_users_custom_column', array( $this, 'jetpack_show_connection_status' ), 10, 3 ); add_filter( 'manage_users_custom_column', array( $this, 'jetpack_show_connection_status' ), 10, 3 );
add_action( 'user_row_actions', array( $this, 'jetpack_user_table_row_actions' ), 10, 2 ); add_action( 'user_row_actions', array( $this, 'jetpack_user_table_row_actions' ), 10, 2 );
if ( isset( $_GET['jetpack-sso-invite-user'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) ); add_action( 'admin_notices', array( $this, 'handle_invitation_results' ) );
}
add_action( 'admin_post_jetpack_invite_user_to_wpcom', array( $this, 'invite_user_to_wpcom' ) ); add_action( 'admin_post_jetpack_invite_user_to_wpcom', array( $this, 'invite_user_to_wpcom' ) );
add_action( 'admin_post_jetpack_revoke_invite_user_to_wpcom', array( $this, 'handle_request_revoke_invite' ) ); add_action( 'admin_post_jetpack_revoke_invite_user_to_wpcom', array( $this, 'handle_request_revoke_invite' ) );
add_action( 'admin_post_jetpack_resend_invite_user_to_wpcom', array( $this, 'handle_request_resend_invite' ) ); add_action( 'admin_post_jetpack_resend_invite_user_to_wpcom', array( $this, 'handle_request_resend_invite' ) );
add_action( 'admin_print_styles-users.php', array( $this, 'jetpack_user_table_styles' ) ); add_action( 'admin_print_styles-users.php', array( $this, 'jetpack_user_table_styles' ) );
add_filter( 'users_list_table_query_args', array( $this, 'set_user_query' ), 100, 1 ); add_filter( 'users_list_table_query_args', array( $this, 'set_user_query' ), 100, 1 );
add_action( 'admin_print_styles-user-new.php', array( $this, 'jetpack_new_users_styles' ) ); add_action( 'admin_print_styles-user-new.php', array( $this, 'jetpack_new_users_styles' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
self::$tracking = new Tracking(); self::$tracking = new Tracking();
} }
@ -102,6 +107,7 @@ class User_Admin {
* Revokes WordPress.com invitation. * Revokes WordPress.com invitation.
* *
* @param int $user_id The user ID. * @param int $user_id The user ID.
* @return mixed Response from the API call or false on failure.
*/ */
public function revoke_user_invite( $user_id ) { public function revoke_user_invite( $user_id ) {
try { try {
@ -970,39 +976,14 @@ class User_Admin {
} }
/** /**
* Adds a column in the user admin table to display user connection status and actions. * Deprecated method. Adds a column in the user admin table to display user connection status and actions.
* *
* @param array $columns User list table columns. * @param array $columns User list table columns.
*
* @return array * @return array
* @deprecated 6.5.0
*/ */
public function jetpack_user_connected_th( $columns ) { public function jetpack_user_connected_th( $columns ) {
Assets::register_script( _deprecated_function( __METHOD__, 'package-6.5.0' );
'jetpack-sso-users',
'../../dist/jetpack-sso-users.js',
__FILE__,
array(
'strategy' => 'defer',
'in_footer' => true,
'enqueue' => true,
'version' => Package_Version::PACKAGE_VERSION,
)
);
$tooltip_string = esc_attr__( 'Jetpack SSO allows a seamless and secure experience on WordPress.com. Join millions of WordPress users who trust us to keep their accounts safe.', 'jetpack-connection' );
wp_add_inline_script(
'jetpack-sso-users',
"var Jetpack_SSOTooltip = { 'tooltipString': '{$tooltip_string}' }",
'before'
);
$columns['user_jetpack'] = sprintf(
'<span class="jetpack-sso-invitation-tooltip-icon jetpack-sso-status-column" role="tooltip" aria-label="%3$s: %1$s" tabindex="0">%2$s</span>',
$tooltip_string,
esc_html__( 'SSO Status', 'jetpack-connection' ),
esc_attr__( 'Tooltip', 'jetpack-connection' )
);
return $columns; return $columns;
} }
@ -1175,31 +1156,30 @@ class User_Admin {
* @param string $val HTML for the column. * @param string $val HTML for the column.
* @param string $col User list table column. * @param string $col User list table column.
* @param int $user_id User ID. * @param int $user_id User ID.
* * @return string Modified column content.
* @return string
*/ */
public function jetpack_show_connection_status( $val, $col, $user_id ) { public function jetpack_show_connection_status( $val, $col, $user_id ) {
if ( 'user_jetpack' === $col ) { if ( 'user_jetpack' !== $col ) {
if ( ( new Manager() )->is_user_connected( $user_id ) ) { return $val;
$connection_html = sprintf( }
'<span title="%1$s" class="jetpack-sso-invitation">%2$s</span>',
esc_attr__( 'This user is connected and can log-in to this site.', 'jetpack-connection' ), // Get base connection status from parent
esc_html__( 'Connected', 'jetpack-connection' ) $connection_status = parent::render_connection_column( '', $col, $user_id );
);
return $connection_html; // If user is not connected, check for pending invite
} else { if ( ! $connection_status ) {
$has_pending_invite = self::has_pending_wpcom_invite( $user_id ); $has_pending_invite = self::has_pending_wpcom_invite( $user_id );
if ( $has_pending_invite ) { if ( $has_pending_invite ) {
$connection_html = sprintf( return sprintf(
'<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>', '<span title="%1$s" class="jetpack-sso-invitation sso-pending-invite">%2$s</span>',
esc_attr__( 'This user didn&#8217;t accept the invitation to join this site yet.', 'jetpack-connection' ), esc_attr__( 'This user didn&#8217;t accept the invitation to join this site yet.', 'jetpack-connection' ),
esc_html__( 'Pending invite', 'jetpack-connection' ) esc_html__( 'Pending invite', 'jetpack-connection' )
); );
return $connection_html;
} }
// Show invite button for non-connected users
$nonce = wp_create_nonce( 'jetpack-sso-invite-user' ); $nonce = wp_create_nonce( 'jetpack-sso-invite-user' );
$connection_html = sprintf( return sprintf(
// Using formmethod and formaction because we can't nest forms and have to submit using the main form.
'<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user"> '<span tabindex="0" role="tooltip" aria-label="%4$s: %3$s" class="jetpack-sso-invitation-tooltip-icon sso-disconnected-user">
<a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a> <a href="%1$s" class="jetpack-sso-invitation sso-disconnected-user">%2$s</a>
<span class="sso-disconnected-user-icon dashicons dashicons-warning"> <span class="sso-disconnected-user-icon dashicons dashicons-warning">
@ -1215,19 +1195,19 @@ class User_Admin {
admin_url( 'admin-post.php' ) admin_url( 'admin-post.php' )
), ),
esc_html__( 'Send invite', 'jetpack-connection' ), esc_html__( 'Send invite', 'jetpack-connection' ),
esc_attr__( 'This user doesn&#8217;t have an SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ), esc_attr__( 'This user doesn&#8217;t have a Jetpack SSO connection to WordPress.com. Invite them to the site to increase security and improve their experience.', 'jetpack-connection' ),
esc_attr__( 'Tooltip', 'jetpack-connection' ) esc_attr__( 'Tooltip', 'jetpack-connection' )
); );
return $connection_html;
} }
}
return $val; return $connection_status;
} }
/** /**
* Creates error notices and redirects the user to the previous page. * Creates error notices and redirects the user to the previous page.
* *
* @param array $query_params - query parameters added to redirection URL. * @param array $query_params - query parameters added to redirection URL.
* @phan-suppress PhanPluginNeverReturnMethod
*/ */
public function create_error_notice_and_redirect( $query_params ) { public function create_error_notice_and_redirect( $query_params ) {
$ref = wp_get_referer(); $ref = wp_get_referer();
@ -1239,7 +1219,8 @@ class User_Admin {
$query_params, $query_params,
$ref $ref
); );
return wp_safe_redirect( $url ); wp_safe_redirect( $url );
exit;
} }
/** /**
@ -1254,9 +1235,6 @@ class User_Admin {
#the-list tr:has(.sso-pending-invite) { #the-list tr:has(.sso-pending-invite) {
background: #E9F0F5; background: #E9F0F5;
} }
.fixed .column-user_jetpack {
width: 100px;
}
.jetpack-sso-invitation { .jetpack-sso-invitation {
background: none; background: none;
border: none; border: none;
@ -1293,9 +1271,6 @@ class User_Admin {
position: relative; position: relative;
cursor: pointer; cursor: pointer;
} }
.jetpack-sso-th-tooltip {
left: -170px;
}
.jetpack-sso-td-tooltip { .jetpack-sso-td-tooltip {
left: -256px; left: -256px;
} }
@ -1319,4 +1294,29 @@ class User_Admin {
</style> </style>
<?php <?php
} }
/**
* Enqueue SSO-specific scripts.
*
* @param string $hook The current admin page.
*/
public function enqueue_scripts( $hook ) {
if ( 'users.php' !== $hook ) {
return;
}
parent::enqueue_scripts( $hook );
// Enqueue the SSO users script.
Assets::register_script(
'jetpack-sso-users',
'../../dist/jetpack-sso-users.js',
__FILE__,
array(
'strategy' => 'defer',
'in_footer' => true,
'enqueue' => true,
'version' => Package_Version::PACKAGE_VERSION,
)
);
}
} }

View File

@ -5,7 +5,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
tooltip.innerHTML += ' [?]'; tooltip.innerHTML += ' [?]';
const tooltipTextbox = document.createElement( 'span' ); const tooltipTextbox = document.createElement( 'span' );
tooltipTextbox.classList.add( 'jetpack-sso-invitation-tooltip', 'jetpack-sso-th-tooltip' ); tooltipTextbox.classList.add( 'jetpack-sso-invitation-tooltip' );
const tooltipString = window.Jetpack_SSOTooltip.tooltipString; const tooltipString = window.Jetpack_SSOTooltip.tooltipString;
tooltipTextbox.innerHTML += tooltipString; tooltipTextbox.innerHTML += tooltipString;
@ -28,7 +28,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
*/ */
function removeTooltip() { function removeTooltip() {
// Only remove tooltip if the element isn't currently active. // Only remove tooltip if the element isn't currently active.
if ( document.activeElement === tooltip ) { if ( tooltip.ownerDocument.activeElement === tooltip ) {
return; return;
} }
tooltip.removeChild( tooltipTextbox ); tooltip.removeChild( tooltipTextbox );
@ -56,7 +56,7 @@ document.addEventListener( 'DOMContentLoaded', function () {
* @param {Event} event - Triggering event. * @param {Event} event - Triggering event.
*/ */
function removeSSOInvitationTooltip( event ) { function removeSSOInvitationTooltip( event ) {
if ( document.activeElement === event.target ) { if ( event.target.ownerDocument.activeElement === event.target ) {
return; return;
} }
this.querySelector( '.jetpack-sso-invitation-tooltip' ).style.display = 'none'; this.querySelector( '.jetpack-sso-invitation-tooltip' ).style.display = 'none';

View File

@ -0,0 +1,151 @@
<?php
/**
* Trait WPCOM_REST_API_Proxy_Request
*
* Used to proxy requests to wpcom servers.
*
* @package automattic/jetpack-connection
*/
namespace Automattic\Jetpack\Connection\Traits;
use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager;
use Automattic\Jetpack\Status\Visitor;
use WP_Error;
use WP_REST_Request;
trait WPCOM_REST_API_Proxy_Request {
/**
* Base path for the API.
*
* @var string
*/
protected $base_api_path;
/**
* Version of the API.
*
* @var string
*/
protected $version;
/**
* The base of the controller's route.
*
* @var string
*/
protected $rest_base;
/**
* Proxy request to wpcom servers on behalf of a user or using the Site-level Connection (blog token).
*
* @param WP_REST_Request $request Request to proxy.
* @param string $path Path to append to the rest base.
* @param string $context Whether the request should be proxied on behalf of the current user or using the Site-level Connection, aka 'blog' token. Can be Either 'user' or 'blog'. Defaults to 'user'.
* @param bool $allow_fallback_to_blog If the $context is 'user', whether we should fallback to using the Site-level Connection in case the current user is not connected.
* @param array $request_options Request options to pass to wp_remote_request.
*
* @return mixed|WP_Error Response from wpcom servers or an error.
*/
public function proxy_request_to_wpcom( $request, $path = '', $context = 'user', $allow_fallback_to_blog = false, $request_options = array() ) {
$blog_id = \Jetpack_Options::get_option( 'id' );
$path = '/sites/' . rawurldecode( $blog_id ) . '/' . rawurldecode( ltrim( $this->rest_base, '/' ) ) . ( $path ? '/' . rawurldecode( ltrim( $path, '/' ) ) : '' );
$query_params = $request->get_query_params();
$manager = new Manager();
/*
* A rest_route parameter can be added when using plain permalinks.
* It is not necessary to pass them to WordPress.com,
* and may even cause issues with some endpoints.
* Let's remove it.
*/
if ( isset( $query_params['rest_route'] ) ) {
unset( $query_params['rest_route'] );
}
$api_url = add_query_arg( $query_params, $path );
$request_options = array_replace_recursive(
array(
'headers' => array(
'Content-Type' => 'application/json',
'X-Forwarded-For' => ( new Visitor() )->get_ip( true ),
),
'method' => $request->get_method(),
),
$request_options
);
// If no body is present, passing it as $request->get_body() will cause an error.
$body = $request->get_body() ? $request->get_body() : null;
$response = new WP_Error(
'rest_unauthorized',
__( 'Please connect your user account to WordPress.com', 'jetpack-connection' ),
array( 'status' => rest_authorization_required_code() )
);
if ( 'user' === $context ) {
if ( ! $manager->is_user_connected() ) {
if ( false === $allow_fallback_to_blog ) {
return $response;
}
$context = 'blog';
} else {
$response = Client::wpcom_json_api_request_as_user( $api_url, $this->version, $request_options, $body, $this->base_api_path );
}
}
if ( 'blog' === $context ) {
if ( ! $manager->is_connected() ) {
return $response;
}
$response = Client::wpcom_json_api_request_as_blog( $api_url, $this->version, $request_options, $body, $this->base_api_path );
}
if ( is_wp_error( $response ) ) {
return $response;
}
$response_status = wp_remote_retrieve_response_code( $response );
$response_body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( $response_status >= 400 ) {
$code = $response_body['code'] ?? 'unknown_error';
$message = $response_body['message'] ?? __( 'An unknown error occurred.', 'jetpack-connection' );
return new WP_Error( $code, $message, array( 'status' => $response_status ) );
}
return $response_body;
}
/**
* Proxy request to wpcom servers on behalf of a user.
*
* @param WP_REST_Request $request Request to proxy.
* @param string $path Path to append to the rest base.
* @param array $request_options Request options to pass to wp_remote_request.
*
* @return mixed|WP_Error Response from wpcom servers or an error.
*/
public function proxy_request_to_wpcom_as_user( $request, $path = '', $request_options = array() ) {
return $this->proxy_request_to_wpcom( $request, $path, 'user', false, $request_options );
}
/**
* Proxy request to wpcom servers using the Site-level Connection (blog token).
*
* @param WP_REST_Request $request Request to proxy.
* @param string $path Path to append to the rest base.
* @param array $request_options Request options to pass to wp_remote_request.
*
* @return mixed|WP_Error Response from wpcom servers or an error.
*/
public function proxy_request_to_wpcom_as_blog( $request, $path = '', $request_options = array() ) {
return $this->proxy_request_to_wpcom( $request, $path, 'blog', false, $request_options );
}
}

View File

@ -63,7 +63,7 @@ class Authorize_Redirect {
if ( ! $dest_url || ( 0 === stripos( $dest_url, 'https://jetpack.com/' ) && 0 === stripos( $dest_url, 'https://wordpress.com/' ) ) ) { if ( ! $dest_url || ( 0 === stripos( $dest_url, 'https://jetpack.com/' ) && 0 === stripos( $dest_url, 'https://wordpress.com/' ) ) ) {
// The destination URL is missing or invalid, nothing to do here. // The destination URL is missing or invalid, nothing to do here.
exit; exit( 0 );
} }
// The user is either already connected, or finished the connection process. // The user is either already connected, or finished the connection process.
@ -73,12 +73,12 @@ class Authorize_Redirect {
} }
wp_safe_redirect( $dest_url ); wp_safe_redirect( $dest_url );
exit; exit( 0 );
} elseif ( ! empty( $_GET['done'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended } elseif ( ! empty( $_GET['done'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
// The user decided not to proceed with setting up the connection. // The user decided not to proceed with setting up the connection.
wp_safe_redirect( Admin_Menu::get_top_level_menu_item_url() ); wp_safe_redirect( Admin_Menu::get_top_level_menu_item_url() );
exit; exit( 0 );
} }
$redirect_args = array( $redirect_args = array(
@ -94,29 +94,66 @@ class Authorize_Redirect {
} }
wp_safe_redirect( $this->build_authorize_url( add_query_arg( $redirect_args, admin_url( 'admin.php' ) ) ) ); wp_safe_redirect( $this->build_authorize_url( add_query_arg( $redirect_args, admin_url( 'admin.php' ) ) ) );
exit; exit( 0 );
} }
/** /**
* Create the Jetpack authorization URL. * Create the Jetpack authorization URL.
* *
* @since 2.7.6 Added optional $from and $raw parameters. * @since 2.7.6 Added optional $from and $raw parameters.
* @since 6.8.0 Added optional $provider and $provider_args parameters.
* *
* @param bool|string $redirect URL to redirect to. * @param bool|string $redirect URL to redirect to.
* @param bool|string $from If not false, adds 'from=$from' param to the connect URL. * @param bool|string $from If not false, adds 'from=$from' param to the connect URL.
* @param bool $raw If true, URL will not be escaped. * @param bool $raw If true, URL will not be escaped.
* @param string|null $provider The authentication provider (google, github, apple, link).
* @param array|null $provider_args Additional provider-specific arguments.
* *
* @todo Update default value for redirect since the called function expects a string. * @todo Update default value for redirect since the called function expects a string.
* *
* @return mixed|void * @return mixed|void
*/ */
public function build_authorize_url( $redirect = false, $from = false, $raw = false ) { public function build_authorize_url( $redirect = false, $from = false, $raw = false, $provider = null, $provider_args = null ) {
add_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); add_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) );
add_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); add_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) );
$url = $this->connection->get_authorization_url( wp_get_current_user(), $redirect, $from, $raw ); $url = $this->connection->get_authorization_url( wp_get_current_user(), $redirect, $from, $raw );
// If a provider is specified, modify the URL to use the provider-specific endpoint
if ( $provider && in_array( $provider, array( 'google', 'github', 'apple', 'link' ), true ) ) {
// Parse the URL to modify it safely
$url_parts = wp_parse_url( $url );
if ( ! empty( $url_parts['host'] ) && ! empty( $url_parts['path'] ) ) {
// Build the new URL using wordpress.com as the host
$url_parts['host'] = 'wordpress.com';
$url_parts['path'] = '/log-in/jetpack/' . $provider;
// Preserve the query parameters
$query_params = array();
if ( ! empty( $url_parts['query'] ) ) {
parse_str( $url_parts['query'], $query_params );
}
// Add magic link specific parameters if provider is 'link'
if ( 'link' === $provider && is_array( $provider_args ) && ! empty( $provider_args['email_address'] ) ) {
$query_params['email_address'] = $provider_args['email_address'];
// Add flag to trigger magic link flow
$query_params['auto_trigger'] = '1';
}
// URL encode all parameter values
$query_params = array_map( 'rawurlencode', $query_params );
// Rebuild the URL
$url = 'https://' . $url_parts['host'] . $url_parts['path'];
if ( ! empty( $query_params ) ) {
$url = add_query_arg( $query_params, $url );
}
}
}
remove_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) ); remove_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) );
remove_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) ); remove_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) );
@ -125,11 +162,14 @@ class Authorize_Redirect {
* *
* @since jetpack-8.9.0 * @since jetpack-8.9.0
* @since 2.7.6 Added $raw parameter. * @since 2.7.6 Added $raw parameter.
* @since 6.8.0 Added $provider and $provider_args parameters.
* *
* @param string $url Connection URL. * @param string $url Connection URL.
* @param bool $raw If true, URL will not be escaped. * @param bool $raw If true, URL will not be escaped.
* @param string|null $provider The authentication provider if specified.
* @param array|null $provider_args Additional provider-specific arguments.
*/ */
return apply_filters( 'jetpack_build_authorize_url', $url, $raw ); return apply_filters( 'jetpack_build_authorize_url', $url, $raw, $provider, $provider_args );
} }
/** /**

View File

@ -5,6 +5,34 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.0.5] - 2025-03-21
### Changed
- Internal updates.
## [3.0.4] - 2025-03-12
### Changed
- Internal updates.
## [3.0.3] - 2025-03-05
### Changed
- Internal updates.
## [3.0.2] - 2025-02-24
### Changed
- Update dependencies.
## [3.0.1] - 2024-11-25
### Changed
- Updated package dependencies. [#40258]
## [3.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [2.0.5] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [2.0.4] - 2024-08-23 ## [2.0.4] - 2024-08-23
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -174,6 +202,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Packages: Finish the constants package - Packages: Finish the constants package
[3.0.5]: https://github.com/Automattic/jetpack-constants/compare/v3.0.4...v3.0.5
[3.0.4]: https://github.com/Automattic/jetpack-constants/compare/v3.0.3...v3.0.4
[3.0.3]: https://github.com/Automattic/jetpack-constants/compare/v3.0.2...v3.0.3
[3.0.2]: https://github.com/Automattic/jetpack-constants/compare/v3.0.1...v3.0.2
[3.0.1]: https://github.com/Automattic/jetpack-constants/compare/v3.0.0...v3.0.1
[3.0.0]: https://github.com/Automattic/jetpack-constants/compare/v2.0.5...v3.0.0
[2.0.5]: https://github.com/Automattic/jetpack-constants/compare/v2.0.4...v2.0.5
[2.0.4]: https://github.com/Automattic/jetpack-constants/compare/v2.0.3...v2.0.4 [2.0.4]: https://github.com/Automattic/jetpack-constants/compare/v2.0.3...v2.0.4
[2.0.3]: https://github.com/Automattic/jetpack-constants/compare/v2.0.2...v2.0.3 [2.0.3]: https://github.com/Automattic/jetpack-constants/compare/v2.0.2...v2.0.3
[2.0.2]: https://github.com/Automattic/jetpack-constants/compare/v2.0.1...v2.0.2 [2.0.2]: https://github.com/Automattic/jetpack-constants/compare/v2.0.1...v2.0.2

View File

@ -4,12 +4,13 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"brain/monkey": "2.6.1", "brain/monkey": "^2.6.2",
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -21,7 +22,10 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -36,7 +40,7 @@
"link-template": "https://github.com/Automattic/jetpack-constants/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-constants/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "2.0.x-dev" "dev-trunk": "3.0.x-dev"
} }
} }
} }

View File

@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [3.0.5] - 2025-03-21
### Changed
- Internal updates.
## [3.0.4] - 2025-03-17
### Changed
- Internal updates.
## [3.0.3] - 2025-03-12
### Changed
- Internal updates.
## [3.0.2] - 2025-03-05
### Changed
- Internal updates.
## [3.0.1] - 2025-02-24
### Changed
- Update dependencies.
## [3.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [2.1.6] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [2.1.5] - 2024-09-16
### Changed
- Device_Detection::get_info() will now memoize its result [#39338]
## [2.1.4] - 2024-08-23 ## [2.1.4] - 2024-08-23
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -200,6 +232,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Moving jetpack_is_mobile into a package - Moving jetpack_is_mobile into a package
[3.0.5]: https://github.com/Automattic/jetpack-device-detection/compare/v3.0.4...v3.0.5
[3.0.4]: https://github.com/Automattic/jetpack-device-detection/compare/v3.0.3...v3.0.4
[3.0.3]: https://github.com/Automattic/jetpack-device-detection/compare/v3.0.2...v3.0.3
[3.0.2]: https://github.com/Automattic/jetpack-device-detection/compare/v3.0.1...v3.0.2
[3.0.1]: https://github.com/Automattic/jetpack-device-detection/compare/v3.0.0...v3.0.1
[3.0.0]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.6...v3.0.0
[2.1.6]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.5...v2.1.6
[2.1.5]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.4...v2.1.5
[2.1.4]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.3...v2.1.4 [2.1.4]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.3...v2.1.4
[2.1.3]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.2...v2.1.3 [2.1.3]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.2...v2.1.3
[2.1.2]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.1...v2.1.2 [2.1.2]: https://github.com/Automattic/jetpack-device-detection/compare/v2.1.1...v2.1.2

View File

@ -4,11 +4,12 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -20,7 +21,10 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -35,7 +39,7 @@
"link-template": "https://github.com/Automattic/jetpack-device-detection/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-device-detection/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "2.1.x-dev" "dev-trunk": "3.0.x-dev"
} }
} }
} }

View File

@ -23,6 +23,20 @@ use function Automattic\Jetpack\Device_Detection\wp_unslash;
*/ */
class Device_Detection { class Device_Detection {
/**
* Memoization cache for get_info() results.
*
* @var array
*/
private static $get_info_memo = array();
/**
* Maximum size of the memoization cache.
*
* @var int
*/
private static $max_memo_size = 100;
/** /**
* Returns information about the current device accessing the page. * Returns information about the current device accessing the page.
* *
@ -41,6 +55,16 @@ class Device_Detection {
* ); * );
*/ */
public static function get_info( $ua = '' ) { public static function get_info( $ua = '' ) {
// Return memoized result if available.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput
$memo_key = ! empty( $ua ) ? $ua : ( $_SERVER['HTTP_USER_AGENT'] ?? '' );
// Note: UA string used raw for compatibility reasons.
// No sanitization is needed as the value is never output or persisted, and is only used for memoization.
// phpcs:enable WordPress.Security.ValidatedSanitizedInput
if ( isset( self::$get_info_memo[ $memo_key ] ) ) {
return self::$get_info_memo[ $memo_key ];
}
$ua_info = new User_Agent_Info( $ua ); $ua_info = new User_Agent_Info( $ua );
$info = array( $info = array(
@ -68,6 +92,13 @@ class Device_Detection {
*/ */
$info = apply_filters( 'jetpack_device_detection_get_info', $info, $ua, $ua_info ); $info = apply_filters( 'jetpack_device_detection_get_info', $info, $ua, $ua_info );
} }
// Memoize the result.
self::$get_info_memo[ $memo_key ] = $info;
if ( count( self::$get_info_memo ) > self::$max_memo_size ) {
array_shift( self::$get_info_memo );
}
return $info; return $info;
} }

View File

@ -5,6 +5,94 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.2.13] - 2025-03-21
### Changed
- Internal updates.
## [0.2.12] - 2025-03-18
### Changed
- Update package dependencies. [#42511]
## [0.2.11] - 2025-03-12
### Changed
- Internal updates.
## [0.2.10] - 2025-03-05
### Changed
- Internal updates.
## [0.2.9] - 2025-03-03
### Changed
- Update package dependencies. [#42163]
## [0.2.8] - 2025-02-24
### Changed
- Update dependencies.
## [0.2.7] - 2025-02-17
### Changed
- Update dependencies.
## [0.2.6] - 2025-02-10
### Changed
- Updated package dependencies. [#41491]
## [0.2.5] - 2025-02-03
### Changed
- Updated package dependencies. [#41286]
## [0.2.4] - 2025-01-20
### Changed
- Updated package dependencies. [#41099]
## [0.2.3] - 2024-12-16
### Changed
- Updated package dependencies. [#40564]
## [0.2.2] - 2024-12-04
### Changed
- Updated package dependencies. [#40363] [#40372]
## [0.2.1] - 2024-11-25
### Changed
- Updated package dependencies. [#40232] [#40288]
## [0.2.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.1.15] - 2024-11-11
### Changed
- Updated package dependencies. [#39999] [#40000] [#40060]
## [0.1.14] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [0.1.13] - 2024-10-29
### Changed
- Internal updates.
## [0.1.12] - 2024-10-14
### Changed
- Only include `wp-polyfill` as a script dependency when needed. [#39629]
## [0.1.11] - 2024-10-10
### Changed
- Updated package dependencies. [#39649] [#39707]
## [0.1.10] - 2024-10-07
### Changed
- Updated package dependencies. [#39594]
## [0.1.9] - 2024-09-23
### Changed
- Update dependencies.
## [0.1.8] - 2024-09-10
### Changed
- Updated package dependencies. [#39302]
## [0.1.7] - 2024-09-05 ## [0.1.7] - 2024-09-05
### Changed ### Changed
- Update dependencies. - Update dependencies.
@ -43,6 +131,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- ExPlat: add condition to prevent fetching the experiment assignment if there's not anon id (meaning that Tracks is likely disabled) [#38327] - ExPlat: add condition to prevent fetching the experiment assignment if there's not anon id (meaning that Tracks is likely disabled) [#38327]
- Updated package dependencies. [#38132] - Updated package dependencies. [#38132]
[0.2.13]: https://github.com/Automattic/jetpack-explat/compare/v0.2.12...v0.2.13
[0.2.12]: https://github.com/Automattic/jetpack-explat/compare/v0.2.11...v0.2.12
[0.2.11]: https://github.com/Automattic/jetpack-explat/compare/v0.2.10...v0.2.11
[0.2.10]: https://github.com/Automattic/jetpack-explat/compare/v0.2.9...v0.2.10
[0.2.9]: https://github.com/Automattic/jetpack-explat/compare/v0.2.8...v0.2.9
[0.2.8]: https://github.com/Automattic/jetpack-explat/compare/v0.2.7...v0.2.8
[0.2.7]: https://github.com/Automattic/jetpack-explat/compare/v0.2.6...v0.2.7
[0.2.6]: https://github.com/Automattic/jetpack-explat/compare/v0.2.5...v0.2.6
[0.2.5]: https://github.com/Automattic/jetpack-explat/compare/v0.2.4...v0.2.5
[0.2.4]: https://github.com/Automattic/jetpack-explat/compare/v0.2.3...v0.2.4
[0.2.3]: https://github.com/Automattic/jetpack-explat/compare/v0.2.2...v0.2.3
[0.2.2]: https://github.com/Automattic/jetpack-explat/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/Automattic/jetpack-explat/compare/v0.2.0...v0.2.1
[0.2.0]: https://github.com/Automattic/jetpack-explat/compare/v0.1.15...v0.2.0
[0.1.15]: https://github.com/Automattic/jetpack-explat/compare/v0.1.14...v0.1.15
[0.1.14]: https://github.com/Automattic/jetpack-explat/compare/v0.1.13...v0.1.14
[0.1.13]: https://github.com/Automattic/jetpack-explat/compare/v0.1.12...v0.1.13
[0.1.12]: https://github.com/Automattic/jetpack-explat/compare/v0.1.11...v0.1.12
[0.1.11]: https://github.com/Automattic/jetpack-explat/compare/v0.1.10...v0.1.11
[0.1.10]: https://github.com/Automattic/jetpack-explat/compare/v0.1.9...v0.1.10
[0.1.9]: https://github.com/Automattic/jetpack-explat/compare/v0.1.8...v0.1.9
[0.1.8]: https://github.com/Automattic/jetpack-explat/compare/v0.1.7...v0.1.8
[0.1.7]: https://github.com/Automattic/jetpack-explat/compare/v0.1.6...v0.1.7 [0.1.7]: https://github.com/Automattic/jetpack-explat/compare/v0.1.6...v0.1.7
[0.1.6]: https://github.com/Automattic/jetpack-explat/compare/v0.1.5...v0.1.6 [0.1.6]: https://github.com/Automattic/jetpack-explat/compare/v0.1.5...v0.1.6
[0.1.5]: https://github.com/Automattic/jetpack-explat/compare/v0.1.4...v0.1.5 [0.1.5]: https://github.com/Automattic/jetpack-explat/compare/v0.1.4...v0.1.5

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-polyfill', 'wp-url'), 'version' => '94dc255b5871f56d5cf3'); <?php return array('dependencies' => array('react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-url'), 'version' => '37d1ea057f1a1470ad33');

View File

@ -1,6 +0,0 @@
/*!
* cookie
* Copyright(c) 2012-2014 Roman Shtylman
* Copyright(c) 2015 Douglas Christopher Wilson
* MIT Licensed
*/

View File

@ -4,12 +4,13 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-connection": "^4.0.0" "automattic/jetpack-connection": "^6.7.7"
}, },
"require-dev": { "require-dev": {
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"autoload": { "autoload": {
"classmap": [ "classmap": [
@ -18,13 +19,14 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
], ],
"test-coverage": "pnpm concurrently --names php,js 'php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\"' 'pnpm:test-coverage'",
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
], ],
"test-js": [ "test-js": [
"echo 'Run `pnpm run test` when ready'" "pnpm run test"
], ],
"test-js-watch": [ "test-js-watch": [
"Composer\\Config::disableProcessTimeout", "Composer\\Config::disableProcessTimeout",
@ -46,7 +48,7 @@
"extra": { "extra": {
"autotagger": true, "autotagger": true,
"branch-alias": { "branch-alias": {
"dev-trunk": "0.1.x-dev" "dev-trunk": "0.2.x-dev"
}, },
"changelogger": { "changelogger": {
"link-template": "https://github.com/Automattic/jetpack-explat/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-explat/compare/v${old}...v${new}"

View File

@ -20,7 +20,7 @@ class ExPlat {
* *
* @var string * @var string
*/ */
const PACKAGE_VERSION = '0.1.7'; const PACKAGE_VERSION = '0.2.13';
/** /**
* Initializer. * Initializer.

View File

@ -11,6 +11,8 @@ namespace Automattic\Jetpack\ExPlat;
use Automattic\Jetpack\Connection\Client; use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager as Jetpack_Connection; use Automattic\Jetpack\Connection\Manager as Jetpack_Connection;
use WP_Error; use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server; use WP_REST_Server;
/** /**
@ -71,7 +73,7 @@ class REST_Controller {
* Get the assignments for a given experiment and anon_id * Get the assignments for a given experiment and anon_id
* *
* @param WP_REST_Request $request The REST request object. * @param WP_REST_Request $request The REST request object.
* @return WP_REST_Response * @return WP_REST_Response|WP_Error
*/ */
public function get_assignments( $request ) { public function get_assignments( $request ) {
$response = null; $response = null;

View File

@ -1,7 +1,7 @@
/** /**
* External dependencies * External dependencies
*/ */
import cookie from 'cookie'; import { parse as cookieParse } from 'cookie';
let initializeAnonIdPromise: Promise< string | null > | null = null; let initializeAnonIdPromise: Promise< string | null > | null = null;
const anonIdPollingIntervalMilliseconds = 50; const anonIdPollingIntervalMilliseconds = 50;
@ -13,7 +13,7 @@ const anonIdPollingIntervalMaxAttempts = 100; // 50 * 100 = 5000 = 5 seconds
* @return {?string} The anonymous cookie value, or null if it doesn't exist * @return {?string} The anonymous cookie value, or null if it doesn't exist
*/ */
export const readAnonCookie = (): string | null => { export const readAnonCookie = (): string | null => {
return cookie.parse( document.cookie ).tk_ai || null; return cookieParse( document.cookie ).tk_ai || null;
}; };
/** /**

View File

@ -5,6 +5,45 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.4.6] - 2025-03-21
### Changed
- Internal updates.
## [0.4.5] - 2025-03-17
### Changed
- Internal updates.
## [0.4.4] - 2025-03-12
### Changed
- Internal updates.
## [0.4.3] - 2025-03-05
### Changed
- Internal updates.
## [0.4.2] - 2025-02-24
### Changed
- Update dependencies.
## [0.4.1] - 2024-11-25
### Changed
- Update package dependencies. [#40258]
## [0.4.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [0.3.1] - 2024-11-04
### Added
- Enable test coverage. [#39961]
### Fixed
- Fix PHPUnit coverage warnings. [#39989]
## [0.3.0] - 2024-09-23
### Added
- IP Utils: added support for CIDR ranges. [#39425]
## [0.2.3] - 2024-08-23 ## [0.2.3] - 2024-08-23
### Changed ### Changed
- Updated package dependencies. [#39004] - Updated package dependencies. [#39004]
@ -51,6 +90,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add jetpack-ip package functionality [#28846] - Add jetpack-ip package functionality [#28846]
- Initialized the package. [#28765] - Initialized the package. [#28765]
[0.4.6]: https://github.com/automattic/jetpack-ip/compare/v0.4.5...v0.4.6
[0.4.5]: https://github.com/automattic/jetpack-ip/compare/v0.4.4...v0.4.5
[0.4.4]: https://github.com/automattic/jetpack-ip/compare/v0.4.3...v0.4.4
[0.4.3]: https://github.com/automattic/jetpack-ip/compare/v0.4.2...v0.4.3
[0.4.2]: https://github.com/automattic/jetpack-ip/compare/v0.4.1...v0.4.2
[0.4.1]: https://github.com/automattic/jetpack-ip/compare/v0.4.0...v0.4.1
[0.4.0]: https://github.com/automattic/jetpack-ip/compare/v0.3.1...v0.4.0
[0.3.1]: https://github.com/automattic/jetpack-ip/compare/v0.3.0...v0.3.1
[0.3.0]: https://github.com/automattic/jetpack-ip/compare/v0.2.3...v0.3.0
[0.2.3]: https://github.com/automattic/jetpack-ip/compare/v0.2.2...v0.2.3 [0.2.3]: https://github.com/automattic/jetpack-ip/compare/v0.2.2...v0.2.3
[0.2.2]: https://github.com/automattic/jetpack-ip/compare/v0.2.1...v0.2.2 [0.2.2]: https://github.com/automattic/jetpack-ip/compare/v0.2.1...v0.2.2
[0.2.1]: https://github.com/automattic/jetpack-ip/compare/v0.2.0...v0.2.1 [0.2.1]: https://github.com/automattic/jetpack-ip/compare/v0.2.0...v0.2.1

View File

@ -4,12 +4,13 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0" "php": ">=7.2"
}, },
"require-dev": { "require-dev": {
"brain/monkey": "2.6.1", "brain/monkey": "^2.6.2",
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -21,7 +22,10 @@
}, },
"scripts": { "scripts": {
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -36,7 +40,7 @@
"link-template": "https://github.com/automattic/jetpack-ip/compare/v${old}...v${new}" "link-template": "https://github.com/automattic/jetpack-ip/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "0.2.x-dev" "dev-trunk": "0.4.x-dev"
}, },
"textdomain": "jetpack-ip", "textdomain": "jetpack-ip",
"version-constants": { "version-constants": {

View File

@ -12,7 +12,7 @@ namespace Automattic\Jetpack\IP;
*/ */
class Utils { class Utils {
const PACKAGE_VERSION = '0.2.3'; const PACKAGE_VERSION = '0.4.6';
/** /**
* Get the current user's IP address. * Get the current user's IP address.
@ -116,6 +116,31 @@ class Utils {
return false; return false;
} }
/**
* Validate an IP address.
*
* @param string $ip IP address.
* @return bool True if valid, false otherwise.
*/
private static function validate_ip_address( string $ip ) {
return filter_var( $ip, FILTER_VALIDATE_IP );
}
/**
* Validate an array of IP addresses.
*
* @param array $ips List of IP addresses.
* @return bool True if all IPs are valid, false otherwise.
*/
private static function validate_ip_addresses( array $ips ) {
foreach ( $ips as $ip ) {
if ( ! self::validate_ip_address( $ip ) ) {
return false;
}
}
return true;
}
/** /**
* Uses inet_pton if available to convert an IP address to a binary string. * Uses inet_pton if available to convert an IP address to a binary string.
* Returns false if an invalid IP address is given. * Returns false if an invalid IP address is given.
@ -128,40 +153,47 @@ class Utils {
} }
/** /**
* Checks that a given IP address is within a given low - high range. * Determines the IP version of the given IP address.
* *
* @param mixed $ip IP. * @param string $ip IP address.
* @param mixed $range_low Range Low. * @return string|false 'ipv4', 'ipv6', or false if invalid.
* @param mixed $range_high Range High.
* @return Bool
*/ */
public static function ip_address_is_in_range( $ip, $range_low, $range_high ) { public static function get_ip_version( $ip ) {
$ip_num = inet_pton( $ip ); if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
$ip_low = inet_pton( $range_low ); return 'ipv4';
$ip_high = inet_pton( $range_high ); } elseif ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
if ( $ip_num && $ip_low && $ip_high && strcmp( $ip_num, $ip_low ) >= 0 && strcmp( $ip_num, $ip_high ) <= 0 ) { return 'ipv6';
return true; } else {
}
return false; return false;
} }
}
/** /**
* Extracts IP addresses from a given string. * Extracts IP addresses from a given string.
* *
* We allow for both, one IP per line or comma-; semicolon; or whitespace-separated lists. This also validates the IP addresses * Supports IPv4 and IPv6 ranges in both hyphen and CIDR notation.
* and only returns the ones that look valid. IP ranges using the "-" character are also supported.
* *
* @param string $ips List of ips - example: "8.8.8.8\n4.4.4.4,2.2.2.2;1.1.1.1 9.9.9.9,5555.5555.5555.5555,1.1.1.10-1.1.1.20". * @param string $ips List of IPs.
* @return array List of valid IP addresses. - example based on input example: array('8.8.8.8', '4.4.4.4', '2.2.2.2', '1.1.1.1', '9.9.9.9', '1.1.1.10-1.1.1.20') * @return array List of valid IP addresses or ranges.
*/ */
public static function get_ip_addresses_from_string( $ips ) { public static function get_ip_addresses_from_string( $ips ) {
$ips = (string) $ips; // Split the string by spaces, commas, and semicolons.
$ips = preg_split( '/[\s,;]/', $ips ); $ips = preg_split( '/[\s,;]/', (string) $ips );
$result = array(); $result = array();
foreach ( $ips as $ip ) { foreach ( $ips as $ip ) {
// Validate both IP values from the range. $ip = trim( $ip );
// Check for CIDR notation
if ( strpos( $ip, '/' ) !== false ) {
if ( self::validate_cidr( $ip ) ) {
$result[] = $ip;
}
continue;
}
// Validate both IP values from the hyphen range.
$range = explode( '-', $ip ); $range = explode( '-', $ip );
if ( count( $range ) === 2 ) { if ( count( $range ) === 2 ) {
if ( self::validate_ip_range( $range[0], $range[1] ) ) { if ( self::validate_ip_range( $range[0], $range[1] ) ) {
@ -179,31 +211,333 @@ class Utils {
return $result; return $result;
} }
/**
* Validates CIDR notation for IPv4 and IPv6 addresses.
*
* @param string $cidr CIDR notation IP address.
* @return bool True if valid, false otherwise.
*/
public static function validate_cidr( $cidr ) {
// Split the CIDR notation into IP address and prefix length using the '/' separator.
$parts = explode( '/', $cidr );
if ( count( $parts ) !== 2 ) {
return false; // Invalid CIDR notation if it doesn't contain exactly one '/'.
}
list( $ip, $netmask ) = $parts;
// Validate the IP address.
if ( ! filter_var( $ip, FILTER_VALIDATE_IP ) ) {
return false;
}
$ip_version = self::get_ip_version( $ip );
if ( ! $ip_version ) {
return false; // Invalid IP address.
}
// Validate the netmask based on the IP version.
if ( ! self::validate_netmask( $netmask, $ip_version ) ) {
return false;
}
return true;
}
/**
* Checks if an IP address is within a CIDR range.
* Supports both IPv4 and IPv6.
*
* @param string $ip IP address.
* @param string $cidr CIDR notation IP range.
* @return bool True if IP is within the range, false otherwise.
*/
public static function ip_in_cidr( $ip, $cidr ) {
// Parse the CIDR notation to extract the base IP address and netmask prefix length.
$parsed_cidr = self::parse_cidr( $cidr );
if ( ! $parsed_cidr ) {
return false;
}
list( $range, $netmask ) = $parsed_cidr;
// Determine the IP version (IPv4 or IPv6) of both the input IP and the CIDR range IP.
$ip_version = self::get_ip_version( $ip );
$range_version = self::get_ip_version( $range );
// Ensure both IP addresses are valid and of the same IP version.
if ( ! $ip_version || ! $range_version || $ip_version !== $range_version ) {
return false;
}
// Validate the netmask based on the IP version.
if ( ! self::validate_netmask( $netmask, $ip_version ) ) {
return false;
}
if ( $ip_version === 'ipv4' ) {
return self::ip_in_ipv4_cidr( $ip, $range, $netmask );
} else {
return self::ip_in_ipv6_cidr( $ip, $range, $netmask );
}
}
/**
* Parses the CIDR notation into network address and netmask.
*
* @param string $cidr CIDR notation IP range.
* @return array|false Array containing network address and netmask, or false on failure.
*/
public static function parse_cidr( $cidr ) {
$cidr_parts = explode( '/', $cidr, 2 );
if ( count( $cidr_parts ) !== 2 ) {
return false; // Invalid CIDR notation
}
list( $range, $netmask ) = $cidr_parts;
// Determine IP version
$ip_version = self::get_ip_version( $range );
if ( ! $ip_version ) {
return false; // Invalid IP address
}
// Validate netmask range
if ( ! self::validate_netmask( $netmask, $ip_version ) ) {
return false; // Netmask out of range
}
return array( $range, (int) $netmask );
}
/**
* Validates the netmask based on IP version.
*
* @param string|int $netmask Netmask value.
* @param string $ip_version 'ipv4' or 'ipv6'.
* @return bool True if valid, false otherwise.
*/
public static function validate_netmask( $netmask, $ip_version ) {
// Ensure that $netmask is an integer
if ( ! ctype_digit( (string) $netmask ) ) {
return false;
}
$netmask = (int) $netmask;
// Validate the netmask based on the IP version.
if ( $ip_version === 'ipv4' ) {
return ( $netmask >= 0 && $netmask <= 32 );
} elseif ( $ip_version === 'ipv6' ) {
return ( $netmask >= 0 && $netmask <= 128 );
} else {
return false;
}
}
/**
* Checks if an IPv4 address is within a CIDR range.
*
* @param string $ip IPv4 address to check.
* @param string $range IPv4 network address.
* @param int $netmask Netmask value.
* @return bool True if IP is within the range, false otherwise.
*/
public static function ip_in_ipv4_cidr( $ip, $range, $netmask ) {
// Validate arguments.
if ( ! self::validate_ip_addresses( array( $ip, $range ) ) || ! self::validate_netmask( $netmask, 'ipv4' ) ) {
return false; // Invalid IP address or netmask.
}
// Convert IP addresses from their dotted representation to 32-bit unsigned integers.
$ip_long = ip2long( $ip );
$range_long = ip2long( $range );
// Check if the conversion was successful.
if ( $ip_long === false || $range_long === false ) {
return false; // One of the IP addresses is invalid.
}
/**
* Create the subnet mask as a 32-bit unsigned integer.
*
* Explanation:
* - (32 - $netmask) calculates the number of host bits (the bits not used for the network address).
* - (1 << (32 - $netmask)) shifts the number 1 left by the number of host bits.
* This results in a number where there is a single 1 followed by zeros equal to the number of host bits.
* - Subtracting 1 gives us a number where the host bits are all 1s.
* - Applying the bitwise NOT operator (~) inverts the bits, turning all host bits to 0 and network bits to 1.
* This results in the subnet mask having 1s in the network portion and 0s in the host portion.
*
* Example for netmask = 24:
* - (32 - 24) = 8
* - (1 << 8) = 256 (binary: 00000000 00000000 00000001 00000000)
* - 256 - 1 = 255 (binary: 00000000 00000000 00000000 11111111)
* - ~255 = 4294967040 (binary: 11111111 11111111 11111111 00000000)
*/
$mask = ~ ( ( 1 << ( 32 - $netmask ) ) - 1 );
/**
* Use bitwise AND to apply the subnet mask to both the IP address and the network address.
* - ($ip_long & $mask) isolates the network portion of the IP address.
* - ($range_long & $mask) isolates the network portion of the CIDR range.
* - If both network portions are equal, the IP address belongs to the same subnet and is within the CIDR range.
*/
return ( $ip_long & $mask ) === ( $range_long & $mask );
}
/**
* Checks if an IPv6 address is within a CIDR range.
*
* @param string $ip IPv6 address to check.
* @param string $range IPv6 network address.
* @param int $netmask Netmask value.
* @return bool True if IP is within the range, false otherwise.
*/
public static function ip_in_ipv6_cidr( $ip, $range, $netmask ) {
// Validate arguments.
if ( ! self::validate_ip_addresses( array( $ip, $range ) ) || ! self::validate_netmask( $netmask, 'ipv6' ) ) {
return false; // Invalid IP address or netmask.
}
// Convert IP addresses from their textual representation to binary strings.
$ip_bin = inet_pton( $ip );
$range_bin = inet_pton( $range );
// Check if the conversion was successful.
if ( $ip_bin === false || $range_bin === false ) {
return false; // One of the IP addresses is invalid.
}
/**
* Calculate the subnet mask in binary form.
*
* IPv6 addresses are 128 bits long.
* The netmask defines how many bits are set to 1 in the subnet mask.
*
* - $netmask_full_bytes: Number of full bytes (each 8 bits) that are all 1s.
* - $netmask_remainder_bits: Remaining bits (less than 8) that need to be set to 1.
*
* For example, if $netmask = 65:
* - $netmask_full_bytes = floor(65 / 8) = 8 (since 8 * 8 = 64 bits)
* - $netmask_remainder_bits = 65 % 8 = 1 (1 bit remaining)
*
* We'll construct the subnet mask by:
* - Starting with $netmask_full_bytes of 0xff (11111111 in binary).
* - Adding a byte where the first $netmask_remainder_bits bits are 1, rest are 0.
* - Padding the rest with zeros to make it 16 bytes (128 bits) long.
*/
// Number of full bytes (each full byte is 8 bits) in the netmask.
$netmask_full_bytes = (int) ( $netmask / 8 );
// Number of remaining bits in the last byte of the netmask.
$netmask_remainder_bits = $netmask % 8;
// Start with a string of $netmask_full_bytes of 0xff bytes (each byte is 8 bits set to 1).
$netmask_bin = str_repeat( "\xff", $netmask_full_bytes );
if ( $netmask_remainder_bits > 0 ) {
// Create the last byte with $netmask_remainder_bits bits set to 1 from the left.
// - str_repeat('1', $netmask_remainder_bits): creates a string with the required number of '1's.
// - str_pad(...): pads the string on the right with '0's to make it 8 bits.
// - bindec(...): converts the binary string to a decimal number.
// - chr(...): gets the character corresponding to the byte value.
$last_byte = chr( bindec( str_pad( str_repeat( '1', $netmask_remainder_bits ), 8, '0', STR_PAD_RIGHT ) ) );
// Append the last byte to the netmask binary string.
$netmask_bin .= $last_byte;
}
// Pad the netmask binary string to 16 bytes (128 bits) with zeros (\x00).
$netmask_bin = str_pad( $netmask_bin, 16, "\x00" );
/**
* Use bitwise AND to apply the subnet mask to both the IP address and the network address.
* - ($ip_bin & $netmask_bin) isolates the network portion of the IP address.
* - ($range_bin & $netmask_bin) isolates the network portion of the CIDR range.
* - If both network portions are equal, the IP address belongs to the same subnet and is within the CIDR range.
*/
return ( $ip_bin & $netmask_bin ) === ( $range_bin & $netmask_bin );
}
/** /**
* Validates the low and high IP addresses of a range. * Validates the low and high IP addresses of a range.
* *
* Now supports IPv6 addresses.
*
* @param string $range_low Low IP address. * @param string $range_low Low IP address.
* @param string $range_high High IP address. * @param string $range_high High IP address.
* @return bool True if the range is valid, false otherwise. * @return bool True if the range is valid, false otherwise.
*/ */
public static function validate_ip_range( $range_low, $range_high ) { public static function validate_ip_range( $range_low, $range_high ) {
// Validate that both IP addresses are valid. // Validate that both IP addresses are valid.
if ( ! filter_var( $range_low, FILTER_VALIDATE_IP ) || ! filter_var( $range_high, FILTER_VALIDATE_IP ) ) { if ( self::validate_ip_addresses( array( $range_low, $range_high ) ) === false ) {
return false; return false;
} }
// Validate that the $range_low is lower or equal to $range_high. // Ensure both IPs are of the same version
// The inet_pton will give us binary string of an ipv4 or ipv6. $range_low_ip_version = self::get_ip_version( $range_low );
// We can then use strcmp to see if the address is in range. $range_high_ip_version = self::get_ip_version( $range_high );
if ( $range_low_ip_version !== $range_high_ip_version || ! $range_low_ip_version || ! $range_high_ip_version ) {
return false; // Invalid or mixed IP versions.
}
// Convert IP addresses to their packed binary representation.
$ip_low = inet_pton( $range_low ); $ip_low = inet_pton( $range_low );
$ip_high = inet_pton( $range_high ); $ip_high = inet_pton( $range_high );
// Check if the conversion was successful.
if ( false === $ip_low || false === $ip_high ) { if ( false === $ip_low || false === $ip_high ) {
return false; return false;
} }
// Compare the binary representations to ensure the low IP is not greater than the high IP.
if ( strcmp( $ip_low, $ip_high ) > 0 ) { if ( strcmp( $ip_low, $ip_high ) > 0 ) {
return false; return false;
} }
return true; return true;
} }
/**
* Checks that a given IP address is within a given range.
*
* Supports CIDR notation and hyphenated ranges for both IPv4 and IPv6.
*
* @param string $ip IP address.
* @param string $range_low Range low or CIDR notation.
* @param null|string $range_high Optional. Range high. Not used if $range_low is CIDR notation.
* @return bool
*/
public static function ip_address_is_in_range( $ip, $range_low, $range_high = null ) {
// Validate that all provided IP addresses are valid.
if ( $range_high !== null && ! self::validate_ip_addresses( array( $ip, $range_low, $range_high ) ) ) {
return false;
} else {
$range_low_parsed = self::parse_cidr( $range_low );
if ( $range_low_parsed && ! self::validate_ip_addresses( array( $ip, $range_low_parsed[0] ) ) ) {
return false;
}
}
if ( strpos( $range_low, '/' ) !== false ) {
// CIDR notation
if ( $range_high !== null ) {
// Invalid usage: CIDR notation with range high parameter
return false;
}
return self::ip_in_cidr( $ip, $range_low );
}
// Hyphenated range
if ( $range_high === null ) {
return false; // Invalid parameters
}
$ip_num = inet_pton( $ip );
$ip_low = inet_pton( $range_low );
$ip_high = inet_pton( $range_high );
if ( $ip_num && $ip_low && $ip_high && strcmp( $ip_num, $ip_low ) >= 0 && strcmp( $ip_num, $ip_high ) <= 0 ) {
return true;
}
return false;
}
} }

View File

@ -5,6 +5,112 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [4.2.7] - 2025-03-24
### Changed
- Allow JITM functionality to be enabled on Simple sites. [#41252]
## [4.2.6] - 2025-03-21
### Changed
- Internal updates.
## [4.2.5] - 2025-03-18
### Changed
- Update dependencies. [#42545]
## [4.2.4] - 2025-03-17
### Changed
- Internal updates.
## [4.2.3] - 2025-03-17
### Changed
- Internal updates.
## [4.2.2] - 2025-03-12
### Changed
- Internal updates.
## [4.2.1] - 2025-03-05
### Changed
- Internal updates.
## [4.2.0] - 2025-03-03
### Changed
- Replace more JITM jQuery Ajax calls with `@wordpress/api-fetch`. [#41990]
- Update package dependencies. [#42163]
## [4.1.1] - 2025-02-24
### Changed
- Refactor handling of JITM-approved screens. [#41748]
## [4.1.0] - 2025-02-17
### Changed
- Update AJAX calls to utilise @wordpress/api-fetch. [#41745]
## [4.0.7] - 2025-02-12
### Fixed
- Fix the query parameter used for JITM query strings. [#41542]
## [4.0.6] - 2025-02-10
### Changed
- Update package dependencies. [#41491]
## [4.0.5] - 2025-02-03
### Changed
- Update package dependencies. [#41286]
- Update the WooCommerce logo in Woo JITMs. [#41322]
## [4.0.4] - 2025-01-20
### Changed
- Updated package dependencies. [#41099]
## [4.0.3] - 2024-12-16
### Changed
- Updated package dependencies. [#40564]
## [4.0.2] - 2024-12-04
### Changed
- Updated package dependencies. [#40363]
## [4.0.1] - 2024-11-25
### Changed
- Updated package dependencies. [#40258] [#40288]
## [4.0.0] - 2024-11-14
### Removed
- General: Update minimum PHP version to 7.2. [#40147]
## [3.1.29] - 2024-11-11
### Changed
- Updated package dependencies. [#39999]
## [3.1.28] - 2024-11-04
### Added
- Enable test coverage. [#39961]
## [3.1.27] - 2024-10-29
### Changed
- Internal updates.
## [3.1.26] - 2024-10-14
### Changed
- Only include `wp-polyfill` as a script dependency when needed. [#39629]
## [3.1.25] - 2024-10-10
### Changed
- Updated package dependencies. [#39707]
## [3.1.24] - 2024-10-07
### Changed
- Updated package dependencies. [#39594]
## [3.1.23] - 2024-09-23
### Changed
- Update dependencies.
## [3.1.22] - 2024-09-10
### Changed
- Updated package dependencies. [#39302]
## [3.1.21] - 2024-09-05 ## [3.1.21] - 2024-09-05
### Changed ### Changed
- Update dependencies. - Update dependencies.
@ -763,6 +869,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Update Jetpack to use new JITM package - Update Jetpack to use new JITM package
[4.2.7]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.6...v4.2.7
[4.2.6]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.5...v4.2.6
[4.2.5]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.4...v4.2.5
[4.2.4]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.3...v4.2.4
[4.2.3]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.2...v4.2.3
[4.2.2]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.1...v4.2.2
[4.2.1]: https://github.com/Automattic/jetpack-jitm/compare/v4.2.0...v4.2.1
[4.2.0]: https://github.com/Automattic/jetpack-jitm/compare/v4.1.1...v4.2.0
[4.1.1]: https://github.com/Automattic/jetpack-jitm/compare/v4.1.0...v4.1.1
[4.1.0]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.7...v4.1.0
[4.0.7]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.6...v4.0.7
[4.0.6]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.5...v4.0.6
[4.0.5]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.4...v4.0.5
[4.0.4]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.3...v4.0.4
[4.0.3]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.2...v4.0.3
[4.0.2]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.1...v4.0.2
[4.0.1]: https://github.com/Automattic/jetpack-jitm/compare/v4.0.0...v4.0.1
[4.0.0]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.29...v4.0.0
[3.1.29]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.28...v3.1.29
[3.1.28]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.27...v3.1.28
[3.1.27]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.26...v3.1.27
[3.1.26]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.25...v3.1.26
[3.1.25]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.24...v3.1.25
[3.1.24]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.23...v3.1.24
[3.1.23]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.22...v3.1.23
[3.1.22]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.21...v3.1.22
[3.1.21]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.20...v3.1.21 [3.1.21]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.20...v3.1.21
[3.1.20]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.19...v3.1.20 [3.1.20]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.19...v3.1.20
[3.1.19]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.18...v3.1.19 [3.1.19]: https://github.com/Automattic/jetpack-jitm/compare/v3.1.18...v3.1.19

View File

@ -1 +1 @@
<?php return array('dependencies' => array('jquery', 'wp-polyfill'), 'version' => 'a41583033504a4ed0b13'); <?php return array('dependencies' => array('jquery', 'wp-api-fetch', 'wp-polyfill', 'wp-url'), 'version' => '0997a33b24034e958e27');

File diff suppressed because one or more lines are too long

View File

@ -4,19 +4,20 @@
"type": "jetpack-library", "type": "jetpack-library",
"license": "GPL-2.0-or-later", "license": "GPL-2.0-or-later",
"require": { "require": {
"php": ">=7.0", "php": ">=7.2",
"automattic/jetpack-a8c-mc-stats": "^2.0.2", "automattic/jetpack-a8c-mc-stats": "^3.0.4",
"automattic/jetpack-assets": "^2.3.7", "automattic/jetpack-assets": "^4.0.14",
"automattic/jetpack-connection": "^4.0.0", "automattic/jetpack-connection": "^6.8.0",
"automattic/jetpack-device-detection": "^2.1.4", "automattic/jetpack-device-detection": "^3.0.5",
"automattic/jetpack-logo": "^2.0.4", "automattic/jetpack-logo": "^3.0.4",
"automattic/jetpack-redirect": "^2.0.4", "automattic/jetpack-redirect": "^3.0.5",
"automattic/jetpack-status": "^4.0.0" "automattic/jetpack-status": "^5.0.10"
}, },
"require-dev": { "require-dev": {
"brain/monkey": "2.6.1", "brain/monkey": "^2.6.2",
"yoast/phpunit-polyfills": "^1.1.1", "yoast/phpunit-polyfills": "^3.0.0",
"automattic/jetpack-changelogger": "^4.2.6" "automattic/jetpack-changelogger": "^6.0.2",
"automattic/phpunit-select-config": "^1.0.1"
}, },
"suggest": { "suggest": {
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package." "automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
@ -34,7 +35,10 @@
"pnpm run build" "pnpm run build"
], ],
"phpunit": [ "phpunit": [
"./vendor/phpunit/phpunit/phpunit --colors=always" "phpunit-select-config phpunit.#.xml.dist --colors=always"
],
"test-coverage": [
"php -dpcov.directory=. ./vendor/bin/phpunit-select-config phpunit.#.xml.dist --coverage-php \"$COVERAGE_DIR/php.cov\""
], ],
"test-php": [ "test-php": [
"@composer phpunit" "@composer phpunit"
@ -57,7 +61,7 @@
"link-template": "https://github.com/Automattic/jetpack-jitm/compare/v${old}...v${new}" "link-template": "https://github.com/Automattic/jetpack-jitm/compare/v${old}...v${new}"
}, },
"branch-alias": { "branch-alias": {
"dev-trunk": "3.1.x-dev" "dev-trunk": "4.2.x-dev"
} }
} }
} }

View File

@ -11,6 +11,7 @@ use Automattic\Jetpack\Assets;
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo; use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Status; use Automattic\Jetpack\Status;
use Automattic\Jetpack\Status\Host;
/** /**
* Jetpack just in time messaging through out the admin * Jetpack just in time messaging through out the admin
@ -20,7 +21,19 @@ use Automattic\Jetpack\Status;
*/ */
class JITM { class JITM {
const PACKAGE_VERSION = '3.1.21'; const PACKAGE_VERSION = '4.2.7';
/**
* List of screen IDs where JITMs are allowed to display.
*
* @var string[]
*/
const APPROVED_SCREEN_IDS = array(
'jetpack',
'woo',
'shop',
'product',
);
/** /**
* The configuration method that is called from the jetpack-config package. * The configuration method that is called from the jetpack-config package.
@ -36,7 +49,7 @@ class JITM {
* @return Post_Connection_JITM|Pre_Connection_JITM JITM instance. * @return Post_Connection_JITM|Pre_Connection_JITM JITM instance.
*/ */
public static function get_instance() { public static function get_instance() {
if ( ( new Connection_Manager() )->is_connected() ) { if ( self::is_connected() ) {
$jitm = new Post_Connection_JITM(); $jitm = new Post_Connection_JITM();
} else { } else {
$jitm = new Pre_Connection_JITM(); $jitm = new Pre_Connection_JITM();
@ -156,7 +169,10 @@ class JITM {
return ( return (
$current_screen $current_screen
&& $current_screen->id && $current_screen->id
&& (bool) preg_match( '/jetpack|woo|shop|product/', $current_screen->id ) && (bool) preg_match(
'/' . implode( '|', self::APPROVED_SCREEN_IDS ) . '/',
$current_screen->id
)
); );
} }
@ -226,7 +242,7 @@ class JITM {
return; return;
} }
// Only add this to Jetpack or Woo admin pages. // Only add this to specifically allowed pages.
if ( ! $this->is_a8c_admin_page() ) { if ( ! $this->is_a8c_admin_page() ) {
return; return;
} }
@ -255,13 +271,48 @@ class JITM {
* @param bool $full_jp_logo_exists Is there a big JP logo already displayed on this screen. * @param bool $full_jp_logo_exists Is there a big JP logo already displayed on this screen.
*/ */
public function generate_icon( $content_icon, $full_jp_logo_exists ) { public function generate_icon( $content_icon, $full_jp_logo_exists ) {
$date_now = new \DateTime( 'now', wp_timezone() );
$feb_4_date = new \DateTime( '02-04-2025', wp_timezone() );
// Don't show the new Woo svg logo until after Feb 4th, 2025
$show_new_logo = $date_now >= $feb_4_date;
switch ( $content_icon ) { switch ( $content_icon ) {
case 'jetpack': case 'jetpack':
$jetpack_logo = new Jetpack_Logo(); $jetpack_logo = new Jetpack_Logo();
$content_icon = '<div class="jp-emblem">' . ( ( $full_jp_logo_exists ) ? $jetpack_logo->get_jp_emblem() : $jetpack_logo->get_jp_emblem_larger() ) . '</div>'; $content_icon = '<div class="jp-emblem">' . ( ( $full_jp_logo_exists ) ? $jetpack_logo->get_jp_emblem() : $jetpack_logo->get_jp_emblem_larger() ) . '</div>';
break; break;
case 'woocommerce': case 'woocommerce':
$content_icon = '<div class="jp-emblem"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 168 100" xml:space="preserve" enable-background="new 0 0 168 100" width="50" height="30"><style type="text/css"> // After Feb 4th 2025, we can remove this date condition check ( & filter) and the old svg logo.
/**
* Filter to force display the new Woo logo in Woo JITM's, or not.
*
* @since 4.0.5
*
* @param bool $show_woo_logo Whether to show the new Woo logo or not.
*/
$content_icon = apply_filters( 'jetpack_jitm_use_new_woo_logo', $show_new_logo )
// New Woo logo
? '<div class="jp-emblem"><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 183.6 47.5" style="enable-background:new 0 0 183.6 47.5;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#873EFF;}
.st1{fill-rule:evenodd;clip-rule:evenodd;}
.st2{fill:#873EFF;}
.st3{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st4{fill:#FFFFFF;}
</style>
<g>
<path class="st0" d="M77.4,0c-4.3,0-7.1,1.4-9.6,6.1L56.4,27.6V8.5c0-5.7-2.7-8.5-7.7-8.5s-7.1,1.7-9.6,6.5L28.3,27.6V8.7
c0-6.1-2.5-8.7-8.6-8.7H7.3C2.6,0,0,2.2,0,6.2s2.5,6.4,7.1,6.4h5.1v24.1c0,6.8,4.6,10.8,11.2,10.8s9.6-2.6,12.9-8.7l7.2-13.5v11.4
c0,6.7,4.4,10.8,11.1,10.8s9.2-2.3,13-8.7l16.6-28C87.8,4.7,85.3,0,77.3,0C77.3,0,77.3,0,77.4,0z"/>
<path class="st0" d="M108.6,0C95,0,84.7,10.1,84.7,23.8s10.4,23.7,23.9,23.7s23.8-10.1,23.9-23.7C132.5,10.1,122.1,0,108.6,0z
M108.6,32.9c-5.1,0-8.6-3.8-8.6-9.1s3.5-9.2,8.6-9.2s8.6,3.9,8.6,9.2S113.8,32.9,108.6,32.9z"/>
<path class="st0" d="M159.7,0c-13.5,0-23.9,10.1-23.9,23.8s10.4,23.7,23.9,23.7s23.9-10.1,23.9-23.7S173.2,0,159.7,0z M159.7,32.9
c-5.2,0-8.5-3.8-8.5-9.1s3.4-9.2,8.5-9.2s8.6,3.9,8.6,9.2S164.9,32.9,159.7,32.9z"/>
</g>
</svg></div>'
// Old Woo logo
: '<div class="jp-emblem"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 168 100" xml:space="preserve" enable-background="new 0 0 168 100" width="50" height="30"><style type="text/css">
.st0{clip-path:url(#SVGID_2_);enable-background:new ;} .st0{clip-path:url(#SVGID_2_);enable-background:new ;}
.st1{clip-path:url(#SVGID_4_);} .st1{clip-path:url(#SVGID_4_);}
.st2{clip-path:url(#SVGID_6_);} .st2{clip-path:url(#SVGID_6_);}
@ -344,4 +395,19 @@ class JITM {
return $params; return $params;
} }
/**
* Check if the current site is connected.
* On WordPress.com Simple, it is always connected.
*
* @return bool true if the site is connected, false otherwise.
*/
private static function is_connected() {
if ( ( new Host() )->is_wpcom_simple() ) {
return true;
}
$connection = new Connection_Manager();
return $connection->is_connected();
}
} }

View File

@ -225,7 +225,11 @@ class Post_Connection_JITM extends JITM {
} }
/** /**
* Asks the wpcom API for the current message to display keyed on query string and message path * Asks the wpcom API for the current message to display keyed on query string and message path.
*
* For sites running on the Dotcom Simple codebase, the network request is bypassed
* via Client::wpcom_json_api_request_as_blog allowing for the JITM\Engine to be called
* directly.
* *
* @param string $message_path The message path to ask for. * @param string $message_path The message path to ask for.
* @param string $query The query string originally from the front end. * @param string $query The query string originally from the front end.

View File

@ -130,6 +130,8 @@ class Pre_Connection_JITM extends JITM {
* @return array The JITMs to show, or an empty array if there is nothing to show * @return array The JITMs to show, or an empty array if there is nothing to show
*/ */
public function get_messages( $message_path, $query, $full_jp_logo_exists ) { public function get_messages( $message_path, $query, $full_jp_logo_exists ) {
// Ensure only admins see pre-connection JITMs since only they can connect to WordPress.com
// and enable modules.
if ( ! current_user_can( 'install_plugins' ) ) { if ( ! current_user_can( 'install_plugins' ) ) {
return array(); return array();
} }

Some files were not shown because too many files have changed in this diff Show More