updated plugin Jetpack Protect
version 1.1.1
This commit is contained in:
parent
9bf96ad952
commit
5284e32c67
@ -5,6 +5,20 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 1.1.1 - 2022-11-18
|
||||
### Fixed
|
||||
- Fix issue with plugin activation.
|
||||
|
||||
## 1.1.0 - 2022-11-17
|
||||
### Added
|
||||
- Add features for paid Jetpack Scan users, including file and database threats, on-demand scanning, and threat auto-fixers.
|
||||
|
||||
### Changed
|
||||
- Compatibility: WordPress 6.1 compatibility
|
||||
|
||||
### Fixed
|
||||
- Adjust alignment of spinner icon and loading text on the in-progress scan screen.
|
||||
|
||||
## 1.0.4 - 2022-08-29
|
||||
### Fixed
|
||||
- Fixed NaN error that prevented the pricing interstitial from rendering.
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'c28c9ff5fed1d1b9867f');
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '79aba5c67c65c2093d2d');
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -5,20 +5,22 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"automattic/jetpack-assets": "^1.17",
|
||||
"automattic/jetpack-admin-ui": "^0.2.11",
|
||||
"automattic/jetpack-autoloader": "^2.11",
|
||||
"automattic/jetpack-composer-plugin": "^1.1",
|
||||
"automattic/jetpack-config": "^1.9",
|
||||
"automattic/jetpack-identity-crisis": "^0.8.22",
|
||||
"automattic/jetpack-my-jetpack": "^2.0",
|
||||
"automattic/jetpack-assets": "^1.17.25",
|
||||
"automattic/jetpack-admin-ui": "^0.2.12",
|
||||
"automattic/jetpack-autoloader": "^2.11.11",
|
||||
"automattic/jetpack-composer-plugin": "^1.1.5",
|
||||
"automattic/jetpack-config": "^1.11.0",
|
||||
"automattic/jetpack-identity-crisis": "^0.8.31",
|
||||
"automattic/jetpack-my-jetpack": "^2.4.0",
|
||||
"automattic/jetpack-plugins-installer": "^0.2.0",
|
||||
"automattic/jetpack-sync": "^1.38"
|
||||
"automattic/jetpack-sync": "^1.43.0",
|
||||
"automattic/jetpack-transport-helper": "^0.1.0",
|
||||
"automattic/jetpack-plans": "^0.2.6"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "1.0.3",
|
||||
"automattic/jetpack-changelogger": "^3.2",
|
||||
"automattic/wordbless": "0.3.1"
|
||||
"automattic/jetpack-changelogger": "^3.2.1",
|
||||
"automattic/wordbless": "0.4.0"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@ -45,15 +47,21 @@
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"pnpm run watch"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
|
||||
},
|
||||
"repositories": [],
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"extra": {
|
||||
"mirror-repo": "Automattic/jetpack-protect-plugin",
|
||||
"autorelease": true,
|
||||
"autotagger": {
|
||||
"v": false
|
||||
},
|
||||
"release-branch-prefix": "protect",
|
||||
"wp-plugin-slug": "jetpack-protect",
|
||||
"wp-svn-autopublish": true,
|
||||
"version-constants": {
|
||||
"JETPACK_PROTECT_VERSION": "jetpack-protect.php"
|
||||
}
|
||||
@ -64,6 +72,6 @@
|
||||
"automattic/jetpack-autoloader": true,
|
||||
"automattic/jetpack-composer-plugin": true
|
||||
},
|
||||
"autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_0_4"
|
||||
"autoloader-suffix": "c4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_1_1"
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
* Plugin Name: Jetpack Protect
|
||||
* Plugin URI: https://wordpress.org/plugins/jetpack-protect
|
||||
* Description: Security tools that keep your site safe and sound, from posts to plugins.
|
||||
* Version: 1.0.4
|
||||
* Version: 1.1.1
|
||||
* Author: Automattic
|
||||
* Author URI: https://jetpack.com/
|
||||
* License: GPLv2 or later
|
||||
@ -33,7 +33,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define( 'JETPACK_PROTECT_VERSION', '1.0.4' );
|
||||
define( 'JETPACK_PROTECT_VERSION', '1.1.1' );
|
||||
define( 'JETPACK_PROTECT_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'JETPACK_PROTECT_ROOT_FILE', __FILE__ );
|
||||
define( 'JETPACK_PROTECT_ROOT_FILE_RELATIVE_PATH', plugin_basename( __FILE__ ) );
|
||||
|
@ -5,6 +5,10 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.12] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.2.11] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -72,6 +76,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Fixing menu visibility issues.
|
||||
|
||||
[0.2.12]: https://github.com/Automattic/jetpack-admin-ui/compare/0.2.11...0.2.12
|
||||
[0.2.11]: https://github.com/Automattic/jetpack-admin-ui/compare/0.2.10...0.2.11
|
||||
[0.2.10]: https://github.com/Automattic/jetpack-admin-ui/compare/0.2.9...0.2.10
|
||||
[0.2.9]: https://github.com/Automattic/jetpack-admin-ui/compare/0.2.8...0.2.9
|
||||
|
@ -24,7 +24,8 @@
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
|
@ -13,7 +13,7 @@ namespace Automattic\Jetpack\Admin_UI;
|
||||
*/
|
||||
class Admin_Menu {
|
||||
|
||||
const PACKAGE_VERSION = '0.2.11';
|
||||
const PACKAGE_VERSION = '0.2.12';
|
||||
|
||||
/**
|
||||
* Whether this class has been initialized
|
||||
|
@ -5,6 +5,22 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.17.25] - 2022-11-08
|
||||
### Changed
|
||||
- Updated package dependencies. [#27289]
|
||||
|
||||
## [1.17.24] - 2022-11-01
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.17.23] - 2022-10-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#26791]
|
||||
|
||||
## [1.17.22] - 2022-10-05
|
||||
### Changed
|
||||
- Updated package dependencies. [#26568]
|
||||
|
||||
## [1.17.21] - 2022-08-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#25814]
|
||||
@ -260,6 +276,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Statically access asset tools
|
||||
|
||||
[1.17.25]: https://github.com/Automattic/jetpack-assets/compare/v1.17.24...v1.17.25
|
||||
[1.17.24]: https://github.com/Automattic/jetpack-assets/compare/v1.17.23...v1.17.24
|
||||
[1.17.23]: https://github.com/Automattic/jetpack-assets/compare/v1.17.22...v1.17.23
|
||||
[1.17.22]: https://github.com/Automattic/jetpack-assets/compare/v1.17.21...v1.17.22
|
||||
[1.17.21]: https://github.com/Automattic/jetpack-assets/compare/v1.17.20...v1.17.21
|
||||
[1.17.20]: https://github.com/Automattic/jetpack-assets/compare/v1.17.19...v1.17.20
|
||||
[1.17.19]: https://github.com/Automattic/jetpack-assets/compare/v1.17.18...v1.17.19
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('wp-i18n'), 'version' => 'ee939953aa2115e2ca59');
|
||||
<?php return array('dependencies' => array('wp-i18n'), 'version' => 'e69db286c9c94bd98790');
|
||||
|
File diff suppressed because one or more lines are too long
@ -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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.11.0] - 2022-10-11
|
||||
### Changed
|
||||
- Integrate Stats package in Jetpack plugin [#26640]
|
||||
|
||||
## [1.10.0] - 2022-09-27
|
||||
### Added
|
||||
- Social: Added the option to configure if the plan information should be refreshed as the package is enabled. [#26294]
|
||||
|
||||
## [1.9.6] - 2022-08-26
|
||||
### Changed
|
||||
- Call ensure_options_$feature methods before the initialization
|
||||
@ -144,6 +152,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Trying to add deterministic initialization.
|
||||
|
||||
[1.11.0]: https://github.com/Automattic/jetpack-config/compare/v1.10.0...v1.11.0
|
||||
[1.10.0]: https://github.com/Automattic/jetpack-config/compare/v1.9.6...v1.10.0
|
||||
[1.9.6]: https://github.com/Automattic/jetpack-config/compare/v1.9.5...v1.9.6
|
||||
[1.9.5]: https://github.com/Automattic/jetpack-config/compare/v1.9.4...v1.9.5
|
||||
[1.9.4]: https://github.com/Automattic/jetpack-config/compare/v1.9.3...v1.9.4
|
||||
|
@ -22,7 +22,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-config/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "1.9.x-dev"
|
||||
"dev-trunk": "1.11.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ use Automattic\Jetpack\JITMS\JITM as JITMS_JITM;
|
||||
use Automattic\Jetpack\Post_List\Post_List as Post_List;
|
||||
use Automattic\Jetpack\Publicize\Publicize_Setup as Publicize_Setup;
|
||||
use Automattic\Jetpack\Search\Initializer as Jetpack_Search_Main;
|
||||
use Automattic\Jetpack\Stats\Main as Stats_Main;
|
||||
use Automattic\Jetpack\Sync\Main as Sync_Main;
|
||||
use Automattic\Jetpack\VideoPress\Initializer as VideoPress_Pkg_Initializer;
|
||||
use Automattic\Jetpack\Waf\Waf_Initializer as Jetpack_Waf_Main;
|
||||
@ -49,6 +50,7 @@ class Config {
|
||||
'wordads' => false,
|
||||
'waf' => false,
|
||||
'videopress' => false,
|
||||
'stats' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
@ -146,6 +148,9 @@ class Config {
|
||||
if ( $this->config['videopress'] ) {
|
||||
$this->ensure_class( 'Automattic\Jetpack\VideoPress\Initializer' ) && $this->ensure_feature( 'videopress' );
|
||||
}
|
||||
if ( $this->config['stats'] ) {
|
||||
$this->ensure_class( 'Automattic\Jetpack\Stats\Main' ) && $this->ensure_feature( 'stats' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -269,6 +274,17 @@ class Config {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Publicize options.
|
||||
*/
|
||||
protected function ensure_options_publicize() {
|
||||
$options = $this->get_feature_options( 'publicize' );
|
||||
|
||||
if ( ! empty( $options['force_refresh'] ) ) {
|
||||
Publicize_Setup::$refresh_plan_info = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables WordAds.
|
||||
*/
|
||||
@ -293,6 +309,14 @@ class Config {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables Stats.
|
||||
*/
|
||||
protected function enable_stats() {
|
||||
Stats_Main::init();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles VideoPress options
|
||||
*/
|
||||
|
@ -5,6 +5,49 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.46.3] - 2022-11-08
|
||||
### Changed
|
||||
- Updated package dependencies. [#27289]
|
||||
|
||||
## [1.46.2] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [1.46.1] - 2022-11-01
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.46.0] - 2022-10-25
|
||||
### Changed
|
||||
- Use blog token to unlink users from WPCOM. [#26705]
|
||||
|
||||
## [1.45.5] - 2022-10-25
|
||||
### Added
|
||||
- Connection: expose BlogId in the global state [#26978]
|
||||
|
||||
## [1.45.4] - 2022-10-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#26791]
|
||||
|
||||
## [1.45.3] - 2022-10-05
|
||||
### Changed
|
||||
- Updated package dependencies. [#26568]
|
||||
|
||||
### Fixed
|
||||
- Clean connection errors after successful blog token restore. [#26489]
|
||||
|
||||
## [1.45.2] - 2022-09-21
|
||||
### Fixed
|
||||
- Check request body error type before creating wp error. [#26304]
|
||||
|
||||
## [1.45.1] - 2022-09-20
|
||||
### Fixed
|
||||
- Rename the initial state key to ensure compatibility with the JS package. [#26259]
|
||||
|
||||
## [1.45.0] - 2022-09-08
|
||||
### Changed
|
||||
- Add option to JP options [#25979]
|
||||
|
||||
## [1.44.0] - 2022-08-29
|
||||
### Added
|
||||
- Connection: verify REST API errors.
|
||||
@ -678,6 +721,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Separate the connection library into its own package.
|
||||
|
||||
[1.46.3]: https://github.com/Automattic/jetpack-connection/compare/v1.46.2...v1.46.3
|
||||
[1.46.2]: https://github.com/Automattic/jetpack-connection/compare/v1.46.1...v1.46.2
|
||||
[1.46.1]: https://github.com/Automattic/jetpack-connection/compare/v1.46.0...v1.46.1
|
||||
[1.46.0]: https://github.com/Automattic/jetpack-connection/compare/v1.45.5...v1.46.0
|
||||
[1.45.5]: https://github.com/Automattic/jetpack-connection/compare/v1.45.4...v1.45.5
|
||||
[1.45.4]: https://github.com/Automattic/jetpack-connection/compare/v1.45.3...v1.45.4
|
||||
[1.45.3]: https://github.com/Automattic/jetpack-connection/compare/v1.45.2...v1.45.3
|
||||
[1.45.2]: https://github.com/Automattic/jetpack-connection/compare/v1.45.1...v1.45.2
|
||||
[1.45.1]: https://github.com/Automattic/jetpack-connection/compare/v1.45.0...v1.45.1
|
||||
[1.45.0]: https://github.com/Automattic/jetpack-connection/compare/v1.44.0...v1.45.0
|
||||
[1.44.0]: https://github.com/Automattic/jetpack-connection/compare/v1.43.1...v1.44.0
|
||||
[1.43.1]: https://github.com/Automattic/jetpack-connection/compare/v1.43.0...v1.43.1
|
||||
[1.43.0]: https://github.com/Automattic/jetpack-connection/compare/v1.42.0...v1.43.0
|
||||
|
@ -8,7 +8,7 @@
|
||||
"automattic/jetpack-admin-ui": "^0.2",
|
||||
"automattic/jetpack-constants": "^1.6",
|
||||
"automattic/jetpack-roles": "^1.4",
|
||||
"automattic/jetpack-status": "^1.14",
|
||||
"automattic/jetpack-status": "^1.15",
|
||||
"automattic/jetpack-redirect": "^1.7"
|
||||
},
|
||||
"require-dev": {
|
||||
@ -34,7 +34,8 @@
|
||||
"phpunit": [
|
||||
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\"",
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"test-coverage": [
|
||||
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-clover \"$COVERAGE_DIR/clover.xml\""
|
||||
],
|
||||
@ -55,7 +56,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-connection/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "1.44.x-dev"
|
||||
"dev-trunk": "1.46.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'd9dbf909a3d10fb26f39');
|
||||
<?php return array('dependencies' => array(), 'version' => 'a96178e4d62fb695caa0');
|
||||
|
@ -1 +1 @@
|
||||
(()=>{var e={775:e=>{let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(775);window.analytics=t})();
|
||||
!function(){var e={775:function(e){let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(775);window.analytics=t}();
|
@ -127,8 +127,7 @@ class Jetpack_Options {
|
||||
'partner_coupon', // (string) A Jetpack partner issued coupon to promote a sale together with Jetpack.
|
||||
'partner_coupon_added', // (string) A date for when `partner_coupon` was added, so we can auto-purge after a certain time interval.
|
||||
'dismissed_backup_review_restore', // (bool) Determines if the component review request is dismissed for successful restore requests.
|
||||
'dismissed_backup_review_time_based', // (bool) Determines if the component review request is dismissed for subscription time based requests.
|
||||
|
||||
'dismissed_backup_review_backups', // (bool) Determines if the component review request is dismissed for successful backup requests.
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -710,7 +710,7 @@ class Error_Handler {
|
||||
}
|
||||
|
||||
$body = json_decode( $body_raw, true );
|
||||
if ( empty( $body['error'] ) ) {
|
||||
if ( empty( $body['error'] ) || ( ! is_string( $body['error'] ) && ! is_int( $body['error'] ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -30,15 +30,15 @@ class Initial_State {
|
||||
global $wp_version;
|
||||
|
||||
return array(
|
||||
'apiRoot' => esc_url_raw( rest_url() ),
|
||||
'apiNonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
|
||||
'connectionStatus' => REST_Connector::connection_status( false ),
|
||||
'userConnectionData' => REST_Connector::get_user_connection_data( false ),
|
||||
'connectedPlugins' => REST_Connector::get_connection_plugins( false ),
|
||||
'wpVersion' => $wp_version,
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'connectionVerifiedErrors' => Error_Handler::get_instance()->get_verified_errors(),
|
||||
'apiRoot' => esc_url_raw( rest_url() ),
|
||||
'apiNonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
|
||||
'connectionStatus' => REST_Connector::connection_status( false ),
|
||||
'userConnectionData' => REST_Connector::get_user_connection_data( false ),
|
||||
'connectedPlugins' => REST_Connector::get_connection_plugins( false ),
|
||||
'wpVersion' => $wp_version,
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'connectionErrors' => Error_Handler::get_instance()->get_verified_errors(),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ use Automattic\Jetpack\Status;
|
||||
use Automattic\Jetpack\Terms_Of_Service;
|
||||
use Automattic\Jetpack\Tracking;
|
||||
use Jetpack_IXR_Client;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
use WP_User;
|
||||
|
||||
@ -831,7 +832,12 @@ class Manager {
|
||||
* @return Boolean Whether the disconnection of the user was successful.
|
||||
*/
|
||||
public function disconnect_user( $user_id = null, $can_overwrite_primary_user = false, $force_disconnect_locally = false ) {
|
||||
$user_id = empty( $user_id ) ? get_current_user_id() : (int) $user_id;
|
||||
$user_id = empty( $user_id ) ? get_current_user_id() : (int) $user_id;
|
||||
$is_primary_user = Jetpack_Options::get_option( 'master_user' ) === $user_id;
|
||||
|
||||
if ( $is_primary_user && ! $can_overwrite_primary_user ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to disconnect the user from WordPress.com.
|
||||
$is_disconnected_from_wpcom = $this->unlink_user_from_wpcom( $user_id );
|
||||
@ -839,7 +845,7 @@ class Manager {
|
||||
$is_disconnected_locally = false;
|
||||
if ( $is_disconnected_from_wpcom || $force_disconnect_locally ) {
|
||||
// Disconnect the user locally.
|
||||
$is_disconnected_locally = $this->get_tokens()->disconnect_user( $user_id, $can_overwrite_primary_user );
|
||||
$is_disconnected_locally = $this->get_tokens()->disconnect_user( $user_id );
|
||||
|
||||
if ( $is_disconnected_locally ) {
|
||||
// Delete cached connected user data.
|
||||
@ -855,6 +861,10 @@ class Manager {
|
||||
* @param int $user_id The current user's ID.
|
||||
*/
|
||||
do_action( 'jetpack_unlinked_user', $user_id );
|
||||
|
||||
if ( $is_primary_user ) {
|
||||
Jetpack_Options::delete_option( 'master_user' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -864,15 +874,13 @@ class Manager {
|
||||
/**
|
||||
* Request to wpcom for a user to be unlinked from their WordPress.com account
|
||||
*
|
||||
* @access public
|
||||
* @param int $user_id The user identifier.
|
||||
*
|
||||
* @param Integer $user_id the user identifier.
|
||||
*
|
||||
* @return Boolean Whether the disconnection of the user was successful.
|
||||
* @return bool Whether the disconnection of the user was successful.
|
||||
*/
|
||||
public function unlink_user_from_wpcom( $user_id ) {
|
||||
// Attempt to disconnect the user from WordPress.com.
|
||||
$xml = new Jetpack_IXR_Client( compact( 'user_id' ) );
|
||||
$xml = new Jetpack_IXR_Client();
|
||||
|
||||
$xml->query( 'jetpack.unlink_user', $user_id );
|
||||
if ( $xml->isError() ) {
|
||||
@ -2416,6 +2424,8 @@ class Manager {
|
||||
return new WP_Error( 'jetpack_secret', '', $code );
|
||||
}
|
||||
|
||||
Error_Handler::get_instance()->delete_all_errors();
|
||||
|
||||
return $this->get_tokens()->update_blog_token( (string) $json->jetpack_secret );
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Connection;
|
||||
*/
|
||||
class Package_Version {
|
||||
|
||||
const PACKAGE_VERSION = '1.44.0';
|
||||
const PACKAGE_VERSION = '1.46.3';
|
||||
|
||||
const PACKAGE_SLUG = 'connection';
|
||||
|
||||
|
@ -432,6 +432,8 @@ class REST_Connector {
|
||||
* @return \WP_REST_Response|array
|
||||
*/
|
||||
public static function get_user_connection_data( $rest_response = true ) {
|
||||
$blog_id = \Jetpack_Options::get_option( 'id' );
|
||||
|
||||
$connection = new Manager();
|
||||
|
||||
$current_user = wp_get_current_user();
|
||||
@ -464,6 +466,7 @@ class REST_Connector {
|
||||
'isMaster' => $is_master_user,
|
||||
'username' => $current_user->user_login,
|
||||
'id' => $current_user->ID,
|
||||
'blogId' => $blog_id,
|
||||
'wpcomUser' => $wpcom_user_data,
|
||||
'gravatar' => get_avatar_url( $current_user->ID, 64, 'mm', '', array( 'force_display' => true ) ),
|
||||
'permissions' => array(
|
||||
|
@ -487,18 +487,19 @@ class Tokens {
|
||||
*
|
||||
* @todo Refactor to properly load the XMLRPC client independently.
|
||||
*
|
||||
* @param Integer $user_id the user identifier.
|
||||
* @param bool $can_overwrite_primary_user Allow for the primary user to be disconnected.
|
||||
* @return Boolean Whether the disconnection of the user was successful.
|
||||
* @param int $user_id The user identifier.
|
||||
* @param bool|null $deprecated Deprecated.
|
||||
*
|
||||
* @return bool Whether the disconnection of the user was successful.
|
||||
*/
|
||||
public function disconnect_user( $user_id, $can_overwrite_primary_user = false ) {
|
||||
public function disconnect_user( $user_id, $deprecated = null ) {
|
||||
$tokens = $this->get_user_tokens();
|
||||
if ( ! $tokens ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( Jetpack_Options::get_option( 'master_user' ) === $user_id && ! $can_overwrite_primary_user ) {
|
||||
return false;
|
||||
if ( null !== $deprecated ) {
|
||||
_deprecated_argument( __METHOD__, '1.46.0', 'Parameter $can_overwrite_primary_user is deprecated' );
|
||||
}
|
||||
|
||||
if ( ! isset( $tokens[ $user_id ] ) ) {
|
||||
|
@ -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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.4.20] - 2022-11-07
|
||||
### Fixed
|
||||
- Ensure that User_Agent is loaded in environments without autoload enabled. (e.g.: WordPress.com and Super Cache) [#27223]
|
||||
|
||||
## [1.4.19] - 2022-10-25
|
||||
### Changed
|
||||
- Update `wp_unslash` wrapper to possibly run on wpcom before WordPress is loaded. [#26971]
|
||||
|
||||
## [1.4.18] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -124,6 +132,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Moving jetpack_is_mobile into a package
|
||||
|
||||
[1.4.20]: https://github.com/Automattic/jetpack-device-detection/compare/v1.4.19...v1.4.20
|
||||
[1.4.19]: https://github.com/Automattic/jetpack-device-detection/compare/v1.4.18...v1.4.19
|
||||
[1.4.18]: https://github.com/Automattic/jetpack-device-detection/compare/v1.4.17...v1.4.18
|
||||
[1.4.17]: https://github.com/Automattic/jetpack-device-detection/compare/v1.4.16...v1.4.17
|
||||
[1.4.16]: https://github.com/Automattic/jetpack-device-detection/compare/v1.4.15...v1.4.16
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace Automattic\Jetpack;
|
||||
|
||||
require_once __DIR__ . '/functions.php';
|
||||
require_once __DIR__ . '/class-user-agent-info.php';
|
||||
|
||||
use Automattic\Jetpack\Device_Detection\User_Agent_Info;
|
||||
use function Automattic\Jetpack\Device_Detection\wp_unslash;
|
||||
|
@ -13,14 +13,18 @@ namespace Automattic\Jetpack\Device_Detection;
|
||||
* Even though PHP itself dropped the option to add slashes to superglobals a decade ago,
|
||||
* WordPress still does it through some misguided extreme backwards compatibility. 🙄
|
||||
*
|
||||
* If WordPress's function exists, assume it needs to be called. If not, assume it doesn't.
|
||||
* If WordPress's function exists, assume it needs to be called.
|
||||
* Else if on WordPress.com, do a simplified version because we're running really early.
|
||||
* Else, assume it's not needed.
|
||||
*
|
||||
* @param string|array $value String or array of data to unslash.
|
||||
* @return string|array Possibly unslashed $value.
|
||||
* @param string $value String of data to unslash.
|
||||
* @return string Possibly unslashed $value.
|
||||
*/
|
||||
function wp_unslash( $value ) {
|
||||
if ( function_exists( '\\wp_unslash' ) ) {
|
||||
return \wp_unslash( $value );
|
||||
} elseif ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
return stripslashes( $value );
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
|
@ -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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.8.31] - 2022-11-10
|
||||
### Changed
|
||||
- Updated package dependencies. [#27319]
|
||||
|
||||
## [0.8.30] - 2022-11-08
|
||||
### Changed
|
||||
- Updated package dependencies. [#27289]
|
||||
|
||||
## [0.8.29] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [0.8.28] - 2022-11-01
|
||||
### Changed
|
||||
- Updated package dependencies. [#27196]
|
||||
|
||||
## [0.8.27] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [0.8.26] - 2022-10-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#26791]
|
||||
|
||||
## [0.8.25] - 2022-10-05
|
||||
### Changed
|
||||
- Updated package dependencies. [#26568]
|
||||
|
||||
## [0.8.24] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.8.23] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.8.22] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -264,6 +300,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- Updated package dependencies.
|
||||
- Use Connection/Urls for home_url and site_url functions migrated from Sync.
|
||||
|
||||
[0.8.31]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.30...v0.8.31
|
||||
[0.8.30]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.29...v0.8.30
|
||||
[0.8.29]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.28...v0.8.29
|
||||
[0.8.28]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.27...v0.8.28
|
||||
[0.8.27]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.26...v0.8.27
|
||||
[0.8.26]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.25...v0.8.26
|
||||
[0.8.25]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.24...v0.8.25
|
||||
[0.8.24]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.23...v0.8.24
|
||||
[0.8.23]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.22...v0.8.23
|
||||
[0.8.22]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.21...v0.8.22
|
||||
[0.8.21]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.20...v0.8.21
|
||||
[0.8.20]: https://github.com/Automattic/jetpack-identity-crisis/compare/v0.8.19...v0.8.20
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => 'ec6be881467d41653072');
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '1621ca28578f7d06fec7');
|
||||
|
File diff suppressed because one or more lines are too long
@ -4,9 +4,9 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-connection": "^1.44",
|
||||
"automattic/jetpack-connection": "^1.46",
|
||||
"automattic/jetpack-constants": "^1.6",
|
||||
"automattic/jetpack-status": "^1.14",
|
||||
"automattic/jetpack-status": "^1.15",
|
||||
"automattic/jetpack-logo": "^1.5",
|
||||
"automattic/jetpack-assets": "^1.17"
|
||||
},
|
||||
@ -36,7 +36,8 @@
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\"",
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"watch": [
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"pnpm run watch"
|
||||
|
@ -28,7 +28,7 @@ class Identity_Crisis {
|
||||
/**
|
||||
* Package Version
|
||||
*/
|
||||
const PACKAGE_VERSION = '0.8.22';
|
||||
const PACKAGE_VERSION = '0.8.31';
|
||||
|
||||
/**
|
||||
* Instance of the object.
|
||||
|
@ -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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.2.33] - 2022-11-08
|
||||
### Changed
|
||||
- Updated package dependencies. [#27289]
|
||||
|
||||
## [2.2.32] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [2.2.31] - 2022-11-01
|
||||
### Changed
|
||||
- Updated package dependencies. [#27196]
|
||||
|
||||
## [2.2.30] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [2.2.29] - 2022-10-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#26791]
|
||||
|
||||
## [2.2.28] - 2022-10-05
|
||||
### Changed
|
||||
- Updated package dependencies. [#26568]
|
||||
|
||||
## [2.2.27] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [2.2.26] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -478,6 +506,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Update Jetpack to use new JITM package
|
||||
|
||||
[2.2.33]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.32...v2.2.33
|
||||
[2.2.32]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.31...v2.2.32
|
||||
[2.2.31]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.30...v2.2.31
|
||||
[2.2.30]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.29...v2.2.30
|
||||
[2.2.29]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.28...v2.2.29
|
||||
[2.2.28]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.27...v2.2.28
|
||||
[2.2.27]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.26...v2.2.27
|
||||
[2.2.26]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.25...v2.2.26
|
||||
[2.2.25]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.24...v2.2.25
|
||||
[2.2.24]: https://github.com/Automattic/jetpack-jitm/compare/v2.2.23...v2.2.24
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '2844220d1ce117cbcaed');
|
||||
<?php return array('dependencies' => array('wp-polyfill'), 'version' => '00af8e5432ff8e29efed');
|
||||
|
@ -1 +1 @@
|
||||
(()=>{"use strict";jQuery(document).ready((function(t){var a={default:function(a){var e='<div class="jitm-card jitm-banner '+(a.CTA.message?"has-call-to-action":"")+" is-upgrade-premium "+a.content.classes+'" data-stats_url="'+a.jitm_stats_url+'">';if(e+='<div class="jitm-banner__content">',e+='<div class="jitm-banner__icon-plan">'+a.content.icon+"</div>",e+='<div class="jitm-banner__info">',e+='<div class="jitm-banner__title">'+a.content.message+"</div>",a.content.description&&""!==a.content.description){if(e+='<div class="jitm-banner__description">'+a.content.description,a.content.list.length>0){e+='<ul class="banner__list">';for(var i=0;i<a.content.list.length;i++){var n=a.content.list[i].item;a.content.list[i].url&&(n='<a href="'+a.content.list[i].url+'" target="_blank" rel="noopener noreferrer" data-module="'+a.feature_class+'" data-jptracks-name="nudge_item_click" data-jptracks-prop="jitm-'+a.id+'">'+n+"</a>"),e+='<li><svg class="gridicon gridicons-checkmark" height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414" /></g></svg>'+n+"</li>"}}e+="</div>"}if(e+="</div>",e+="</div>",e+='<div class="jitm-banner__buttons_container">',a.activate_module&&(e+='<div class="jitm-banner__action" id="jitm-banner__activate">',e+='<a href="#" data-module="'+a.activate_module+'" type="button" class="jitm-button is-compact is-primary jptracks" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'-activate_module">'+window.jitm_config.activate_module_text+"</a>",e+="</div>"),a.CTA.message){var c="jitm-button is-compact jptracks";a.CTA.primary&&null===a.activate_module&&(c+=" is-primary");var o=a.CTA.ajax_action;e+='<div class="jitm-banner__action">',e+='<a href="'+(a.CTA.hasOwnProperty("link")&&a.CTA.link.length?a.CTA.link:a.url)+'" target="'+(!1===a.CTA.newWindow||o?"_self":"_blank")+'" rel="noopener noreferrer" title="'+a.CTA.message+'" data-module="'+a.feature_class+'" type="button" class="'+c+'" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'" '+(o?'data-ajax-action="'+o+'"':"")+">"+a.CTA.message+"</a>",e+="</div>"}return e+="</div>",a.is_dismissible&&(e+='<a href="#" data-module="'+a.feature_class+'" class="jitm-banner__dismiss"></a>'),t(e+="</div>")}},e=function(){t(".jetpack-jitm-message").each((function(){var e=t(this),i=e.data("message-path"),n=e.data("query"),c=e.data("redirect"),o=location.hash;"_dashboard"!==(o=o.replace(/#\//,"_"))&&(i=i.replace("toplevel_page_jetpack","toplevel_page_jetpack"+o));var r=!!t(".jetpack-logo__masthead").length;t.get(window.jitm_config.api_root+"jetpack/v4/jitm",{message_path:i,query:n,full_jp_logo_exists:r,_wpnonce:e.data("nonce")}).then((function(i){"object"==typeof i&&i[1]&&(i=[i[1]]),0!==i.length&&i[0].content&&function(e,i,n){var c;(c=i.template)&&a[c]||(c="default"),i.url=i.url+"&redirect="+n;var o,r=a[c](i);r.find(".jitm-banner__dismiss").on("click",(o=r,function(a){a.preventDefault(),o.hide(),t.ajax({url:window.jitm_config.api_root+"jetpack/v4/jitm",method:"POST",beforeSend:function(t){t.setRequestHeader("X-WP-Nonce",window.jitm_config.nonce)},data:{id:i.id,feature_class:i.feature_class}})})),t("#jp-admin-notices").length>0?(e.innerHTML=r,t("#jp-admin-notices").find(".jitm-card")&&t(".jitm-card").replaceWith(r),r.prependTo(t("#jp-admin-notices"))):e.replaceWith(r),r.find("#jitm-banner__activate a").on("click",(function(){var a=t(this);if(a.attr("disabled"))return!1;t.ajax({url:window.jitm_config.api_root+"jetpack/v4/module/"+a.data("module")+"/active",method:"POST",beforeSend:function(a){a.setRequestHeader("X-WP-Nonce",e.data("nonce")),t("#jitm-banner__activate a").text(window.jitm_config.activating_module_text),t("#jitm-banner__activate a").attr("disabled",!0)}}).done((function(){t("#jitm-banner__activate a").text(window.jitm_config.activated_module_text),t("#jitm-banner__activate a").attr("disabled",!0),setTimeout((function(){r.fadeOut("slow")}),2e3)}))})),r.find(".jitm-button[data-ajax-action]").on("click",(function(a){a.preventDefault();var i=t(this);return i.attr("disabled",!0),t.post(window.ajaxurl,{action:i.data("ajax-action"),_nonce:e.data("ajax-nonce")}).done((function(){r.fadeOut("slow")})).fail((function(){i.attr("disabled",!1)})),!1}))}(e,i[0],c)}))}))};e(),t(window).on("hashchange",(function(t){if(t.originalEvent.newURL.indexOf("jetpack#/")>=0){var a=document.querySelector(".jitm-card");a&&a.remove(),e()}}))}))})();
|
||||
!function(){"use strict";jQuery(document).ready((function(t){var a={default:function(a){var e='<div class="jitm-card jitm-banner '+(a.CTA.message?"has-call-to-action":"")+" is-upgrade-premium "+a.content.classes+'" data-stats_url="'+a.jitm_stats_url+'">';if(e+='<div class="jitm-banner__content">',e+='<div class="jitm-banner__icon-plan">'+a.content.icon+"</div>",e+='<div class="jitm-banner__info">',e+='<div class="jitm-banner__title">'+a.content.message+"</div>",a.content.description&&""!==a.content.description){if(e+='<div class="jitm-banner__description">'+a.content.description,a.content.list.length>0){e+='<ul class="banner__list">';for(var i=0;i<a.content.list.length;i++){var n=a.content.list[i].item;a.content.list[i].url&&(n='<a href="'+a.content.list[i].url+'" target="_blank" rel="noopener noreferrer" data-module="'+a.feature_class+'" data-jptracks-name="nudge_item_click" data-jptracks-prop="jitm-'+a.id+'">'+n+"</a>"),e+='<li><svg class="gridicon gridicons-checkmark" height="16" width="16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M9 19.414l-6.707-6.707 1.414-1.414L9 16.586 20.293 5.293l1.414 1.414" /></g></svg>'+n+"</li>"}}e+="</div>"}if(e+="</div>",e+="</div>",e+='<div class="jitm-banner__buttons_container">',a.activate_module&&(e+='<div class="jitm-banner__action" id="jitm-banner__activate">',e+='<a href="#" data-module="'+a.activate_module+'" type="button" class="jitm-button is-compact is-primary jptracks" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'-activate_module">'+window.jitm_config.activate_module_text+"</a>",e+="</div>"),a.CTA.message){var c="jitm-button is-compact jptracks";a.CTA.primary&&null===a.activate_module&&(c+=" is-primary");var o=a.CTA.ajax_action;e+='<div class="jitm-banner__action">',e+='<a href="'+(a.CTA.hasOwnProperty("link")&&a.CTA.link.length?a.CTA.link:a.url)+'" target="'+(!1===a.CTA.newWindow||o?"_self":"_blank")+'" rel="noopener noreferrer" title="'+a.CTA.message+'" data-module="'+a.feature_class+'" type="button" class="'+c+'" data-jptracks-name="nudge_click" data-jptracks-prop="jitm-'+a.id+'" '+(o?'data-ajax-action="'+o+'"':"")+">"+a.CTA.message+"</a>",e+="</div>"}return e+="</div>",a.is_dismissible&&(e+='<a href="#" data-module="'+a.feature_class+'" class="jitm-banner__dismiss"></a>'),t(e+="</div>")}},e=function(){t(".jetpack-jitm-message").each((function(){var e=t(this),i=e.data("message-path"),n=e.data("query"),c=e.data("redirect"),o=location.hash;"_dashboard"!==(o=o.replace(/#\//,"_"))&&(i=i.replace("toplevel_page_jetpack","toplevel_page_jetpack"+o));var r=!!t(".jetpack-logo__masthead").length;t.get(window.jitm_config.api_root+"jetpack/v4/jitm",{message_path:i,query:n,full_jp_logo_exists:r,_wpnonce:e.data("nonce")}).then((function(i){"object"==typeof i&&i[1]&&(i=[i[1]]),0!==i.length&&i[0].content&&function(e,i,n){var c;(c=i.template)&&a[c]||(c="default"),i.url=i.url+"&redirect="+n;var o,r=a[c](i);r.find(".jitm-banner__dismiss").on("click",(o=r,function(a){a.preventDefault(),o.hide(),t.ajax({url:window.jitm_config.api_root+"jetpack/v4/jitm",method:"POST",beforeSend:function(t){t.setRequestHeader("X-WP-Nonce",window.jitm_config.nonce)},data:{id:i.id,feature_class:i.feature_class}})})),t("#jp-admin-notices").length>0?(e.innerHTML=r,t("#jp-admin-notices").find(".jitm-card")&&t(".jitm-card").replaceWith(r),r.prependTo(t("#jp-admin-notices"))):e.replaceWith(r),r.find("#jitm-banner__activate a").on("click",(function(){var a=t(this);if(a.attr("disabled"))return!1;t.ajax({url:window.jitm_config.api_root+"jetpack/v4/module/"+a.data("module")+"/active",method:"POST",beforeSend:function(a){a.setRequestHeader("X-WP-Nonce",e.data("nonce")),t("#jitm-banner__activate a").text(window.jitm_config.activating_module_text),t("#jitm-banner__activate a").attr("disabled",!0)}}).done((function(){t("#jitm-banner__activate a").text(window.jitm_config.activated_module_text),t("#jitm-banner__activate a").attr("disabled",!0),setTimeout((function(){r.fadeOut("slow")}),2e3)}))})),r.find(".jitm-button[data-ajax-action]").on("click",(function(a){a.preventDefault();var i=t(this);return i.attr("disabled",!0),t.post(window.ajaxurl,{action:i.data("ajax-action"),_nonce:e.data("ajax-nonce")}).done((function(){r.fadeOut("slow")})).fail((function(){i.attr("disabled",!1)})),!1}))}(e,i[0],c)}))}))};e(),t(window).on("hashchange",(function(t){if(t.originalEvent.newURL.indexOf("jetpack#/")>=0){var a=document.querySelector(".jitm-card");a&&a.remove(),e()}}))}))}();
|
@ -6,12 +6,12 @@
|
||||
"require": {
|
||||
"automattic/jetpack-a8c-mc-stats": "^1.4",
|
||||
"automattic/jetpack-assets": "^1.17",
|
||||
"automattic/jetpack-connection": "^1.44",
|
||||
"automattic/jetpack-connection": "^1.46",
|
||||
"automattic/jetpack-device-detection": "^1.4",
|
||||
"automattic/jetpack-logo": "^1.5",
|
||||
"automattic/jetpack-partner": "^1.7",
|
||||
"automattic/jetpack-redirect": "^1.7",
|
||||
"automattic/jetpack-status": "^1.14"
|
||||
"automattic/jetpack-status": "^1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"brain/monkey": "2.6.1",
|
||||
|
@ -20,7 +20,7 @@ use Automattic\Jetpack\Status;
|
||||
*/
|
||||
class JITM {
|
||||
|
||||
const PACKAGE_VERSION = '2.2.26';
|
||||
const PACKAGE_VERSION = '2.2.33';
|
||||
|
||||
/**
|
||||
* The configuration method that is called from the jetpack-config package.
|
||||
|
@ -5,6 +5,18 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.7.11] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [1.7.10] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.7.9] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.7.8] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -206,6 +218,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Licensing: Add support for Jetpack licenses
|
||||
|
||||
[1.7.11]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.10...v1.7.11
|
||||
[1.7.10]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.9...v1.7.10
|
||||
[1.7.9]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.8...v1.7.9
|
||||
[1.7.8]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.7...v1.7.8
|
||||
[1.7.7]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.6...v1.7.7
|
||||
[1.7.6]: https://github.com/Automattic/jetpack-licensing/compare/v1.7.5...v1.7.6
|
||||
|
@ -4,7 +4,7 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-connection": "^1.44"
|
||||
"automattic/jetpack-connection": "^1.46"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/wordbless": "@dev",
|
||||
@ -20,7 +20,8 @@
|
||||
"phpunit": [
|
||||
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\"",
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"test-coverage": [
|
||||
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-clover \"$COVERAGE_DIR/clover.xml\""
|
||||
],
|
||||
|
@ -5,6 +5,10 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.5.18] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.5.17] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -126,6 +130,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Packages: Add a basic Jetpack Logo package
|
||||
|
||||
[1.5.18]: https://github.com/Automattic/jetpack-logo/compare/v1.5.17...v1.5.18
|
||||
[1.5.17]: https://github.com/Automattic/jetpack-logo/compare/v1.5.16...v1.5.17
|
||||
[1.5.16]: https://github.com/Automattic/jetpack-logo/compare/v1.5.15...v1.5.16
|
||||
[1.5.15]: https://github.com/Automattic/jetpack-logo/compare/v1.5.14...v1.5.15
|
||||
|
@ -5,6 +5,95 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.4.0] - 2022-11-17
|
||||
### Added
|
||||
- Added Jetpack Protect to My Jetpack. [#26069]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#26736]
|
||||
|
||||
## [2.3.5] - 2022-11-10
|
||||
### Changed
|
||||
- Updated package dependencies. [#27319]
|
||||
|
||||
## [2.3.4] - 2022-11-08
|
||||
### Changed
|
||||
- Updated package dependencies. [#27289]
|
||||
|
||||
## [2.3.3] - 2022-11-01
|
||||
### Changed
|
||||
- Updated package dependencies. [#27196]
|
||||
|
||||
## [2.3.2] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [2.3.1] - 2022-10-25
|
||||
### Added
|
||||
- Add a flag to indicate if the pricing is introductory with product price [#26982]
|
||||
- My Jetpack: Support trial [#27033]
|
||||
|
||||
### Changed
|
||||
- Search: now support 38 languages [#27025]
|
||||
|
||||
### Fixed
|
||||
- Don't show old price when it's the same as new one [#27015]
|
||||
- Search: check if free plan and new pricing is active using wpcom API [#27016]
|
||||
|
||||
## [2.3.0] - 2022-10-19
|
||||
### Added
|
||||
- Added support for free product and added free product for Search [#26808]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#26883]
|
||||
|
||||
## [2.2.3] - 2022-10-17
|
||||
### Changed
|
||||
- Updated package dependencies. [#26851]
|
||||
|
||||
## [2.2.2] - 2022-10-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#26790]
|
||||
|
||||
## [2.2.1] - 2022-10-11
|
||||
### Changed
|
||||
- Updated package dependencies. [#25973]
|
||||
|
||||
## [2.2.0] - 2022-10-05
|
||||
### Added
|
||||
- Integrate the new connection error message React component into My Jetpack. [#26485]
|
||||
- Search: add post type breakdown endpoint [#26463]
|
||||
- Trigger restore connection flow. [#26489]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#26457]
|
||||
|
||||
## [2.1.1] - 2022-09-27
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [2.1.0] - 2022-09-20
|
||||
### Added
|
||||
- Added the ConnectionErrorNotice React component. [#26259]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
### Fixed
|
||||
- Fixed the tests for the Module_Product class by creating and using a sample, test-only module product class as the test subject instead of relying on Videopress or other concrete products. [#26227]
|
||||
|
||||
## [2.0.5] - 2022-09-08
|
||||
### Changed
|
||||
- Change VideoPress into a Hybrid product in My Jetpack [#25954]
|
||||
- Updated package dependencies.
|
||||
|
||||
## [2.0.4] - 2022-08-31
|
||||
### Added
|
||||
- Allow plugins to override a product class. [#25891]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#25856]
|
||||
|
||||
## [2.0.3] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -579,6 +668,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- Created package
|
||||
|
||||
[2.4.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.5...2.4.0
|
||||
[2.3.5]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.4...2.3.5
|
||||
[2.3.4]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.3...2.3.4
|
||||
[2.3.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.2...2.3.3
|
||||
[2.3.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.1...2.3.2
|
||||
[2.3.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.3.0...2.3.1
|
||||
[2.3.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.2.3...2.3.0
|
||||
[2.2.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.2.2...2.2.3
|
||||
[2.2.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.2.1...2.2.2
|
||||
[2.2.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.2.0...2.2.1
|
||||
[2.2.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.1.1...2.2.0
|
||||
[2.1.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.1.0...2.1.1
|
||||
[2.1.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.5...2.1.0
|
||||
[2.0.5]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.4...2.0.5
|
||||
[2.0.4]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.3...2.0.4
|
||||
[2.0.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.2...2.0.3
|
||||
[2.0.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.1...2.0.2
|
||||
[2.0.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.0.0...2.0.1
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'ef234302efce2d8f505a');
|
||||
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => 'c8b0206144b22212a975');
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@
|
||||
"require": {
|
||||
"automattic/jetpack-admin-ui": "^0.2",
|
||||
"automattic/jetpack-assets": "^1.17",
|
||||
"automattic/jetpack-connection": "^1.44",
|
||||
"automattic/jetpack-connection": "^1.46",
|
||||
"automattic/jetpack-jitm": "^2.2",
|
||||
"automattic/jetpack-licensing": "^1.7",
|
||||
"automattic/jetpack-plugins-installer": "^0.2",
|
||||
@ -52,7 +52,8 @@
|
||||
"Composer\\Config::disableProcessTimeout",
|
||||
"pnpm run watch"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
@ -64,7 +65,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "2.0.x-dev"
|
||||
"dev-trunk": "2.4.x-dev"
|
||||
},
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-initializer.php"
|
||||
|
@ -15,6 +15,7 @@ use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Automattic\Jetpack\Connection\Rest_Authentication as Connection_Rest_Authentication;
|
||||
use Automattic\Jetpack\JITMS\JITM as JITM;
|
||||
use Automattic\Jetpack\Licensing;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Status as Status;
|
||||
use Automattic\Jetpack\Terms_Of_Service;
|
||||
use Automattic\Jetpack\Tracking;
|
||||
@ -29,7 +30,7 @@ class Initializer {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PACKAGE_VERSION = '2.0.3';
|
||||
const PACKAGE_VERSION = '2.4.0';
|
||||
|
||||
/**
|
||||
* Initialize My Jetapack
|
||||
@ -159,6 +160,7 @@ class Initializer {
|
||||
'purchases' => array(
|
||||
'items' => array(),
|
||||
),
|
||||
'plugins' => Plugins_Installer::get_plugins(),
|
||||
'myJetpackUrl' => admin_url( 'admin.php?page=my-jetpack' ),
|
||||
'topJetpackMenuItemUrl' => Admin_Menu::get_top_level_menu_item_url(),
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
|
@ -17,22 +17,49 @@ class Products {
|
||||
*
|
||||
* Here's where all the existing Products are registered
|
||||
*
|
||||
* @throws \Exception If the result of a filter has invalid classes.
|
||||
* @return array List of class names
|
||||
*/
|
||||
public static function get_products_classes() {
|
||||
return array(
|
||||
Products\Anti_Spam::class,
|
||||
Products\Backup::class,
|
||||
Products\Boost::class,
|
||||
Products\Crm::class,
|
||||
Products\Extras::class,
|
||||
Products\Scan::class,
|
||||
Products\Search::class,
|
||||
Products\Social::class,
|
||||
Products\Security::class,
|
||||
Products\Protect::class,
|
||||
Products\Videopress::class,
|
||||
$classes = array(
|
||||
'anti-spam' => Products\Anti_Spam::class,
|
||||
'backup' => Products\Backup::class,
|
||||
'boost' => Products\Boost::class,
|
||||
'crm' => Products\Crm::class,
|
||||
'extras' => Products\Extras::class,
|
||||
'scan' => Products\Scan::class,
|
||||
'search' => Products\Search::class,
|
||||
'social' => Products\Social::class,
|
||||
'security' => Products\Security::class,
|
||||
'protect' => Products\Protect::class,
|
||||
'videopress' => Products\Videopress::class,
|
||||
);
|
||||
|
||||
/**
|
||||
* This filter allows plugin to override the Product class of a given product. The new class must be a child class of the default one declared in My Jetpack
|
||||
*
|
||||
* For example, a stand-alone plugin could overwrite its product class to control specific behavior of the product in the My Jetpack page after it is active without having to commit changes to the My Jetpack package:
|
||||
*
|
||||
* add_filter( 'my_jetpack_products_classes', function( $classes ) {
|
||||
* $classes['my_plugin'] = 'My_Plugin'; // a class that extends the original one declared in the My Jetpack package.
|
||||
* return $classes
|
||||
* } );
|
||||
*
|
||||
* @param array $classes An array where the keys are the product slugs and the values are the class names.
|
||||
*/
|
||||
$final_classes = apply_filters( 'my_jetpack_products_classes', $classes );
|
||||
|
||||
// Check that the classes are still child of the same original classes.
|
||||
foreach ( (array) $final_classes as $slug => $final_class ) {
|
||||
if ( $final_class === $classes[ $slug ] ) {
|
||||
continue;
|
||||
}
|
||||
if ( ! class_exists( $final_class ) || ! is_subclass_of( $final_class, $classes[ $slug ] ) ) {
|
||||
throw new \Exception( 'You can only overwrite a Product class with a child of the original class.' );
|
||||
}
|
||||
}
|
||||
|
||||
return $final_classes;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,13 +84,24 @@ class Products {
|
||||
* @return ?array
|
||||
*/
|
||||
public static function get_product( $product_slug ) {
|
||||
foreach ( self::get_products_classes() as $class ) {
|
||||
$p_slug = $class::$slug;
|
||||
if ( $p_slug === $product_slug ) {
|
||||
return $class::get_info();
|
||||
}
|
||||
$classes = self::get_products_classes();
|
||||
if ( isset( $classes[ $product_slug ] ) ) {
|
||||
return $classes[ $product_slug ]::get_info();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get one product Class name
|
||||
*
|
||||
* @param string $product_slug The product slug.
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_product_class( $product_slug ) {
|
||||
$classes = self::get_products_classes();
|
||||
if ( isset( $classes[ $product_slug ] ) ) {
|
||||
return $classes[ $product_slug ];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -72,11 +110,7 @@ class Products {
|
||||
* @return array Product slugs array.
|
||||
*/
|
||||
public static function get_products_slugs() {
|
||||
$slugs = array();
|
||||
foreach ( self::get_products_classes() as $class ) {
|
||||
$slugs[] = $class::$slug;
|
||||
}
|
||||
return $slugs;
|
||||
return array_keys( self::get_products_classes() );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,7 +152,7 @@ class Products {
|
||||
'status' => array(
|
||||
'title' => 'The product status',
|
||||
'type' => 'string',
|
||||
'enum' => array( 'active', 'inactive', 'plugin_absent', 'needs_purchase', 'error' ),
|
||||
'enum' => array( 'active', 'inactive', 'plugin_absent', 'needs_purchase', 'needs_purchase_or_free', 'error' ),
|
||||
),
|
||||
'class' => array(
|
||||
'title' => 'The product class handler',
|
||||
@ -133,12 +167,16 @@ class Products {
|
||||
* tied to the Products.
|
||||
*/
|
||||
public static function extend_plugins_action_links() {
|
||||
Products\Backup::extend_plugin_action_links();
|
||||
Products\Boost::extend_plugin_action_links();
|
||||
Products\Crm::extend_plugin_action_links();
|
||||
|
||||
// Extend Jetpack plugin using Videopress instance.
|
||||
Products\Videopress::extend_plugin_action_links();
|
||||
$products = array(
|
||||
'backup',
|
||||
'boost',
|
||||
'crm',
|
||||
'videopress', // we use videopress here to add the plugin action to the Jetpack plugin itself
|
||||
);
|
||||
foreach ( $products as $product ) {
|
||||
$class_name = self::get_product_class( $product );
|
||||
$class_name::extend_plugin_action_links();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -157,18 +157,21 @@ class Wpcom_Products {
|
||||
return array();
|
||||
}
|
||||
|
||||
$cost = $product->cost;
|
||||
$discount_price = $cost;
|
||||
$cost = $product->cost;
|
||||
$discount_price = $cost;
|
||||
$is_introductory_offer = false;
|
||||
|
||||
// Get/compute the discounted price.
|
||||
if ( isset( $product->introductory_offer->cost_per_interval ) ) {
|
||||
$discount_price = $product->introductory_offer->cost_per_interval;
|
||||
$discount_price = $product->introductory_offer->cost_per_interval;
|
||||
$is_introductory_offer = true;
|
||||
}
|
||||
|
||||
$pricing = array(
|
||||
'currency_code' => $product->currency_code,
|
||||
'full_price' => $cost,
|
||||
'discount_price' => $discount_price,
|
||||
'currency_code' => $product->currency_code,
|
||||
'full_price' => $cost,
|
||||
'discount_price' => $discount_price,
|
||||
'is_introductory_offer' => $is_introductory_offer,
|
||||
);
|
||||
|
||||
return self::populate_with_discount( $product, $pricing, $discount_price );
|
||||
|
@ -76,7 +76,6 @@ abstract class Hybrid_Product extends Product {
|
||||
|
||||
/*
|
||||
* Otherwise, activate Jetpack plugin.
|
||||
* Silent mode True to avoid redirects.
|
||||
*/
|
||||
if ( static::is_jetpack_plugin_installed() ) {
|
||||
return activate_plugin( static::get_installed_plugin_filename( 'jetpack' ) );
|
||||
@ -95,7 +94,7 @@ abstract class Hybrid_Product extends Product {
|
||||
|
||||
if ( is_wp_error( $product_activation ) ) {
|
||||
// If we failed to install the stand-alone plugin because the package was not found, let's try and install Jetpack plugin instead.
|
||||
// This might happens, for example, while the stand-alone plugin was not released to the WP.org repository yet.
|
||||
// This might happen, for example, while the stand-alone plugin was not released to the WP.org repository yet.
|
||||
if ( 'no_package' === $product_activation->get_error_code() ) {
|
||||
$product_activation = Plugins_Installer::install_plugin( self::JETPACK_PLUGIN_SLUG );
|
||||
if ( ! is_wp_error( $product_activation ) ) {
|
||||
|
@ -222,6 +222,19 @@ abstract class Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product supports trial or not
|
||||
*
|
||||
* Returns true if it supports. Return false otherwise.
|
||||
*
|
||||
* Free products will always return false.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_trial_support() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether product is a bundle.
|
||||
*
|
||||
@ -266,11 +279,19 @@ abstract class Product {
|
||||
// We only consider missing user connection an error when the Product is active.
|
||||
if ( static::$requires_user_connection && ! ( new Connection_Manager() )->has_connected_owner() ) {
|
||||
$status = 'error';
|
||||
} elseif ( ! static::has_required_plan() ) {
|
||||
$status = 'needs_purchase'; // We need needs_purchase here as well because some products we consider active without the required plan.
|
||||
} elseif ( ! static::has_required_plan() ) { // We need needs_purchase here as well because some products we consider active without the required plan.
|
||||
if ( static::has_trial_support() ) {
|
||||
$status = 'needs_purchase_or_free';
|
||||
} else {
|
||||
$status = 'needs_purchase';
|
||||
}
|
||||
}
|
||||
} elseif ( ! static::has_required_plan() ) {
|
||||
$status = 'needs_purchase';
|
||||
if ( static::has_trial_support() ) {
|
||||
$status = 'needs_purchase_or_free';
|
||||
} else {
|
||||
$status = 'needs_purchase';
|
||||
}
|
||||
} else {
|
||||
$status = 'inactive';
|
||||
}
|
||||
|
@ -14,9 +14,28 @@ use Jetpack_Options;
|
||||
* Search stats (e.g. post count, post type breakdown)
|
||||
*/
|
||||
class Search_Stats {
|
||||
const CACHE_EXPIRY = 5 * MINUTE_IN_SECONDS;
|
||||
const CACHE_GROUP = 'jetpack_search';
|
||||
const COUNT_ESTIMATE_CACHE_KEY = 'count_estimate';
|
||||
const EXCLUDED_POST_TYPES = array(
|
||||
'elementor_library', // Used by Elementor.
|
||||
'jp_sitemap', // Used by Jetpack.
|
||||
'revision',
|
||||
'vip-legacy-redirect',
|
||||
'scheduled-action',
|
||||
'nbcs_video_lookup',
|
||||
'reply', // bbpress, these get included in the topic
|
||||
'product_variation', // woocommerce, not really public
|
||||
'nav_menu_item',
|
||||
'shop_order', // woocommerce, not really public
|
||||
'redirect_rule', // Used by the Safe Redirect plugin.
|
||||
);
|
||||
|
||||
const DO_NOT_EXCLUDE_POST_TYPES = array(
|
||||
'topic', // bbpress
|
||||
'forum', // bbpress
|
||||
);
|
||||
|
||||
const CACHE_EXPIRY = 1 * MINUTE_IN_SECONDS;
|
||||
const CACHE_GROUP = 'jetpack_search';
|
||||
const POST_TYPE_BREAKDOWN_CACHE_KEY = 'post_type_break_down';
|
||||
|
||||
/**
|
||||
* Get stats from the WordPress.com API for the current blog ID.
|
||||
@ -43,47 +62,89 @@ class Search_Stats {
|
||||
* Estimate record counts via a local database query.
|
||||
*/
|
||||
public static function estimate_count() {
|
||||
$cached_value = wp_cache_get( self::COUNT_ESTIMATE_CACHE_KEY, self::CACHE_GROUP );
|
||||
if ( false !== $cached_value ) {
|
||||
return $cached_value;
|
||||
}
|
||||
return array_sum( static::get_post_type_breakdown() );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$indexable_statuses = get_post_stati( array( 'public' => true ) );
|
||||
$unindexable_post_types = array_merge(
|
||||
// Explicitly exclude various post types registered by plugins.
|
||||
/**
|
||||
* Calculate breakdown of post types for the site.
|
||||
*/
|
||||
public static function get_post_type_breakdown() {
|
||||
$indexable_post_types = get_post_types(
|
||||
array(
|
||||
'elementor_library', // Used by Elementor.
|
||||
'jp_sitemap', // Used by Jetpack.
|
||||
'product_variation', // Used by Woocommerce.
|
||||
'redirect_rule', // Used by the Safe Redirect plugin.
|
||||
'reply', // Used by bbpress.
|
||||
'scheduled-action', // Used by Woocommerce.
|
||||
),
|
||||
get_post_types(
|
||||
array(
|
||||
'exclude_from_search' => true,
|
||||
'public' => false,
|
||||
),
|
||||
'names',
|
||||
'or'
|
||||
'public' => true,
|
||||
'exclude_from_search' => false,
|
||||
)
|
||||
);
|
||||
|
||||
$prep_for_query = function ( $string ) use ( $wpdb ) {
|
||||
// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.QuotedSimplePlaceholder -- This is used to sanitize post type names.
|
||||
return $wpdb->prepare( "'%s'", $string );
|
||||
};
|
||||
|
||||
$statuses_list = implode( ',', array_map( $prep_for_query, $indexable_statuses ) );
|
||||
$post_types_list = implode( ',', array_map( $prep_for_query, $unindexable_post_types ) );
|
||||
|
||||
$count = (int) $wpdb->get_var(
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- This is properly prepared, but the query is constructed using variables.
|
||||
"SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status IN ($statuses_list) AND post_type NOT IN ($post_types_list)"
|
||||
$indexable_status_array = get_post_stati(
|
||||
array(
|
||||
'public' => true,
|
||||
'exclude_from_search' => false,
|
||||
)
|
||||
);
|
||||
$raw_posts_counts = static::get_raw_post_type_breakdown();
|
||||
if ( ! $raw_posts_counts || is_wp_error( $raw_posts_counts ) ) {
|
||||
return array();
|
||||
}
|
||||
$posts_counts = static::get_post_type_breakdown_with( $raw_posts_counts, $indexable_post_types, $indexable_status_array );
|
||||
|
||||
wp_cache_set( self::COUNT_ESTIMATE_CACHE_KEY, $count, self::CACHE_GROUP, self::CACHE_EXPIRY );
|
||||
return $count;
|
||||
return $posts_counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate breakdown of post types with passed in indexable post types and statuses.
|
||||
* The function is going to be used from WPCOM as well for consistency.
|
||||
*
|
||||
* @param array $raw_posts_counts Array of post types with counts as value.
|
||||
* @param array $indexable_post_types Array of indexable post types.
|
||||
* @param array $indexable_status_array Array of indexable post statuses.
|
||||
*/
|
||||
public static function get_post_type_breakdown_with( $raw_posts_counts, $indexable_post_types, $indexable_status_array ) {
|
||||
$posts_counts = array();
|
||||
foreach ( $raw_posts_counts as $row ) {
|
||||
// ignore if status is not public.
|
||||
if ( ! in_array( $row['post_status'], $indexable_status_array, true ) ) {
|
||||
continue;
|
||||
}
|
||||
// ignore if post type is in excluded post types.
|
||||
if ( in_array( $row['post_type'], self::EXCLUDED_POST_TYPES, true ) ) {
|
||||
continue;
|
||||
}
|
||||
// ignore if post type is not public and is not explicitly included.
|
||||
if ( ! in_array( $row['post_type'], $indexable_post_types, true ) &&
|
||||
! in_array( $row['post_type'], self::DO_NOT_EXCLUDE_POST_TYPES, true )
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
// add up post type counts of potentially multiple post_status.
|
||||
if ( ! isset( $posts_counts[ $row['post_type'] ] ) ) {
|
||||
$posts_counts[ $row['post_type'] ] = 0;
|
||||
}
|
||||
$posts_counts[ $row['post_type'] ] += intval( $row['num_posts'] );
|
||||
}
|
||||
|
||||
arsort( $posts_counts, SORT_NUMERIC );
|
||||
return $posts_counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw post type breakdown from the database.
|
||||
*/
|
||||
protected static function get_raw_post_type_breakdown() {
|
||||
global $wpdb;
|
||||
|
||||
$results = wp_cache_get( self::POST_TYPE_BREAKDOWN_CACHE_KEY, self::CACHE_GROUP );
|
||||
if ( false !== $results ) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
$query = "SELECT post_type, post_status, COUNT( * ) AS num_posts
|
||||
FROM {$wpdb->posts}
|
||||
WHERE post_password = ''
|
||||
GROUP BY post_type, post_status";
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
|
||||
$results = $wpdb->get_results( $query, ARRAY_A );
|
||||
wp_cache_set( self::POST_TYPE_BREAKDOWN_CACHE_KEY, $results, self::CACHE_GROUP, self::CACHE_EXPIRY );
|
||||
return $results;
|
||||
}
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ class Search extends Hybrid_Product {
|
||||
return array(
|
||||
__( 'Instant search and indexing', 'jetpack-my-jetpack' ),
|
||||
__( 'Powerful filtering', 'jetpack-my-jetpack' ),
|
||||
__( 'Supports 29 languages', 'jetpack-my-jetpack' ),
|
||||
__( 'Supports 38 languages', 'jetpack-my-jetpack' ),
|
||||
__( 'Spelling correction', 'jetpack-my-jetpack' ),
|
||||
);
|
||||
}
|
||||
@ -117,8 +117,10 @@ class Search extends Hybrid_Product {
|
||||
// Basic pricing info.
|
||||
$pricing = array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
'available' => true,
|
||||
'trial_available' => static::has_trial_support(),
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
'wpcom_free_product_slug' => static::get_wpcom_free_product_slug(),
|
||||
),
|
||||
Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() )
|
||||
);
|
||||
@ -130,6 +132,8 @@ class Search extends Hybrid_Product {
|
||||
return $pricing;
|
||||
}
|
||||
|
||||
$pricing['estimated_record_count'] = $record_count;
|
||||
|
||||
return array_merge( $pricing, $search_pricing );
|
||||
}
|
||||
|
||||
@ -142,6 +146,41 @@ class Search extends Hybrid_Product {
|
||||
return 'jetpack_search';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM free product slug
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_free_product_slug() {
|
||||
return 'jetpack_search_free';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the new_pricing_202208 is set to not empty in URL for testing purpose, or it's active.
|
||||
*/
|
||||
public static function is_new_pricing_202208() {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
if ( isset( $_GET['new_pricing_202208'] ) && $_GET['new_pricing_202208'] ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$record_count = intval( Search_Stats::estimate_count() );
|
||||
$search_pricing = static::get_pricing_from_wpcom( $record_count );
|
||||
if ( is_wp_error( $search_pricing ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return '202208' === $search_pricing['pricing_version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Override status to `needs_purchase_or_free` when status is `needs_purchase`.
|
||||
*/
|
||||
public static function get_status() {
|
||||
$status = parent::get_status();
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use centralized Search pricing API.
|
||||
*
|
||||
@ -158,10 +197,22 @@ class Search extends Hybrid_Product {
|
||||
return $pricings[ $record_count ];
|
||||
}
|
||||
|
||||
$response = wp_remote_get(
|
||||
sprintf( Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/wpcom/v2/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ),
|
||||
array( 'timeout' => 5 )
|
||||
);
|
||||
if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
|
||||
// For simple sites fetch the response directly.
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
sprintf( '/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ),
|
||||
'2',
|
||||
array( 'timeout' => 5 ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
} else {
|
||||
// For non-simple sites we have to use the wp_remote_get, as connection might not be available.
|
||||
$response = wp_remote_get(
|
||||
sprintf( Constants::get_constant( 'JETPACK__WPCOM_JSON_API_BASE' ) . '/wpcom/v2/jetpack-search/pricing?record_count=%1$d&locale=%2$s', $record_count, get_user_locale() ),
|
||||
array( 'timeout' => 5 )
|
||||
);
|
||||
}
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'search_pricing_fetch_failed' );
|
||||
@ -205,6 +256,19 @@ class Search extends Hybrid_Product {
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product supports trial or not
|
||||
*
|
||||
* Returns true if it supports. Return false otherwise.
|
||||
*
|
||||
* Free products will always return false.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_trial_support() {
|
||||
return static::is_new_pricing_202208();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan of the site already supports the product
|
||||
*
|
||||
|
@ -7,13 +7,13 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Module_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the VideoPress product
|
||||
*/
|
||||
class Videopress extends Module_Product {
|
||||
class Videopress extends Hybrid_Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
@ -29,6 +29,31 @@ class Videopress extends Module_Product {
|
||||
*/
|
||||
public static $module_name = 'videopress';
|
||||
|
||||
/**
|
||||
* The slug of the plugin associated with this product.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $plugin_slug = 'jetpack-videopress';
|
||||
|
||||
/**
|
||||
* The filename (id) of the plugin associated with this product.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $plugin_filename = array(
|
||||
'jetpack-videopress/jetpack-videopress.php',
|
||||
'videopress/jetpack-videopress.php',
|
||||
'jetpack-videopress-dev/jetpack-videopress.php',
|
||||
);
|
||||
|
||||
/**
|
||||
* Search only requires site connection
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public static $requires_user_connection = true;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
@ -118,8 +143,11 @@ class Videopress extends Module_Product {
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
if ( static::is_active() ) {
|
||||
if ( method_exists( 'Automattic\Jetpack\VideoPress\Initializer', 'should_initialize_admin_ui' ) && \Automattic\Jetpack\VideoPress\Initializer::should_initialize_admin_ui() ) {
|
||||
return \Automattic\Jetpack\VideoPress\Admin_UI::get_admin_page_url();
|
||||
} else {
|
||||
return admin_url( 'admin.php?page=jetpack#/settings?term=videopress' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,6 +5,22 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.7.19] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [1.7.18] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [1.7.17] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.7.16] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.7.15] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -184,6 +200,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Add partner subsidiary id to upgrade URLs.
|
||||
|
||||
[1.7.19]: https://github.com/Automattic/jetpack-partner/compare/v1.7.18...v1.7.19
|
||||
[1.7.18]: https://github.com/Automattic/jetpack-partner/compare/v1.7.17...v1.7.18
|
||||
[1.7.17]: https://github.com/Automattic/jetpack-partner/compare/v1.7.16...v1.7.17
|
||||
[1.7.16]: https://github.com/Automattic/jetpack-partner/compare/v1.7.15...v1.7.16
|
||||
[1.7.15]: https://github.com/Automattic/jetpack-partner/compare/v1.7.14...v1.7.15
|
||||
[1.7.14]: https://github.com/Automattic/jetpack-partner/compare/v1.7.13...v1.7.14
|
||||
[1.7.13]: https://github.com/Automattic/jetpack-partner/compare/v1.7.12...v1.7.13
|
||||
|
@ -4,8 +4,8 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-connection": "^1.44",
|
||||
"automattic/jetpack-status": "^1.14"
|
||||
"automattic/jetpack-connection": "^1.46",
|
||||
"automattic/jetpack-status": "^1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"brain/monkey": "2.6.1",
|
||||
@ -22,7 +22,8 @@
|
||||
"phpunit": [
|
||||
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\"",
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"test-coverage": [
|
||||
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-clover \"$COVERAGE_DIR/clover.xml\""
|
||||
],
|
||||
|
@ -5,6 +5,10 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.7] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.2.6] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -76,6 +80,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Fixed
|
||||
- Use `composer update` rather than `install` in scripts, as composer.lock isn't checked in.
|
||||
|
||||
[0.2.7]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.6...v0.2.7
|
||||
[0.2.6]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.5...v0.2.6
|
||||
[0.2.5]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.4...v0.2.5
|
||||
[0.2.4]: https://github.com/Automattic/jetpack-password-checker/compare/v0.2.3...v0.2.4
|
||||
|
@ -24,7 +24,8 @@
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
|
@ -5,6 +5,10 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.7.19] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [1.7.18] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -152,6 +156,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Create Jetpack Redirect package
|
||||
|
||||
[1.7.19]: https://github.com/Automattic/jetpack-redirect/compare/v1.7.18...v1.7.19
|
||||
[1.7.18]: https://github.com/Automattic/jetpack-redirect/compare/v1.7.17...v1.7.18
|
||||
[1.7.17]: https://github.com/Automattic/jetpack-redirect/compare/v1.7.16...v1.7.17
|
||||
[1.7.16]: https://github.com/Automattic/jetpack-redirect/compare/v1.7.15...v1.7.16
|
||||
|
@ -4,7 +4,7 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-status": "^1.14"
|
||||
"automattic/jetpack-status": "^1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"brain/monkey": "2.6.1",
|
||||
|
@ -5,6 +5,10 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.15.0] - 2022-11-07
|
||||
### Added
|
||||
- WordPress.com: add checks for Simple or either Simple/WoA. [#27278]
|
||||
|
||||
## [1.14.3] - 2022-07-26
|
||||
### Changed
|
||||
- Updated package dependencies. [#25158]
|
||||
@ -208,6 +212,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Packages: Introduce a status package
|
||||
|
||||
[1.15.0]: https://github.com/Automattic/jetpack-status/compare/v1.14.3...v1.15.0
|
||||
[1.14.3]: https://github.com/Automattic/jetpack-status/compare/v1.14.2...v1.14.3
|
||||
[1.14.2]: https://github.com/Automattic/jetpack-status/compare/v1.14.1...v1.14.2
|
||||
[1.14.1]: https://github.com/Automattic/jetpack-status/compare/v1.14.0...v1.14.1
|
||||
|
@ -36,7 +36,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-status/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "1.14.x-dev"
|
||||
"dev-trunk": "1.15.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,26 @@ class Host {
|
||||
return Constants::is_defined( 'WPCOM_IS_VIP_ENV' ) && true === Constants::get_constant( 'WPCOM_IS_VIP_ENV' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this is a Simple platform site.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_wpcom_simple() {
|
||||
return Constants::is_defined( 'IS_WPCOM' ) && true === Constants::get_constant( 'IS_WPCOM' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this is a WordPress.com site.
|
||||
*
|
||||
* Includes both Simple and WoA platforms.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_wpcom_platform() {
|
||||
return $this->is_wpcom_simple() || $this->is_woa_site();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all wordpress.com environments to the safe redirect allowed list.
|
||||
*
|
||||
|
@ -5,6 +5,56 @@ 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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [1.43.0] - 2022-11-17
|
||||
### Added
|
||||
- Added new sync option for launch-status [#27434]
|
||||
- Jetpack Sync: Add new endpoint for resetting Sync locks. [#27446]
|
||||
|
||||
## [1.42.0] - 2022-11-14
|
||||
### Changed
|
||||
- Save attached media to post meta [#26930]
|
||||
|
||||
## [1.41.0] - 2022-11-07
|
||||
### Changed
|
||||
- Jetpack Sync: add Updates module in required Sync modules. [#27182]
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [1.40.3] - 2022-11-01
|
||||
### Added
|
||||
- Adds wpcom_gifting_subscription option for syncing [#27116]
|
||||
|
||||
## [1.40.2] - 2022-10-27
|
||||
### Fixed
|
||||
- Check $action_links is still array after plugin_action_links filter has been applied. [#27076]
|
||||
|
||||
## [1.40.1] - 2022-10-25
|
||||
### Added
|
||||
- Added featured_image_email_enabled option for syncing [#27009]
|
||||
|
||||
### Changed
|
||||
- Search Sync Settings :: Add Marketplace product extra fields meta to allow list [#26927]
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [1.40.0] - 2022-10-17
|
||||
### Added
|
||||
- Adding the `sl-insta-media` post type to the Sync blacklist as the post type data isn't relevant to Sync and takes up non-trivial resources. [#26826]
|
||||
|
||||
## [1.39.0] - 2022-10-11
|
||||
### Added
|
||||
- Added some taxonomies to be indexed by Search. [#26683]
|
||||
|
||||
## [1.38.4] - 2022-09-20
|
||||
### Added
|
||||
- Gutenberg Support: add additional theme_supports items to our synced allowlist. [#26239]
|
||||
|
||||
### Changed
|
||||
- Default Theme Support: Add support for new feature added in WP 6.1 [#26236]
|
||||
- Theme Supports: updated allowed values list to align with a Core change r54159-core [#26220]
|
||||
|
||||
## [1.38.3] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [1.38.2] - 2022-08-29
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
@ -711,6 +761,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Packages: Move sync to a classmapped package
|
||||
|
||||
[1.43.0]: https://github.com/Automattic/jetpack-sync/compare/v1.42.0...v1.43.0
|
||||
[1.42.0]: https://github.com/Automattic/jetpack-sync/compare/v1.41.0...v1.42.0
|
||||
[1.41.0]: https://github.com/Automattic/jetpack-sync/compare/v1.40.3...v1.41.0
|
||||
[1.40.3]: https://github.com/Automattic/jetpack-sync/compare/v1.40.2...v1.40.3
|
||||
[1.40.2]: https://github.com/Automattic/jetpack-sync/compare/v1.40.1...v1.40.2
|
||||
[1.40.1]: https://github.com/Automattic/jetpack-sync/compare/v1.40.0...v1.40.1
|
||||
[1.40.0]: https://github.com/Automattic/jetpack-sync/compare/v1.39.0...v1.40.0
|
||||
[1.39.0]: https://github.com/Automattic/jetpack-sync/compare/v1.38.4...v1.39.0
|
||||
[1.38.4]: https://github.com/Automattic/jetpack-sync/compare/v1.38.3...v1.38.4
|
||||
[1.38.3]: https://github.com/Automattic/jetpack-sync/compare/v1.38.2...v1.38.3
|
||||
[1.38.2]: https://github.com/Automattic/jetpack-sync/compare/v1.38.1...v1.38.2
|
||||
[1.38.1]: https://github.com/Automattic/jetpack-sync/compare/v1.38.0...v1.38.1
|
||||
[1.38.0]: https://github.com/Automattic/jetpack-sync/compare/v1.37.1...v1.38.0
|
||||
|
@ -4,12 +4,12 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-connection": "^1.44",
|
||||
"automattic/jetpack-connection": "^1.46",
|
||||
"automattic/jetpack-constants": "^1.6",
|
||||
"automattic/jetpack-identity-crisis": "^0.8",
|
||||
"automattic/jetpack-password-checker": "^0.2",
|
||||
"automattic/jetpack-roles": "^1.4",
|
||||
"automattic/jetpack-status": "^1.14"
|
||||
"automattic/jetpack-status": "^1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/jetpack-changelogger": "^3.2",
|
||||
@ -31,7 +31,8 @@
|
||||
"test-php": [
|
||||
"@composer phpunit"
|
||||
],
|
||||
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
||||
"post-install-cmd": "WorDBless\\Composer\\InstallDropin::copy",
|
||||
"post-update-cmd": "WorDBless\\Composer\\InstallDropin::copy"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
@ -46,7 +47,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-sync/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "1.38.x-dev"
|
||||
"dev-trunk": "1.43.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
@ -1042,4 +1042,28 @@ class Actions {
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Sync locks.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
* @since 1.43.0
|
||||
*/
|
||||
public static function reset_sync_locks() {
|
||||
// Next sync locks.
|
||||
delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_sync' );
|
||||
delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_full_sync' );
|
||||
delete_option( Sender::NEXT_SYNC_TIME_OPTION_NAME . '_full-sync-enqueue' );
|
||||
// Retry after locks.
|
||||
delete_option( self::RETRY_AFTER_PREFIX . '_sync' );
|
||||
delete_option( self::RETRY_AFTER_PREFIX . '_full_sync' );
|
||||
// Dedicated sync lock.
|
||||
\Jetpack_Options::delete_raw_option( Dedicated_Sender::DEDICATED_SYNC_REQUEST_LOCK_OPTION_NAME );
|
||||
// Queue locks.
|
||||
$sync_queue = new Queue( 'sync' );
|
||||
$sync_queue->unlock();
|
||||
$full_sync_queue = new Queue( 'full_sync' );
|
||||
$full_sync_queue->unlock();
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class Data_Settings {
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Constants',
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Full_Sync_Immediately', // enable Initial Sync on Site Connection.
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Options',
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Updates',
|
||||
),
|
||||
'jetpack_sync_callable_whitelist' => array(
|
||||
'site_url' => array( 'Automattic\\Jetpack\\Connection\\Urls', 'site_url' ),
|
||||
|
@ -57,6 +57,7 @@ class Defaults {
|
||||
'disabled_reblogs',
|
||||
'disallowed_keys',
|
||||
'enable_header_ad',
|
||||
'featured_image_email_enabled',
|
||||
'gmt_offset',
|
||||
'gravatar_disable_hovercards',
|
||||
'highlander_comment_form_prompt',
|
||||
@ -101,6 +102,7 @@ class Defaults {
|
||||
'jetpack_wga',
|
||||
'large_size_h',
|
||||
'large_size_w',
|
||||
'launch-status',
|
||||
'mailserver_login', // Not syncing contents, only the option name.
|
||||
'mailserver_pass', // Not syncing contents, only the option name.
|
||||
'mailserver_port',
|
||||
@ -173,6 +175,7 @@ class Defaults {
|
||||
'wpcom_publish_comments_with_markdown',
|
||||
'wpcom_publish_posts_with_markdown',
|
||||
'videopress_private_enabled_for_site',
|
||||
'wpcom_gifting_subscription',
|
||||
);
|
||||
|
||||
/**
|
||||
@ -407,6 +410,7 @@ class Defaults {
|
||||
'scheduled-action', // Action Scheduler - Job Queue for WordPress https://github.com/woocommerce/woocommerce/tree/e7762627c37ec1f7590e6cac4218ba0c6a20024d/includes/libraries/action-scheduler .
|
||||
'secupress_log_action',
|
||||
'sg_optimizer_jobs',
|
||||
'sl-insta-media',
|
||||
'snitch',
|
||||
'vip-legacy-redirect',
|
||||
'wp-rest-api-log', // https://wordpress.org/plugins/wp-rest-api-log/.
|
||||
@ -721,6 +725,7 @@ class Defaults {
|
||||
'_wpas_feature_enabled',
|
||||
'_wpas_is_tweetstorm',
|
||||
'_wpas_mess',
|
||||
'_wpas_options',
|
||||
'advanced_seo_description', // Jetpack_SEO_Posts::DESCRIPTION_META_KEY.
|
||||
'content_width',
|
||||
'custom_css_add',
|
||||
@ -796,16 +801,21 @@ class Defaults {
|
||||
*/
|
||||
public static $default_theme_support_whitelist = array(
|
||||
'align-wide',
|
||||
'appearance-tools', // In Gutenberg.
|
||||
'automatic-feed-links',
|
||||
'block-templates',
|
||||
'block-template-parts', // WP 6.1. Added via https://core.trac.wordpress.org/changeset/54176
|
||||
'custom-background',
|
||||
'custom-header',
|
||||
'custom-logo',
|
||||
'customize-selective-refresh-widgets',
|
||||
'dark-editor-style',
|
||||
'default-color-palette', // In Gutenberg.
|
||||
'default-gradient-presets', // In Gutenberg.
|
||||
'disable-custom-colors',
|
||||
'disable-custom-font-sizes',
|
||||
'disable-custom-gradients',
|
||||
'disable-layout-styles', // WP 6.1. Added via https://core.trac.wordpress.org/changeset/54159
|
||||
'editor-color-palette',
|
||||
'editor-font-sizes',
|
||||
'editor-gradient-presets',
|
||||
|
@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Sync;
|
||||
*/
|
||||
class Package_Version {
|
||||
|
||||
const PACKAGE_VERSION = '1.38.2';
|
||||
const PACKAGE_VERSION = '1.43.0';
|
||||
|
||||
const PACKAGE_SLUG = 'sync';
|
||||
|
||||
|
@ -317,6 +317,17 @@ class REST_Endpoints {
|
||||
)
|
||||
);
|
||||
|
||||
// Reset Sync locks.
|
||||
register_rest_route(
|
||||
'jetpack/v4',
|
||||
'/sync/locks',
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => __CLASS__ . '::reset_locks',
|
||||
'permission_callback' => __CLASS__ . '::verify_default_permissions',
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -768,6 +779,23 @@ class REST_Endpoints {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset Sync locks.
|
||||
*
|
||||
* @since 1.43.0
|
||||
*
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
public static function reset_locks() {
|
||||
Actions::reset_sync_locks();
|
||||
|
||||
return rest_ensure_response(
|
||||
array(
|
||||
'success' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that request has default permissions to perform sync actions.
|
||||
*
|
||||
|
@ -376,6 +376,10 @@ class Callables extends Module {
|
||||
);
|
||||
/** This filter is documented in src/wp-admin/includes/class-wp-plugins-list-table.php */
|
||||
$action_links = apply_filters( 'plugin_action_links', $action_links, $plugin_file, null, 'all' );
|
||||
// Verify $action_links is still an array.
|
||||
if ( ! is_array( $action_links ) ) {
|
||||
$action_links = array();
|
||||
}
|
||||
/** This filter is documented in src/wp-admin/includes/class-wp-plugins-list-table.php */
|
||||
$action_links = apply_filters( "plugin_action_links_{$plugin_file}", $action_links, $plugin_file, null, 'all' );
|
||||
// Verify $action_links is still an array to resolve warnings from filters not returning an array.
|
||||
|
@ -69,367 +69,368 @@ class Search extends Module {
|
||||
*/
|
||||
private static $postmeta_to_sync = array(
|
||||
// jetpack.
|
||||
'jetpack-search-meta0' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta1' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta2' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta3' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta4' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta5' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta6' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta7' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta8' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta9' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta0' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta1' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta2' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta3' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta4' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta5' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta6' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta7' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta8' => array( 'searchable_in_all_content' => true ),
|
||||
'jetpack-search-meta9' => array( 'searchable_in_all_content' => true ),
|
||||
|
||||
// woocommerce.
|
||||
'entity_types' => array(),
|
||||
'exclude_product_categories' => array(),
|
||||
'exclude_product_ids' => array(),
|
||||
'free_shipping' => array(),
|
||||
'id_field' => array(),
|
||||
'individual_use' => array(),
|
||||
'limit_usage_to_x_items' => array(),
|
||||
'maximum_amount' => array(),
|
||||
'minimum_amount' => array(),
|
||||
'post_id' => array(),
|
||||
'product_categories' => array( 'searchable_in_all_content' => true ),
|
||||
'product_ids' => array(),
|
||||
'total_sales' => array(
|
||||
'entity_types' => array(),
|
||||
'exclude_product_categories' => array(),
|
||||
'exclude_product_ids' => array(),
|
||||
'free_shipping' => array(),
|
||||
'id_field' => array(),
|
||||
'individual_use' => array(),
|
||||
'limit_usage_to_x_items' => array(),
|
||||
'maximum_amount' => array(),
|
||||
'minimum_amount' => array(),
|
||||
'post_id' => array(),
|
||||
'product_categories' => array( 'searchable_in_all_content' => true ),
|
||||
'product_ids' => array(),
|
||||
'total_sales' => array(
|
||||
'available' => false,
|
||||
'alternatives' => array(
|
||||
'wc.percent_of_sales',
|
||||
),
|
||||
),
|
||||
'usage_limit' => array(),
|
||||
'usage_limit_per_user' => array(),
|
||||
'_crosssell_ids' => array(),
|
||||
'_downloadable' => array(),
|
||||
'_featured' => array(),
|
||||
'_height' => array(),
|
||||
'_length' => array(),
|
||||
'_price' => array(
|
||||
'usage_limit' => array(),
|
||||
'usage_limit_per_user' => array(),
|
||||
'_crosssell_ids' => array(),
|
||||
'_downloadable' => array(),
|
||||
'_featured' => array(),
|
||||
'_height' => array(),
|
||||
'_length' => array(),
|
||||
'_price' => array(
|
||||
'alternatives' => array(
|
||||
'wc.price',
|
||||
'wc.min_price',
|
||||
'wc.max_price',
|
||||
),
|
||||
),
|
||||
'_prices_include_tax' => array(),
|
||||
'_product_attributes' => array(),
|
||||
'_product_version' => array(),
|
||||
'_regular_price' => array(
|
||||
'_prices_include_tax' => array(),
|
||||
'_product_attributes' => array(),
|
||||
'_product_version' => array(),
|
||||
'_regular_price' => array(
|
||||
'alternatives' => array(
|
||||
'wc.regular_price',
|
||||
),
|
||||
),
|
||||
'_sale_price' => array(
|
||||
'_sale_price' => array(
|
||||
'alternatives' => array(
|
||||
'wc.sale_price',
|
||||
),
|
||||
),
|
||||
'_sale_price_dates_from' => array(),
|
||||
'_sale_price_dates_to' => array(),
|
||||
'_sku' => array( 'searchable_in_all_content' => true ),
|
||||
'_stock_status' => array(),
|
||||
'_wc_average_rating' => array(
|
||||
'_sale_price_dates_from' => array(),
|
||||
'_sale_price_dates_to' => array(),
|
||||
'_sku' => array( 'searchable_in_all_content' => true ),
|
||||
'_stock_status' => array(),
|
||||
'_wc_average_rating' => array(
|
||||
'alternatives' => array(
|
||||
'wc.ave_rating_score',
|
||||
),
|
||||
),
|
||||
'_wc_rating_count' => array(
|
||||
'_wc_rating_count' => array(
|
||||
'alternatives' => array(
|
||||
'wc.rating', // wc.rating.count_1, wc.rating.count_2, ...
|
||||
),
|
||||
),
|
||||
'_wc_review_count' => array(),
|
||||
'_weight' => array(),
|
||||
'_width' => array(),
|
||||
'_wc_review_count' => array(),
|
||||
'_weight' => array(),
|
||||
'_width' => array(),
|
||||
|
||||
// co-authors plus.
|
||||
'cap-description' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-user_login' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-user_email' => array(),
|
||||
'cap-last_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-first_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-display_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-website' => array(),
|
||||
'cap-jabber' => array(),
|
||||
'cap-aim' => array(),
|
||||
'cap-twitter' => array(),
|
||||
'cap-facebook' => array(),
|
||||
'cap-google_plus' => array(),
|
||||
'cap-job_title' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-description' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-user_login' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-user_email' => array(),
|
||||
'cap-last_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-first_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-display_name' => array( 'searchable_in_all_content' => true ),
|
||||
'cap-website' => array(),
|
||||
'cap-jabber' => array(),
|
||||
'cap-aim' => array(),
|
||||
'cap-twitter' => array(),
|
||||
'cap-facebook' => array(),
|
||||
'cap-google_plus' => array(),
|
||||
'cap-job_title' => array( 'searchable_in_all_content' => true ),
|
||||
|
||||
// bbpress.
|
||||
'bbpl_like' => array(),
|
||||
'bbpress_discussion_comments_copied' => array(),
|
||||
'bbpress_discussion_tags_copied' => array(),
|
||||
'bbpress_discussion_topic_id' => array(),
|
||||
'bbpress_discussion_use_defaults' => array(),
|
||||
'bbpress_page_header_bg' => array(),
|
||||
'bbpress_title_bg' => array(),
|
||||
'use_bbpress_discussion_topic' => array(),
|
||||
'bbpl_like' => array(),
|
||||
'bbpress_discussion_comments_copied' => array(),
|
||||
'bbpress_discussion_tags_copied' => array(),
|
||||
'bbpress_discussion_topic_id' => array(),
|
||||
'bbpress_discussion_use_defaults' => array(),
|
||||
'bbpress_page_header_bg' => array(),
|
||||
'bbpress_title_bg' => array(),
|
||||
'use_bbpress_discussion_topic' => array(),
|
||||
|
||||
// wpml.
|
||||
'tm_meta_wpml' => array(),
|
||||
'wpml_language' => array(),
|
||||
'wpml_media_lang' => array(),
|
||||
'wpml_media_processed' => array(),
|
||||
'tm_meta_wpml' => array(),
|
||||
'wpml_language' => array(),
|
||||
'wpml_media_lang' => array(),
|
||||
'wpml_media_processed' => array(),
|
||||
|
||||
// blogger import.
|
||||
'blogger_author' => array( 'searchable_in_all_content' => true ),
|
||||
'blogger_blog' => array( 'searchable_in_all_content' => true ),
|
||||
'blogger_permalink' => array( 'searchable_in_all_content' => true ),
|
||||
'blogger_author' => array( 'searchable_in_all_content' => true ),
|
||||
'blogger_blog' => array( 'searchable_in_all_content' => true ),
|
||||
'blogger_permalink' => array( 'searchable_in_all_content' => true ),
|
||||
|
||||
// geo.
|
||||
'geo_address' => array( 'searchable_in_all_content' => true ),
|
||||
'geo_latitude' => array(),
|
||||
'geo_longitude' => array(),
|
||||
'geo_public' => array(),
|
||||
'geolocated' => array(),
|
||||
'geolocation_city' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_country_long' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_country_short' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_formatted_address' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_lat' => array(),
|
||||
'geolocation_long' => array(),
|
||||
'geolocation_postcode' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_state_long' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_state_short' => array( 'searchable_in_all_content' => true ),
|
||||
'geo_address' => array( 'searchable_in_all_content' => true ),
|
||||
'geo_latitude' => array(),
|
||||
'geo_longitude' => array(),
|
||||
'geo_public' => array(),
|
||||
'geolocated' => array(),
|
||||
'geolocation_city' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_country_long' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_country_short' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_formatted_address' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_lat' => array(),
|
||||
'geolocation_long' => array(),
|
||||
'geolocation_postcode' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_state_long' => array( 'searchable_in_all_content' => true ),
|
||||
'geolocation_state_short' => array( 'searchable_in_all_content' => true ),
|
||||
|
||||
// wp-ultimate-recipe.
|
||||
'recipe_alternate_image' => array(),
|
||||
'recipe_cook_time' => array(),
|
||||
'recipe_cook_time_text' => array(),
|
||||
'recipe_description' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_ingredients' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_instructions' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_notes' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_nutritional' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_passive_time' => array(),
|
||||
'recipe_passive_time_text' => array(),
|
||||
'recipe_prep_time' => array(),
|
||||
'recipe_prep_time_text' => array(),
|
||||
'recipe_rating' => array(),
|
||||
'recipe_servings' => array(),
|
||||
'recipe_servings_normalized' => array(),
|
||||
'recipe_servings_type' => array(),
|
||||
'recipe_terms' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_terms_with_parents' => array(),
|
||||
'recipe_title' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_user_ratings' => array(),
|
||||
'recipe_user_ratings_rating' => array(),
|
||||
'recipe_alternate_image' => array(),
|
||||
'recipe_cook_time' => array(),
|
||||
'recipe_cook_time_text' => array(),
|
||||
'recipe_description' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_ingredients' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_instructions' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_notes' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_nutritional' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_passive_time' => array(),
|
||||
'recipe_passive_time_text' => array(),
|
||||
'recipe_prep_time' => array(),
|
||||
'recipe_prep_time_text' => array(),
|
||||
'recipe_rating' => array(),
|
||||
'recipe_servings' => array(),
|
||||
'recipe_servings_normalized' => array(),
|
||||
'recipe_servings_type' => array(),
|
||||
'recipe_terms' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_terms_with_parents' => array(),
|
||||
'recipe_title' => array( 'searchable_in_all_content' => true ),
|
||||
'recipe_user_ratings' => array(),
|
||||
'recipe_user_ratings_rating' => array(),
|
||||
|
||||
// generic fields.
|
||||
// from advanced-custom-fields and metabox.io .
|
||||
'Link' => array(),
|
||||
'Location' => array(),
|
||||
'Title' => array( 'searchable_in_all_content' => true ),
|
||||
'ad_code' => array(),
|
||||
'address' => array(),
|
||||
'admin_mail' => array(),
|
||||
'admin_only' => array(),
|
||||
'advertisers' => array( 'searchable_in_all_content' => true ),
|
||||
'age' => array(),
|
||||
'aliases' => array(),
|
||||
'alternate_title' => array(),
|
||||
'amazon' => array(),
|
||||
'answer' => array( 'searchable_in_all_content' => true ),
|
||||
'area' => array(),
|
||||
'attention' => array(),
|
||||
'attr' => array(),
|
||||
'author' => array( 'searchable_in_all_content' => true ),
|
||||
'author_name' => array( 'searchable_in_all_content' => true ),
|
||||
'blog' => array(),
|
||||
'blog_id' => array(),
|
||||
'call_to_action' => array(),
|
||||
'campaign_preview' => array(),
|
||||
'canonical_url' => array(),
|
||||
'catch_text' => array(),
|
||||
'category' => array( 'searchable_in_all_content' => true ),
|
||||
'classificacao' => array(),
|
||||
'classification' => array(),
|
||||
'code' => array(),
|
||||
'codigo' => array(),
|
||||
'company' => array( 'searchable_in_all_content' => true ),
|
||||
'company_website' => array(),
|
||||
'config' => array(),
|
||||
'construction' => array(),
|
||||
'container_ids' => array(),
|
||||
'content' => array( 'searchable_in_all_content' => true ),
|
||||
'content_body-full_content' => array( 'searchable_in_all_content' => true ),
|
||||
'copyright' => array(),
|
||||
'custom_page_title' => array( 'searchable_in_all_content' => true ),
|
||||
'custom_permalink' => array(),
|
||||
'customize' => array(),
|
||||
'data' => array(),
|
||||
'date' => array(),
|
||||
'day' => array(),
|
||||
'descripcion' => array( 'searchable_in_all_content' => true ),
|
||||
'description' => array( 'searchable_in_all_content' => true ),
|
||||
'display_settings' => array(),
|
||||
'display_type' => array(),
|
||||
'duration' => array(),
|
||||
'embed' => array(),
|
||||
'entity_ids' => array(),
|
||||
'entity_types' => array(),
|
||||
'event_subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'excluded_container_ids' => array(),
|
||||
'exclusions' => array(),
|
||||
'experience' => array(),
|
||||
'external_url' => array(),
|
||||
'featured' => array(),
|
||||
'featured_image' => array(),
|
||||
'featured_post' => array(),
|
||||
'featured_story' => array(),
|
||||
'fee' => array(),
|
||||
'filter' => array(),
|
||||
'follow' => array(),
|
||||
'footer_text' => array(),
|
||||
'from_header' => array(),
|
||||
'fullscreen_view' => array(),
|
||||
'gallery' => array(),
|
||||
'genre' => array( 'searchable_in_all_content' => true ),
|
||||
'guests' => array( 'searchable_in_all_content' => true ),
|
||||
'has_variations' => array(),
|
||||
'hashtag' => array(),
|
||||
'header_image' => array(),
|
||||
'hidden_from_ui' => array(),
|
||||
'hide_on_screen' => array(),
|
||||
'homepage_order' => array(),
|
||||
'hours' => array(),
|
||||
'i18n' => array(),
|
||||
'id' => array(),
|
||||
'image' => array(),
|
||||
'image_size' => array(),
|
||||
'image_source' => array(),
|
||||
'index' => array(),
|
||||
'intro_text' => array( 'searchable_in_all_content' => true ),
|
||||
'job_mention' => array( 'searchable_in_all_content' => true ),
|
||||
'keywords' => array( 'searchable_in_all_content' => true ),
|
||||
'latest_news' => array(),
|
||||
'layout' => array(),
|
||||
'link' => array(),
|
||||
'link_dump' => array( 'searchable_in_all_content' => true ),
|
||||
'link_url' => array(),
|
||||
'location' => array(),
|
||||
'logo' => array(),
|
||||
'main_title' => array( 'searchable_in_all_content' => true ),
|
||||
'maximum_entity_count' => array(),
|
||||
'media' => array(),
|
||||
'mentions' => array(),
|
||||
'messages' => array(),
|
||||
'meta_description' => array( 'searchable_in_all_content' => true ),
|
||||
'meta_id' => array(),
|
||||
'meta_index' => array(),
|
||||
'meta_key' => array(),
|
||||
'meta_value' => array(),
|
||||
'modal-dialog-id' => array(),
|
||||
'name' => array( 'searchable_in_all_content' => true ),
|
||||
'nombre' => array( 'searchable_in_all_content' => true ),
|
||||
'notes' => array( 'searchable_in_all_content' => true ),
|
||||
'options' => array(),
|
||||
'order_by' => array(),
|
||||
'order_direction' => array(),
|
||||
'original_cats' => array(),
|
||||
'original_headers' => array(),
|
||||
'original_link' => array(),
|
||||
'original_message' => array(),
|
||||
'original_subject' => array(),
|
||||
'original_title' => array(),
|
||||
'original_to' => array(),
|
||||
'other_setting' => array(),
|
||||
'page_canonical' => array(),
|
||||
'page_layout' => array(),
|
||||
'page_sidebar' => array(),
|
||||
'page_tags' => array(),
|
||||
'panels_data' => array(),
|
||||
'parking' => array(),
|
||||
'pdf_upload' => array(),
|
||||
'photo' => array(),
|
||||
'play_time' => array(),
|
||||
'position' => array(),
|
||||
'post-rating' => array(),
|
||||
'post_background' => array(),
|
||||
'post_color' => array(),
|
||||
'post_sidebar' => array(),
|
||||
'post_subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'price' => array(),
|
||||
'publication' => array(),
|
||||
'rating' => array(),
|
||||
'ratings_average' => array(),
|
||||
'ratings_score' => array(),
|
||||
'ratings_users' => array(),
|
||||
'relation' => array(),
|
||||
'reply_to_header' => array(),
|
||||
'required' => array(),
|
||||
'returns' => array(),
|
||||
'review_post' => array(),
|
||||
'rule' => array(),
|
||||
'section' => array( 'searchable_in_all_content' => true ),
|
||||
'session_transcript' => array(),
|
||||
'settings' => array(),
|
||||
'sex' => array(),
|
||||
'shares_count' => array(),
|
||||
'show_description' => array( 'searchable_in_all_content' => true ),
|
||||
'show_page_title' => array(),
|
||||
'side' => array(),
|
||||
'sidebar' => array(),
|
||||
'site' => array(),
|
||||
'situation' => array(),
|
||||
'slide_template' => array(),
|
||||
'slug' => array(),
|
||||
'sortorder' => array(),
|
||||
'source' => array(),
|
||||
'start_date' => array(),
|
||||
'status' => array(),
|
||||
'styles' => array(),
|
||||
'subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'subtitulo' => array(),
|
||||
'success' => array(),
|
||||
'summary' => array( 'searchable_in_all_content' => true ),
|
||||
'synopsis' => array( 'searchable_in_all_content' => true ),
|
||||
'tel' => array(),
|
||||
'tema' => array(),
|
||||
'testimonial' => array(),
|
||||
'testimonial_author' => array(),
|
||||
'text_already_subscribed' => array(),
|
||||
'text_error' => array(),
|
||||
'text_invalid_email' => array(),
|
||||
'text_not_subscribed' => array(),
|
||||
'text_required_field_missing' => array(),
|
||||
'text_subscribed' => array(),
|
||||
'text_unsubscribed' => array(),
|
||||
'thumbnail' => array(),
|
||||
'time' => array(),
|
||||
'time_jump_list' => array( 'searchable_in_all_content' => true ),
|
||||
'title' => array( 'searchable_in_all_content' => true ),
|
||||
'title_view' => array(),
|
||||
'titre' => array( 'searchable_in_all_content' => true ),
|
||||
'titulo' => array( 'searchable_in_all_content' => true ),
|
||||
'to_header' => array(),
|
||||
'toc' => array(),
|
||||
'transcript' => array( 'searchable_in_all_content' => true ),
|
||||
'transport_uri' => array(),
|
||||
'type' => array(),
|
||||
'url' => array(),
|
||||
'validation' => array(),
|
||||
'value' => array(),
|
||||
'values' => array(),
|
||||
'variation' => array(),
|
||||
'video' => array(),
|
||||
'video_type' => array(),
|
||||
'video_url' => array(),
|
||||
'videopress_guid' => array(),
|
||||
'website' => array(),
|
||||
'weight' => array(),
|
||||
'year' => array(),
|
||||
'Link' => array(),
|
||||
'Location' => array(),
|
||||
'Title' => array( 'searchable_in_all_content' => true ),
|
||||
'ad_code' => array(),
|
||||
'address' => array(),
|
||||
'admin_mail' => array(),
|
||||
'admin_only' => array(),
|
||||
'advertisers' => array( 'searchable_in_all_content' => true ),
|
||||
'age' => array(),
|
||||
'aliases' => array(),
|
||||
'alternate_title' => array(),
|
||||
'amazon' => array(),
|
||||
'answer' => array( 'searchable_in_all_content' => true ),
|
||||
'area' => array(),
|
||||
'attention' => array(),
|
||||
'attr' => array(),
|
||||
'author' => array( 'searchable_in_all_content' => true ),
|
||||
'author_name' => array( 'searchable_in_all_content' => true ),
|
||||
'blog' => array(),
|
||||
'blog_id' => array(),
|
||||
'call_to_action' => array(),
|
||||
'campaign_preview' => array(),
|
||||
'canonical_url' => array(),
|
||||
'catch_text' => array(),
|
||||
'category' => array( 'searchable_in_all_content' => true ),
|
||||
'classificacao' => array(),
|
||||
'classification' => array(),
|
||||
'code' => array(),
|
||||
'codigo' => array(),
|
||||
'company' => array( 'searchable_in_all_content' => true ),
|
||||
'company_website' => array(),
|
||||
'config' => array(),
|
||||
'construction' => array(),
|
||||
'container_ids' => array(),
|
||||
'content' => array( 'searchable_in_all_content' => true ),
|
||||
'content_body-full_content' => array( 'searchable_in_all_content' => true ),
|
||||
'copyright' => array(),
|
||||
'custom_page_title' => array( 'searchable_in_all_content' => true ),
|
||||
'custom_permalink' => array(),
|
||||
'customize' => array(),
|
||||
'data' => array(),
|
||||
'date' => array(),
|
||||
'day' => array(),
|
||||
'descripcion' => array( 'searchable_in_all_content' => true ),
|
||||
'description' => array( 'searchable_in_all_content' => true ),
|
||||
'display_settings' => array(),
|
||||
'display_type' => array(),
|
||||
'duration' => array(),
|
||||
'embed' => array(),
|
||||
'entity_ids' => array(),
|
||||
'entity_types' => array(),
|
||||
'event_subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'excluded_container_ids' => array(),
|
||||
'exclusions' => array(),
|
||||
'experience' => array(),
|
||||
'external_url' => array(),
|
||||
'featured' => array(),
|
||||
'featured_image' => array(),
|
||||
'featured_post' => array(),
|
||||
'featured_story' => array(),
|
||||
'fee' => array(),
|
||||
'filter' => array(),
|
||||
'follow' => array(),
|
||||
'footer_text' => array(),
|
||||
'from_header' => array(),
|
||||
'fullscreen_view' => array(),
|
||||
'gallery' => array(),
|
||||
'genre' => array( 'searchable_in_all_content' => true ),
|
||||
'guests' => array( 'searchable_in_all_content' => true ),
|
||||
'has_variations' => array(),
|
||||
'hashtag' => array(),
|
||||
'header_image' => array(),
|
||||
'hidden_from_ui' => array(),
|
||||
'hide_on_screen' => array(),
|
||||
'homepage_order' => array(),
|
||||
'hours' => array(),
|
||||
'i18n' => array(),
|
||||
'id' => array(),
|
||||
'image' => array(),
|
||||
'image_size' => array(),
|
||||
'image_source' => array(),
|
||||
'index' => array(),
|
||||
'intro_text' => array( 'searchable_in_all_content' => true ),
|
||||
'job_mention' => array( 'searchable_in_all_content' => true ),
|
||||
'keywords' => array( 'searchable_in_all_content' => true ),
|
||||
'latest_news' => array(),
|
||||
'layout' => array(),
|
||||
'link' => array(),
|
||||
'link_dump' => array( 'searchable_in_all_content' => true ),
|
||||
'link_url' => array(),
|
||||
'location' => array(),
|
||||
'logo' => array(),
|
||||
'main_title' => array( 'searchable_in_all_content' => true ),
|
||||
'maximum_entity_count' => array(),
|
||||
'media' => array(),
|
||||
'mentions' => array(),
|
||||
'messages' => array(),
|
||||
'meta_description' => array( 'searchable_in_all_content' => true ),
|
||||
'meta_id' => array(),
|
||||
'meta_index' => array(),
|
||||
'meta_key' => array(),
|
||||
'meta_value' => array(),
|
||||
'modal-dialog-id' => array(),
|
||||
'name' => array( 'searchable_in_all_content' => true ),
|
||||
'nombre' => array( 'searchable_in_all_content' => true ),
|
||||
'notes' => array( 'searchable_in_all_content' => true ),
|
||||
'options' => array(),
|
||||
'order_by' => array(),
|
||||
'order_direction' => array(),
|
||||
'original_cats' => array(),
|
||||
'original_headers' => array(),
|
||||
'original_link' => array(),
|
||||
'original_message' => array(),
|
||||
'original_subject' => array(),
|
||||
'original_title' => array(),
|
||||
'original_to' => array(),
|
||||
'other_setting' => array(),
|
||||
'page_canonical' => array(),
|
||||
'page_layout' => array(),
|
||||
'page_sidebar' => array(),
|
||||
'page_tags' => array(),
|
||||
'panels_data' => array(),
|
||||
'parking' => array(),
|
||||
'pdf_upload' => array(),
|
||||
'photo' => array(),
|
||||
'play_time' => array(),
|
||||
'position' => array(),
|
||||
'post-rating' => array(),
|
||||
'post_background' => array(),
|
||||
'post_color' => array(),
|
||||
'post_sidebar' => array(),
|
||||
'post_subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'price' => array(),
|
||||
'publication' => array(),
|
||||
'rating' => array(),
|
||||
'ratings_average' => array(),
|
||||
'ratings_score' => array(),
|
||||
'ratings_users' => array(),
|
||||
'relation' => array(),
|
||||
'reply_to_header' => array(),
|
||||
'required' => array(),
|
||||
'returns' => array(),
|
||||
'review_post' => array(),
|
||||
'rule' => array(),
|
||||
'section' => array( 'searchable_in_all_content' => true ),
|
||||
'session_transcript' => array(),
|
||||
'settings' => array(),
|
||||
'sex' => array(),
|
||||
'shares_count' => array(),
|
||||
'show_description' => array( 'searchable_in_all_content' => true ),
|
||||
'show_page_title' => array(),
|
||||
'side' => array(),
|
||||
'sidebar' => array(),
|
||||
'site' => array(),
|
||||
'situation' => array(),
|
||||
'slide_template' => array(),
|
||||
'slug' => array(),
|
||||
'sortorder' => array(),
|
||||
'source' => array(),
|
||||
'start_date' => array(),
|
||||
'status' => array(),
|
||||
'styles' => array(),
|
||||
'subtitle' => array( 'searchable_in_all_content' => true ),
|
||||
'subtitulo' => array(),
|
||||
'success' => array(),
|
||||
'summary' => array( 'searchable_in_all_content' => true ),
|
||||
'synopsis' => array( 'searchable_in_all_content' => true ),
|
||||
'tel' => array(),
|
||||
'tema' => array(),
|
||||
'testimonial' => array(),
|
||||
'testimonial_author' => array(),
|
||||
'text_already_subscribed' => array(),
|
||||
'text_error' => array(),
|
||||
'text_invalid_email' => array(),
|
||||
'text_not_subscribed' => array(),
|
||||
'text_required_field_missing' => array(),
|
||||
'text_subscribed' => array(),
|
||||
'text_unsubscribed' => array(),
|
||||
'thumbnail' => array(),
|
||||
'time' => array(),
|
||||
'time_jump_list' => array( 'searchable_in_all_content' => true ),
|
||||
'title' => array( 'searchable_in_all_content' => true ),
|
||||
'title_view' => array(),
|
||||
'titre' => array( 'searchable_in_all_content' => true ),
|
||||
'titulo' => array( 'searchable_in_all_content' => true ),
|
||||
'to_header' => array(),
|
||||
'toc' => array(),
|
||||
'transcript' => array( 'searchable_in_all_content' => true ),
|
||||
'transport_uri' => array(),
|
||||
'type' => array(),
|
||||
'url' => array(),
|
||||
'validation' => array(),
|
||||
'value' => array(),
|
||||
'values' => array(),
|
||||
'variation' => array(),
|
||||
'video' => array(),
|
||||
'video_type' => array(),
|
||||
'video_url' => array(),
|
||||
'videopress_guid' => array(),
|
||||
'website' => array(),
|
||||
'weight' => array(),
|
||||
'year' => array(),
|
||||
|
||||
// wp.com martketplace search - @see https://wp.me/pdh6GB-Ax#comment-2104
|
||||
'_app_icon' => array(),
|
||||
'_featured_product_video' => array(),
|
||||
'wpcom_marketplace_org_slug' => array(),
|
||||
'_wc_general_product_dependency_theme' => array(),
|
||||
'_wc_general_product_dependency_plugin' => array(),
|
||||
'_app_icon' => array(),
|
||||
'_featured_product_video' => array(),
|
||||
'wpcom_marketplace_org_slug' => array(),
|
||||
'_wc_general_product_dependency_theme' => array(),
|
||||
'_wc_general_product_dependency_plugin' => array(),
|
||||
'wpcom_marketplace_product_extra_fields' => array(),
|
||||
|
||||
); // end indexed post meta.
|
||||
|
||||
@ -1014,6 +1015,7 @@ class Search extends Module {
|
||||
'product-brand',
|
||||
'product_brand',
|
||||
'product-category',
|
||||
'product_cat',
|
||||
'product_delivery_time',
|
||||
'product_delivery_times',
|
||||
'product_price_label',
|
||||
@ -1083,6 +1085,7 @@ class Search extends Module {
|
||||
'attachment_category',
|
||||
'attachment_tag',
|
||||
'atum_location',
|
||||
'audience_type',
|
||||
'avhec_catgroup',
|
||||
'bartype',
|
||||
'baths',
|
||||
@ -1092,6 +1095,8 @@ class Search extends Module {
|
||||
'booked_custom_calendars',
|
||||
'brand',
|
||||
'brands',
|
||||
'business',
|
||||
'business_cat',
|
||||
'business_category',
|
||||
'bwg_tag',
|
||||
'byline',
|
||||
@ -1154,6 +1159,7 @@ class Search extends Module {
|
||||
'dlm_download_tag',
|
||||
'doc_tag',
|
||||
'document-category',
|
||||
'document-type',
|
||||
'download_artist',
|
||||
'download_category',
|
||||
'download_tag',
|
||||
@ -1241,6 +1247,7 @@ class Search extends Module {
|
||||
'incsub_wiki_category',
|
||||
'industry',
|
||||
'ingredient',
|
||||
'insight-type',
|
||||
'issue',
|
||||
'issuem_issue',
|
||||
'issuem_issue_tags',
|
||||
@ -1302,6 +1309,8 @@ class Search extends Module {
|
||||
'muviyear',
|
||||
'news-category',
|
||||
'news-tag',
|
||||
'news-type',
|
||||
'news_type_cat',
|
||||
'news_category',
|
||||
'nova_menu',
|
||||
'nova_menu_item_label',
|
||||
@ -1318,6 +1327,7 @@ class Search extends Module {
|
||||
'pdf_lv_tag',
|
||||
'pec_events_category',
|
||||
'people',
|
||||
'people-department',
|
||||
'people-expertise',
|
||||
'people-location',
|
||||
'perfect_quotes_category',
|
||||
@ -1350,6 +1360,7 @@ class Search extends Module {
|
||||
'portcat',
|
||||
'portfolio-category',
|
||||
'portfolio-gallery',
|
||||
'portfolio-status',
|
||||
'portfolio-skills',
|
||||
'portfolio-tag',
|
||||
'portfolio-tags',
|
||||
@ -1378,6 +1389,8 @@ class Search extends Module {
|
||||
'pricingcats',
|
||||
'print_section',
|
||||
'print_status',
|
||||
'product_asset_class',
|
||||
'product_name',
|
||||
'programs',
|
||||
'project-attributes',
|
||||
'project-cat',
|
||||
@ -1407,6 +1420,7 @@ class Search extends Module {
|
||||
'pwb-brand',
|
||||
'qmn_log_type',
|
||||
'qualification',
|
||||
'qualifications',
|
||||
'quality',
|
||||
'question-category',
|
||||
'question-tag',
|
||||
@ -1636,6 +1650,7 @@ class Search extends Module {
|
||||
'wcs-room',
|
||||
'wcs-type',
|
||||
'wdca_ad_categories',
|
||||
'webinar_type_cat',
|
||||
'where',
|
||||
'who',
|
||||
'wiki-category',
|
||||
|
@ -0,0 +1,14 @@
|
||||
# Changelog
|
||||
|
||||
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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.1.0 - 2022-11-01
|
||||
### Added
|
||||
- Adding the initial empty package
|
||||
- Duplicate helper script code to a dedicated package
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies.
|
@ -0,0 +1,357 @@
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
@ -0,0 +1,38 @@
|
||||
# Security Policy
|
||||
|
||||
Full details of the Automattic Security Policy can be found on [automattic.com](https://automattic.com/security/).
|
||||
|
||||
## Supported Versions
|
||||
|
||||
Generally, only the latest version of Jetpack has continued support. If a critical vulnerability is found in the current version of Jetpack, we may opt to backport any patches to previous versions.
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
[Jetpack](https://jetpack.com/) is an open-source plugin for WordPress. Our HackerOne program covers the plugin software, as well as a variety of related projects and infrastructure.
|
||||
|
||||
**For responsible disclosure of security issues and to be eligible for our bug bounty program, please submit your report via the [HackerOne](https://hackerone.com/automattic) portal.**
|
||||
|
||||
Our most critical targets are:
|
||||
|
||||
* Jetpack and the Jetpack composer packages (all within this repo)
|
||||
* Jetpack.com -- the primary marketing site.
|
||||
* cloud.jetpack.com -- a management site.
|
||||
* wordpress.com -- the shared management site for both Jetpack and WordPress.com sites.
|
||||
|
||||
For more targets, see the `In Scope` section on [HackerOne](https://hackerone.com/automattic).
|
||||
|
||||
_Please note that the **WordPress software is a separate entity** from Automattic. Please report vulnerabilities for WordPress through [the WordPress Foundation's HackerOne page](https://hackerone.com/wordpress)._
|
||||
|
||||
## Guidelines
|
||||
|
||||
We're committed to working with security researchers to resolve the vulnerabilities they discover. You can help us by following these guidelines:
|
||||
|
||||
* Follow [HackerOne's disclosure guidelines](https://www.hackerone.com/disclosure-guidelines).
|
||||
* Pen-testing Production:
|
||||
* Please **setup a local environment** instead whenever possible. Most of our code is open source (see above).
|
||||
* If that's not possible, **limit any data access/modification** to the bare minimum necessary to reproduce a PoC.
|
||||
* **_Don't_ automate form submissions!** That's very annoying for us, because it adds extra work for the volunteers who manage those systems, and reduces the signal/noise ratio in our communication channels.
|
||||
* To be eligible for a bounty, all of these guidelines must be followed.
|
||||
* Be Patient - Give us a reasonable time to correct the issue before you disclose the vulnerability.
|
||||
|
||||
We also expect you to comply with all applicable laws. You're responsible to pay any taxes associated with your bounties.
|
@ -0,0 +1,32 @@
|
||||
<?php
|
||||
/**
|
||||
* Action Hooks for Jetpack Transport Helper module.
|
||||
*
|
||||
* @package automattic/jetpack-transport-helper
|
||||
*/
|
||||
|
||||
// If WordPress's plugin API is available already, use it. If not,
|
||||
// drop data into `$wp_filter` for `WP_Hook::build_preinitialized_hooks()`.
|
||||
if ( function_exists( 'add_filter' ) ) {
|
||||
$add_filter = 'add_filter';
|
||||
$add_action = 'add_action';
|
||||
} else {
|
||||
$add_filter = function ( $name, $cb, $priority = 10, $accepted_args = 1 ) {
|
||||
global $wp_filter;
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$wp_filter[ $name ][ $priority ][] = array(
|
||||
'accepted_args' => $accepted_args,
|
||||
'function' => $cb,
|
||||
);
|
||||
};
|
||||
$add_action = $add_filter;
|
||||
}
|
||||
|
||||
// Clean up expired Jetpack Helper Scripts from a scheduled event.
|
||||
$add_action( 'jetpack_cleanup_helper_scripts', array( 'Automattic\\Jetpack\\Transport_Helper\\Helper_Script_Manager', 'cleanup_expired_helper_scripts' ) );
|
||||
|
||||
// Register REST routes.
|
||||
$add_action( 'rest_api_init', array( 'Automattic\\Jetpack\\Transport_Helper\\REST_Controller', 'register_rest_routes' ) );
|
||||
|
||||
// Set up package version hook.
|
||||
$add_filter( 'jetpack_package_versions', 'Automattic\\Jetpack\\Transport_Helper\\Package_Version::send_package_version_to_tracker' );
|
@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "automattic/jetpack-transport-helper",
|
||||
"description": "Package to help transport server communication",
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-connection": "^1.46"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "1.0.3",
|
||||
"automattic/jetpack-changelogger": "^3.2",
|
||||
"automattic/wordbless": "dev-master"
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"actions.php"
|
||||
],
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"phpunit": [
|
||||
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
||||
],
|
||||
"test-coverage": [
|
||||
"php -dpcov.directory=. ./vendor/bin/phpunit --coverage-clover \"$COVERAGE_DIR/clover.xml\""
|
||||
],
|
||||
"test-php": [
|
||||
"@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",
|
||||
"prefer-stable": true,
|
||||
"extra": {
|
||||
"mirror-repo": "Automattic/jetpack-transport-helper",
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-package-version.php"
|
||||
},
|
||||
"changelogger": {
|
||||
"link-template": "https://github.com/Automattic/jetpack-transport-helper/compare/v${old}...v${new}"
|
||||
},
|
||||
"autotagger": true,
|
||||
"branch-alias": {
|
||||
"dev-trunk": "0.1.x-dev"
|
||||
},
|
||||
"textdomain": "jetpack-transport-helper"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"roots/wordpress-core-installer": true
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
/**
|
||||
* The Jetpack Helper Script Manager class.
|
||||
*
|
||||
* @package automattic/jetpack-transport-helper
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Transport_Helper;
|
||||
|
||||
/**
|
||||
* Helper_Script_Manager manages installation, deletion and cleanup of Helper Scripts
|
||||
*/
|
||||
class Helper_Script_Manager {
|
||||
|
||||
const TEMP_DIRECTORY = 'jetpack-temp';
|
||||
const HELPER_HEADER = "<?php /* Jetpack Backup Helper Script */\n";
|
||||
const EXPIRY_TIME = 8 * 3600; // 8 hours
|
||||
const MAX_FILESIZE = 1024 * 1024; // 1 MiB
|
||||
|
||||
const README_LINES = array(
|
||||
'These files have been put on your server by Jetpack. They are cleaned up automatically when we no longer need them.',
|
||||
'If you no longer have Jetpack connected to your site, you can delete them manually.',
|
||||
'If you have questions or need assistance, please contact Jetpack Support at https://jetpack.com/support/',
|
||||
'If you like to build amazing things with WordPress, you should visit automattic.com/jobs and apply to join the fun – mention this file when you apply!;',
|
||||
);
|
||||
|
||||
const INDEX_FILE = '<?php // Silence is golden';
|
||||
|
||||
/**
|
||||
* Installs a Helper Script, and returns its filesystem path and access url.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param string $script_body Helper Script file contents.
|
||||
* @return array|WP_Error Either an array containing the path and url of the helper script, or an error.
|
||||
*/
|
||||
public static function install_helper_script( $script_body ) {
|
||||
// Check that the script body contains the correct header.
|
||||
if ( strncmp( $script_body, self::HELPER_HEADER, strlen( self::HELPER_HEADER ) ) !== 0 ) {
|
||||
return new \WP_Error( 'invalid_helper', 'Invalid Helper Script header' );
|
||||
}
|
||||
|
||||
// Refuse to install a Helper Script that is too large.
|
||||
if ( strlen( $script_body ) > self::MAX_FILESIZE ) {
|
||||
return new \WP_Error( 'invalid_helper', 'Invalid Helper Script size' );
|
||||
}
|
||||
|
||||
// Replace '[wp_path]' in the Helper Script with the WordPress installation location. Allows the Helper Script to find WordPress.
|
||||
$script_body = str_replace( '[wp_path]', addslashes( ABSPATH ), $script_body );
|
||||
|
||||
// Create a jetpack-temp directory for the Helper Script.
|
||||
$temp_directory = self::create_temp_directory();
|
||||
if ( \is_wp_error( $temp_directory ) ) {
|
||||
return $temp_directory;
|
||||
}
|
||||
|
||||
// Generate a random filename, avoid clashes.
|
||||
$max_attempts = 5;
|
||||
for ( $attempt = 0; $attempt < $max_attempts; $attempt++ ) {
|
||||
$file_key = wp_generate_password( 10, false );
|
||||
$file_name = 'jp-helper-' . $file_key . '.php';
|
||||
$file_path = trailingslashit( $temp_directory['path'] ) . $file_name;
|
||||
|
||||
if ( ! file_exists( $file_path ) ) {
|
||||
// Attempt to write helper script.
|
||||
if ( ! self::put_contents( $file_path, $script_body ) ) {
|
||||
if ( file_exists( $file_path ) ) {
|
||||
unlink( $file_path );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Always schedule a cleanup run shortly after EXPIRY_TIME.
|
||||
\wp_schedule_single_event( time() + self::EXPIRY_TIME + 60, 'jetpack_cleanup_helper_scripts' );
|
||||
|
||||
// Success! Figure out the URL and return the path and URL.
|
||||
return array(
|
||||
'path' => $file_path,
|
||||
'url' => trailingslashit( $temp_directory['url'] ) . $file_name,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new \WP_Error( 'install_faied', 'Failed to install Helper Script' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a path, verify it looks like a helper script and then delete it if so.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param string $path Path to Helper Script to delete.
|
||||
* @return boolean True if the file is deleted (or does not exist).
|
||||
*/
|
||||
public static function delete_helper_script( $path ) {
|
||||
if ( ! file_exists( $path ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check this file looks like a JPR helper script.
|
||||
if ( ! self::verify_file_header( $path, self::HELPER_HEADER ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return unlink( $path );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for Helper Scripts that are suspiciously old, and clean them out.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function cleanup_expired_helper_scripts() {
|
||||
self::cleanup_helper_scripts( time() - self::EXPIRY_TIME );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for and delete all Helper Scripts. Used during uninstallation.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function delete_all_helper_scripts() {
|
||||
self::cleanup_helper_scripts( null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for and delete Helper Scripts. If an $expiry_time is specified, only delete Helper Scripts
|
||||
* with an mtime older than $expiry_time. Otherwise, delete them all.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param int|null $expiry_time If specified, only delete scripts older than $expiry_time.
|
||||
*/
|
||||
public static function cleanup_helper_scripts( $expiry_time = null ) {
|
||||
foreach ( self::get_install_locations() as $directory => $url ) {
|
||||
$temp_dir = trailingslashit( $directory ) . self::TEMP_DIRECTORY;
|
||||
|
||||
if ( is_dir( $temp_dir ) ) {
|
||||
// Find expired helper scripts and delete them.
|
||||
$helper_scripts = glob( trailingslashit( $temp_dir ) . 'jp-helper-*.php' );
|
||||
if ( is_array( $helper_scripts ) ) {
|
||||
foreach ( $helper_scripts as $filename ) {
|
||||
if ( null === $expiry_time || filemtime( $filename ) < $expiry_time ) {
|
||||
self::delete_helper_script( $filename );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the directory if it's empty now.
|
||||
self::delete_empty_helper_directory( $temp_dir );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a helper script directory if it's empty
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param string $dir Path to Helper Script directory.
|
||||
* @return boolean True if the directory is deleted
|
||||
*/
|
||||
private static function delete_empty_helper_directory( $dir ) {
|
||||
if ( ! is_dir( $dir ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tally the files in the target directory, and reject if there are too many.
|
||||
$glob_path = trailingslashit( $dir ) . '*';
|
||||
$dir_contents = glob( $glob_path );
|
||||
if ( count( $dir_contents ) > 2 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the only remaining files are a README and index.php generated by this system.
|
||||
$allowed_files = array(
|
||||
'README' => self::README_LINES[0],
|
||||
'index.php' => self::INDEX_FILE,
|
||||
);
|
||||
|
||||
foreach ( $dir_contents as $path ) {
|
||||
$basename = basename( $path );
|
||||
if ( ! isset( $allowed_files[ $basename ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the file starts with the expected contents.
|
||||
if ( ! self::verify_file_header( $path, $allowed_files[ $basename ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! unlink( $path ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If the directory is now empty, delete it.
|
||||
if ( count( glob( $glob_path ) ) === 0 ) {
|
||||
return rmdir( $dir );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find an appropriate location for a jetpack-temp folder, and create one
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return WP_Error|array Array containing the url and path of the temp directory if successful, WP_Error if not.
|
||||
*/
|
||||
private static function create_temp_directory() {
|
||||
foreach ( self::get_install_locations() as $directory => $url ) {
|
||||
// Check if the install location is writeable.
|
||||
if ( ! is_writeable( $directory ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create if one doesn't already exist.
|
||||
$temp_dir = trailingslashit( $directory ) . self::TEMP_DIRECTORY;
|
||||
if ( ! is_dir( $temp_dir ) ) {
|
||||
if ( ! mkdir( $temp_dir ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Temp directory created. Drop a README and index.php file in there.
|
||||
self::write_supplementary_temp_files( $temp_dir );
|
||||
}
|
||||
|
||||
return array(
|
||||
'path' => trailingslashit( $directory ) . self::TEMP_DIRECTORY,
|
||||
'url' => trailingslashit( $url ) . self::TEMP_DIRECTORY,
|
||||
);
|
||||
}
|
||||
|
||||
return new \WP_Error( 'temp_directory', 'Failed to create jetpack-temp directory' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write out an index.php file and a README file for a new jetpack-temp directory.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param string $dir Path to Helper Script directory.
|
||||
*/
|
||||
private static function write_supplementary_temp_files( $dir ) {
|
||||
$readme_path = trailingslashit( $dir ) . 'README';
|
||||
self::put_contents( $readme_path, implode( "\n\n", self::README_LINES ) );
|
||||
|
||||
$index_path = trailingslashit( $dir ) . 'index.php';
|
||||
self::put_contents( $index_path, self::INDEX_FILE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a file to the specified location with the specified contents.
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
*
|
||||
* @param string $file_path Path to write to.
|
||||
* @param string $contents File contents to write.
|
||||
* @return boolean True if successfully written.
|
||||
*/
|
||||
private static function put_contents( $file_path, $contents ) {
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! function_exists( '\\WP_Filesystem' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
|
||||
if ( ! \WP_Filesystem() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $wp_filesystem->put_contents( $file_path, $contents );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a file exists, is readable, and has the expected header.
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
*
|
||||
* @param string $file_path File to verify.
|
||||
* @param string $expected_header Header that the file should have.
|
||||
* @return boolean True if the file exists, is readable, and the header matches.
|
||||
*/
|
||||
private static function verify_file_header( $file_path, $expected_header ) {
|
||||
global $wp_filesystem;
|
||||
|
||||
if ( ! function_exists( '\\WP_Filesystem' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
}
|
||||
|
||||
if ( ! \WP_Filesystem() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify the file exists and is readable.
|
||||
if ( ! $wp_filesystem->exists( $file_path ) || ! $wp_filesystem->is_readable( $file_path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify that the file isn't too big or small.
|
||||
$file_size = $wp_filesystem->size( $file_path );
|
||||
if ( $file_size < strlen( $expected_header ) || $file_size > self::MAX_FILESIZE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read the file and verify its header.
|
||||
$contents = $wp_filesystem->get_contents( $file_path );
|
||||
return ( strncmp( $contents, $expected_header, strlen( $expected_header ) ) === 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an associative array of possible places to install a jetpack-temp directory, along with the URL to access each.
|
||||
*
|
||||
* @access private
|
||||
* @static
|
||||
*
|
||||
* @return array Array, with keys specifying the full path of install locations, and values with the equivalent URL.
|
||||
*/
|
||||
public static function get_install_locations() {
|
||||
// Include WordPress root and wp-content.
|
||||
$install_locations = array(
|
||||
\ABSPATH => \get_site_url(),
|
||||
\WP_CONTENT_DIR => \WP_CONTENT_URL,
|
||||
);
|
||||
|
||||
// Include uploads folder.
|
||||
$upload_dir_info = \wp_upload_dir();
|
||||
$install_locations[ $upload_dir_info['basedir'] ] = $upload_dir_info['baseurl'];
|
||||
|
||||
return $install_locations;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
<?php
|
||||
/**
|
||||
* The Package_Version class.
|
||||
*
|
||||
* @package automattic/jetpack-transport-helper
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Transport_Helper;
|
||||
|
||||
/**
|
||||
* The Package_Version class.
|
||||
*/
|
||||
class Package_Version {
|
||||
|
||||
const PACKAGE_VERSION = '0.1.0';
|
||||
|
||||
const PACKAGE_SLUG = 'transport-helper';
|
||||
|
||||
/**
|
||||
* Adds the package slug and version to the package version tracker's data.
|
||||
*
|
||||
* @param array $package_versions The package version array.
|
||||
*
|
||||
* @return array The packge version array.
|
||||
*/
|
||||
public static function send_package_version_to_tracker( $package_versions ) {
|
||||
$package_versions[ self::PACKAGE_SLUG ] = self::PACKAGE_VERSION;
|
||||
return $package_versions;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* The Jetpack Helper Script Rest Controller class.
|
||||
* Registers the REST routes.
|
||||
*
|
||||
* @package automattic/jetpack-transport-helper
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Transport_Helper;
|
||||
|
||||
use Automattic\Jetpack\Connection\Rest_Authentication;
|
||||
use WP_Error;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Server;
|
||||
|
||||
/**
|
||||
* Registers the REST routes.
|
||||
*/
|
||||
class REST_Controller {
|
||||
/**
|
||||
* Registers the REST routes.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*/
|
||||
public static function register_rest_routes() {
|
||||
// Install a Helper Script to assist with fetching data.
|
||||
register_rest_route(
|
||||
'jetpack/v4',
|
||||
// This route can be generalized once we no longer depend on the backup package
|
||||
'/backup-helper-script',
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
'callback' => __CLASS__ . '::install_helper_script',
|
||||
'permission_callback' => __CLASS__ . '::helper_script_permissions_callback',
|
||||
'args' => array(
|
||||
'helper' => array(
|
||||
'description' => __( 'base64 encoded Helper Script body.', 'jetpack-transport-helper' ),
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Delete a Helper Script.
|
||||
register_rest_route(
|
||||
'jetpack/v4',
|
||||
// This route can be generalized once we no longer depend on the backup package
|
||||
'/backup-helper-script',
|
||||
array(
|
||||
'methods' => WP_REST_Server::DELETABLE,
|
||||
'callback' => __CLASS__ . '::delete_helper_script',
|
||||
'permission_callback' => __CLASS__ . '::helper_script_permissions_callback',
|
||||
'args' => array(
|
||||
'path' => array(
|
||||
'description' => __( 'Path to Helper Script', 'jetpack-transport-helper' ),
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Jetpack endpoints should only be available via site-level authentication.
|
||||
* This means that the corresponding endpoints can only be accessible from WPCOM.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return bool|WP_Error True if a blog token was used to sign the request, WP_Error otherwise.
|
||||
*/
|
||||
public static function helper_script_permissions_callback() {
|
||||
if ( Rest_Authentication::is_signed_with_blog_token() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$error_msg = esc_html__(
|
||||
'You are not allowed to perform this action.',
|
||||
'jetpack-transport-helper'
|
||||
);
|
||||
|
||||
return new WP_Error( 'rest_forbidden', $error_msg, array( 'status' => rest_authorization_required_code() ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the Helper Script.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param WP_REST_Request $request The request sent to the WP REST API.
|
||||
* @return array|WP_Error Returns the result of Helper Script installation. Returns one of:
|
||||
* - WP_Error on failure, or
|
||||
* - An array with installation info on success:
|
||||
* 'path' (string) The sinstallation path.
|
||||
* 'url' (string) The access url.
|
||||
* 'abspath' (string) The abspath.
|
||||
*/
|
||||
public static function install_helper_script( $request ) {
|
||||
$helper_script = $request->get_param( 'helper' );
|
||||
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
||||
$helper_script = base64_decode( $helper_script );
|
||||
if ( ! $helper_script ) {
|
||||
return new WP_Error( 'invalid_args', __( 'Helper Script body must be base64 encoded', 'jetpack-transport-helper' ), 400 );
|
||||
}
|
||||
|
||||
$installation_info = Helper_Script_Manager::install_helper_script( $helper_script );
|
||||
Helper_Script_Manager::cleanup_expired_helper_scripts();
|
||||
|
||||
// Include ABSPATH with successful result.
|
||||
if ( ! is_wp_error( $installation_info ) ) {
|
||||
$installation_info['abspath'] = ABSPATH;
|
||||
}
|
||||
|
||||
return rest_ensure_response( $installation_info );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a Helper Script.
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @param WP_REST_Request $request The request sent to the WP REST API.
|
||||
* @return array An array with 'success' key indicating the result of the delete operation.
|
||||
*/
|
||||
public static function delete_helper_script( $request ) {
|
||||
$path_to_helper_script = $request->get_param( 'path' );
|
||||
|
||||
$deleted = Helper_Script_Manager::delete_helper_script( $path_to_helper_script );
|
||||
Helper_Script_Manager::cleanup_expired_helper_scripts();
|
||||
|
||||
return rest_ensure_response(
|
||||
array(
|
||||
'success' => $deleted,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -4,49 +4,53 @@ return array(
|
||||
'domain' => 'jetpack-protect',
|
||||
'type' => 'plugins',
|
||||
'packages' => array(
|
||||
'jetpack-admin-ui' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-admin-ui',
|
||||
'ver' => '0.2.12',
|
||||
),
|
||||
'jetpack-assets' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-assets',
|
||||
'ver' => '1.17.25',
|
||||
),
|
||||
'jetpack-config' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-config',
|
||||
'ver' => '1.9.6',
|
||||
'ver' => '1.11.0',
|
||||
),
|
||||
'jetpack-connection' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-connection',
|
||||
'ver' => '1.46.3',
|
||||
),
|
||||
'jetpack-idc' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-identity-crisis',
|
||||
'ver' => '0.8.31',
|
||||
),
|
||||
'jetpack-jitm' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-jitm',
|
||||
'ver' => '2.2.33',
|
||||
),
|
||||
'jetpack-licensing' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-licensing',
|
||||
'ver' => '1.7.11',
|
||||
),
|
||||
'jetpack-my-jetpack' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-my-jetpack',
|
||||
'ver' => '2.4.0',
|
||||
),
|
||||
'jetpack-password-checker' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-password-checker',
|
||||
'ver' => '0.2.7',
|
||||
),
|
||||
'jetpack-plugins-installer' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-plugins-installer',
|
||||
'ver' => '0.2.0',
|
||||
),
|
||||
'jetpack-admin-ui' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-admin-ui',
|
||||
'ver' => '0.2.11',
|
||||
),
|
||||
'jetpack-assets' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-assets',
|
||||
'ver' => '1.17.21',
|
||||
),
|
||||
'jetpack-jitm' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-jitm',
|
||||
'ver' => '2.2.26',
|
||||
),
|
||||
'jetpack-password-checker' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-password-checker',
|
||||
'ver' => '0.2.6',
|
||||
),
|
||||
'jetpack-idc' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-identity-crisis',
|
||||
'ver' => '0.8.22',
|
||||
),
|
||||
'jetpack-connection' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-connection',
|
||||
'ver' => '1.44.0',
|
||||
),
|
||||
'jetpack-licensing' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-licensing',
|
||||
'ver' => '1.7.8',
|
||||
),
|
||||
'jetpack-sync' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-sync',
|
||||
'ver' => '1.38.2',
|
||||
'ver' => '1.43.0',
|
||||
),
|
||||
'jetpack-my-jetpack' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-my-jetpack',
|
||||
'ver' => '2.0.3',
|
||||
'jetpack-transport-helper' => array(
|
||||
'path' => 'jetpack_vendor/automattic/jetpack-transport-helper',
|
||||
'ver' => '0.1.0',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -1,10 +1,10 @@
|
||||
=== Jetpack Protect ===
|
||||
Contributors: automattic, retrofox, leogermani, renatoagds, bjorsch, ebinnion, fgiannar, zinigor, miguelxavierpenha, dsmart, jeherve, manzoorwanijk, njweller, oskosk, samiff, siddarthan, wpkaren, arsihasi, kraftbj, kev, sermitr, kangzj, pabline
|
||||
Contributors: automattic, retrofox, leogermani, renatoagds, bjorsch, ebinnion, fgiannar, zinigor, miguelxavierpenha, dsmart, jeherve, manzoorwanijk, njweller, oskosk, samiff, siddarthan, wpkaren, arsihasi, kraftbj, kev, sermitr, kangzj, pabline, dkmyta
|
||||
Tags: jetpack, protect, security, malware, scan
|
||||
Requires at least: 5.9
|
||||
Requires at least: 6.0
|
||||
Requires PHP: 5.6
|
||||
Tested up to: 6.0
|
||||
Stable tag: 1.0.4
|
||||
Tested up to: 6.1
|
||||
Stable tag: 1.1.1
|
||||
License: GPLv2 or later
|
||||
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
@ -109,7 +109,7 @@ The features of the new Jetpack Protect plugin are not included in the [Jetpack
|
||||
3. View all the found vulnerabilities in your site and learn how to fix them.
|
||||
|
||||
== Changelog ==
|
||||
### 1.0.4 - 2022-08-29
|
||||
#### Fixed
|
||||
- Fixed NaN error that prevented the pricing interstitial from rendering.
|
||||
## 1.1.1 - 2022-11-18
|
||||
### Fixed
|
||||
- Fix issue with plugin activation.
|
||||
|
||||
|
56
wp-content/plugins/jetpack-protect/src/class-credentials.php
Normal file
56
wp-content/plugins/jetpack-protect/src/class-credentials.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle Rewind
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Jetpack_Options;
|
||||
|
||||
/**
|
||||
* Class that handles the rewind api call.
|
||||
*/
|
||||
class Credentials {
|
||||
/**
|
||||
* Get the rewind state, if no creds are set the state will be 'awaiting_for_credentials'
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function get_credential_array() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$api_url = sprintf( '/sites/%d/scan', $blog_id );
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
$api_url,
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parsed_response = json_decode( $response['body'] );
|
||||
|
||||
if ( ! $parsed_response ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset( $parsed_response->credentials ) ? $parsed_response->credentials : array();
|
||||
}
|
||||
|
||||
}
|
@ -18,10 +18,16 @@ use Automattic\Jetpack\JITMS\JITM as JITM;
|
||||
use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer;
|
||||
use Automattic\Jetpack\My_Jetpack\Products as My_Jetpack_Products;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Protect\Credentials;
|
||||
use Automattic\Jetpack\Protect\Plan;
|
||||
use Automattic\Jetpack\Protect\Scan_Status;
|
||||
use Automattic\Jetpack\Protect\Site_Health;
|
||||
use Automattic\Jetpack\Protect\Status as Protect_Status;
|
||||
use Automattic\Jetpack\Protect\Status;
|
||||
use Automattic\Jetpack\Protect\Threats;
|
||||
use Automattic\Jetpack\Status as Jetpack_Status;
|
||||
use Automattic\Jetpack\Sync\Functions as Sync_Functions;
|
||||
use Automattic\Jetpack\Sync\Sender;
|
||||
|
||||
/**
|
||||
* Class Jetpack_Protect
|
||||
*/
|
||||
@ -32,8 +38,9 @@ class Jetpack_Protect {
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'init' ) );
|
||||
add_action( '_admin_menu', array( $this, 'admin_page_init' ) );
|
||||
|
||||
// Init Jetpack packages and ConnectionUI.
|
||||
// Init Jetpack packages
|
||||
add_action(
|
||||
'plugins_loaded',
|
||||
function () {
|
||||
@ -54,11 +61,13 @@ class Jetpack_Protect {
|
||||
'jetpack_sync_modules' => array(
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Options',
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Callables',
|
||||
'Automattic\\Jetpack\\Sync\\Modules\\Users',
|
||||
),
|
||||
'jetpack_sync_callable_whitelist' => array(
|
||||
'get_plugins' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'get_plugins' ),
|
||||
'get_themes' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'get_themes' ),
|
||||
'wp_version' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'wp_version' ),
|
||||
'main_network_site' => array( 'Automattic\\Jetpack\\Connection\\Urls', 'main_network_site_url' ),
|
||||
'get_plugins' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'get_plugins' ),
|
||||
'get_themes' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'get_themes' ),
|
||||
'wp_version' => array( 'Automattic\\Jetpack\\Sync\\Functions', 'wp_version' ),
|
||||
),
|
||||
'jetpack_sync_options_contentless' => array(),
|
||||
'jetpack_sync_options_whitelist' => array(
|
||||
@ -84,22 +93,6 @@ class Jetpack_Protect {
|
||||
// Set up the REST authentication hooks.
|
||||
Connection_Rest_Authentication::init();
|
||||
|
||||
$total_vuls = Protect_Status::get_total_vulnerabilities();
|
||||
$menu_label = _x( 'Protect', 'The Jetpack Protect product name, without the Jetpack prefix', 'jetpack-protect' );
|
||||
if ( $total_vuls ) {
|
||||
$menu_label .= sprintf( ' <span class="update-plugins">%d</span>', $total_vuls );
|
||||
}
|
||||
|
||||
$page_suffix = Admin_Menu::add_menu(
|
||||
__( 'Jetpack Protect', 'jetpack-protect' ),
|
||||
$menu_label,
|
||||
'manage_options',
|
||||
'jetpack-protect',
|
||||
array( $this, 'plugin_settings_page' ),
|
||||
99
|
||||
);
|
||||
add_action( 'load-' . $page_suffix, array( $this, 'admin_init' ) );
|
||||
|
||||
add_action( 'admin_bar_menu', array( $this, 'admin_bar' ), 65 );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
|
||||
// Add custom WP REST API endoints.
|
||||
@ -113,10 +106,25 @@ class Jetpack_Protect {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the admin resources.
|
||||
* Initialize the admin page resources.
|
||||
*/
|
||||
public function admin_init() {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
|
||||
public function admin_page_init() {
|
||||
$total_threats = Status::get_total_threats();
|
||||
$menu_label = _x( 'Protect', 'The Jetpack Protect product name, without the Jetpack prefix', 'jetpack-protect' );
|
||||
if ( $total_threats ) {
|
||||
$menu_label .= sprintf( ' <span class="update-plugins">%d</span>', $total_threats );
|
||||
}
|
||||
|
||||
$page_suffix = Admin_Menu::add_menu(
|
||||
__( 'Jetpack Protect', 'jetpack-protect' ),
|
||||
$menu_label,
|
||||
'manage_options',
|
||||
'jetpack-protect',
|
||||
array( $this, 'plugin_settings_page' ),
|
||||
99
|
||||
);
|
||||
|
||||
add_action( 'load-' . $page_suffix, array( $this, 'enqueue_admin_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,18 +173,26 @@ class Jetpack_Protect {
|
||||
*/
|
||||
public function initial_state() {
|
||||
global $wp_version;
|
||||
return array(
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
$refresh_status_from_wpcom = isset( $_GET['checkPlan'] );
|
||||
$initial_state = array(
|
||||
'apiRoot' => esc_url_raw( rest_url() ),
|
||||
'apiNonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
|
||||
'status' => Protect_Status::get_status(),
|
||||
'status' => Status::get_status( $refresh_status_from_wpcom ),
|
||||
'installedPlugins' => Plugins_Installer::get_plugins(),
|
||||
'installedThemes' => Sync_Functions::get_themes(),
|
||||
'wpVersion' => $wp_version,
|
||||
'adminUrl' => admin_url( 'admin.php?page=jetpack-protect' ),
|
||||
'securityBundle' => My_Jetpack_Products::get_product( 'security' ),
|
||||
'adminUrl' => 'admin.php?page=jetpack-protect',
|
||||
'siteSuffix' => ( new Jetpack_Status() )->get_site_suffix(),
|
||||
'jetpackScan' => My_Jetpack_Products::get_product( 'scan' ),
|
||||
'productData' => My_Jetpack_Products::get_product( 'protect' ),
|
||||
'hasRequiredPlan' => Plan::has_required_plan(),
|
||||
);
|
||||
|
||||
$initial_state['jetpackScan']['pricingForUi'] = Plan::get_product( 'jetpack_scan' );
|
||||
|
||||
return $initial_state;
|
||||
}
|
||||
/**
|
||||
* Main plugin settings page.
|
||||
@ -202,11 +218,11 @@ class Jetpack_Protect {
|
||||
$manager = new Connection_Manager( 'jetpack-protect' );
|
||||
$manager->remove_connection();
|
||||
|
||||
Protect_Status::delete_option();
|
||||
Status::delete_option();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a shortcut on Admin Bar to show the total of vulnerabilities found.
|
||||
* Create a shortcut on Admin Bar to show the total of threats found.
|
||||
*
|
||||
* @param object $wp_admin_bar The Admin Bar object.
|
||||
* @return void
|
||||
@ -216,7 +232,7 @@ class Jetpack_Protect {
|
||||
return;
|
||||
}
|
||||
|
||||
$total = Protect_Status::get_total_vulnerabilities();
|
||||
$total = Status::get_total_threats();
|
||||
|
||||
if ( $total > 0 ) {
|
||||
$args = array(
|
||||
@ -224,8 +240,8 @@ class Jetpack_Protect {
|
||||
'title' => '<span class="ab-icon jp-protect-icon"></span><span class="ab-label">' . $total . '</span>',
|
||||
'href' => admin_url( 'admin.php?page=jetpack-protect' ),
|
||||
'meta' => array(
|
||||
// translators: %d is the number of vulnerabilities found.
|
||||
'title' => sprintf( _n( '%d vulnerability found by Jetpack Protect', '%d vulnerabilities found by Jetpack Protect', $total, 'jetpack-protect' ), $total ),
|
||||
// translators: %d is the number of threats found.
|
||||
'title' => sprintf( _n( '%d threat found by Jetpack Protect', '%d threats found by Jetpack Protect', $total, 'jetpack-protect' ), $total ),
|
||||
),
|
||||
);
|
||||
|
||||
@ -239,6 +255,18 @@ class Jetpack_Protect {
|
||||
* @return void
|
||||
*/
|
||||
public static function register_rest_endpoints() {
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'check-plan',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => __CLASS__ . '::api_check_plan',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'status',
|
||||
@ -250,15 +278,208 @@ class Jetpack_Protect {
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'clear-scan-cache',
|
||||
array(
|
||||
'methods' => \WP_REST_SERVER::EDITABLE,
|
||||
'callback' => __CLASS__ . '::api_clear_scan_cache',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'ignore-threat',
|
||||
array(
|
||||
'methods' => \WP_REST_SERVER::EDITABLE,
|
||||
'callback' => __CLASS__ . '::api_ignore_threat',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'fix-threats',
|
||||
array(
|
||||
'methods' => \WP_REST_SERVER::EDITABLE,
|
||||
'callback' => __CLASS__ . '::api_fix_threats',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'fix-threats-status',
|
||||
array(
|
||||
'methods' => \WP_REST_SERVER::READABLE,
|
||||
'callback' => __CLASS__ . '::api_fix_threats_status',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'check-credentials',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'callback' => __CLASS__ . '::api_check_credentials',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'jetpack-protect/v1',
|
||||
'scan',
|
||||
array(
|
||||
'methods' => \WP_REST_SERVER::EDITABLE,
|
||||
'callback' => __CLASS__ . '::api_scan',
|
||||
'permission_callback' => function () {
|
||||
return current_user_can( 'manage_options' );
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return site plan data for the API endpoint
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_check_plan() {
|
||||
$has_required_plan = Plan::has_required_plan();
|
||||
|
||||
return rest_ensure_response( $has_required_plan, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return Protect Status for the API endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_get_status() {
|
||||
$status = Protect_Status::get_status();
|
||||
public static function api_get_status( $request ) {
|
||||
$status = Status::get_status( $request['hard_refresh'] );
|
||||
return rest_ensure_response( $status, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the Scan_Status cache for the API endpoint
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_clear_scan_cache() {
|
||||
$cache_cleared = Scan_Status::delete_option();
|
||||
|
||||
if ( ! $cache_cleared ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to clear the Jetpack Scan cache.', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( 'Jetpack Scan cache cleared.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignores a threat for the API endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_ignore_threat( $request ) {
|
||||
if ( ! $request['threat_id'] ) {
|
||||
return new WP_REST_RESPONSE( 'Missing threat ID.', 400 );
|
||||
}
|
||||
|
||||
$threat_ignored = Threats::ignore_threat( $request['threat_id'] );
|
||||
|
||||
if ( ! $threat_ignored ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to ignore the threat.', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( 'Threat ignored.' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes threats for the API endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_fix_threats( $request ) {
|
||||
if ( empty( $request['threat_ids'] ) ) {
|
||||
return new WP_REST_RESPONSE( 'Missing threat IDs.', 400 );
|
||||
}
|
||||
|
||||
$threats_fixed = Threats::fix_threats( $request['threat_ids'] );
|
||||
|
||||
if ( ! $threats_fixed ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to fix the threat.', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $threats_fixed );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes threats for the API endpoint
|
||||
*
|
||||
* @param WP_REST_Request $request The request object.
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_fix_threats_status( $request ) {
|
||||
if ( empty( $request['threat_ids'] ) ) {
|
||||
return new WP_REST_RESPONSE( 'Missing threat IDs.', 400 );
|
||||
}
|
||||
|
||||
$threats_fixed = Threats::fix_threats_status( $request['threat_ids'] );
|
||||
|
||||
if ( ! $threats_fixed ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to get the fixer status of the threats.', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $threats_fixed );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the site has credentials configured
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_check_credentials() {
|
||||
$credential_array = Credentials::get_credential_array();
|
||||
|
||||
if ( ! isset( $credential_array ) ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to fetch the credentials array', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( $credential_array );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a scan for the API endpoint
|
||||
*
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function api_scan() {
|
||||
$scan_enqueued = Threats::scan();
|
||||
|
||||
if ( ! $scan_enqueued ) {
|
||||
return new WP_REST_Response( 'An error occured while attempting to enqueue the scan.', 500 );
|
||||
}
|
||||
|
||||
return new WP_REST_Response( 'Scan enqueued.' );
|
||||
}
|
||||
}
|
||||
|
111
wp-content/plugins/jetpack-protect/src/class-plan.php
Normal file
111
wp-content/plugins/jetpack-protect/src/class-plan.php
Normal file
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle the Protect plan
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Current_Plan;
|
||||
|
||||
/**
|
||||
* The Plan class.
|
||||
*/
|
||||
class Plan {
|
||||
/**
|
||||
* The meta name used to store the cache date
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CACHE_DATE_META_NAME = 'protect-cache-date';
|
||||
|
||||
/**
|
||||
* Valid pediord for the cache: One week.
|
||||
*/
|
||||
const CACHE_VALIDITY_PERIOD = 7 * DAY_IN_SECONDS;
|
||||
|
||||
/**
|
||||
* The meta name used to store the cache
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CACHE_META_NAME = 'protect-cache';
|
||||
|
||||
/**
|
||||
* Checks if the cache is old, meaning we need to fetch new data from WPCOM
|
||||
*/
|
||||
private static function is_cache_old() {
|
||||
if ( empty( self::get_product_from_cache() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$cache_date = get_user_meta( get_current_user_id(), self::CACHE_DATE_META_NAME, true );
|
||||
return time() - (int) $cache_date > ( self::CACHE_VALIDITY_PERIOD );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product list from the user cache
|
||||
*/
|
||||
private static function get_product_from_cache() {
|
||||
return get_user_meta( get_current_user_id(), self::CACHE_META_NAME, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product data
|
||||
*
|
||||
* @param string $wpcom_product The product slug.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_product( $wpcom_product = 'jetpack_scan' ) {
|
||||
if ( ! self::is_cache_old() ) {
|
||||
return self::get_product_from_cache();
|
||||
}
|
||||
|
||||
$request_url = 'https://public-api.wordpress.com/rest/v1.1/products?locale=' . get_user_locale() . '&type=jetpack';
|
||||
$wpcom_request = wp_remote_get( esc_url_raw( $request_url ) );
|
||||
$response_code = wp_remote_retrieve_response_code( $wpcom_request );
|
||||
|
||||
if ( 200 === $response_code ) {
|
||||
$products = json_decode( wp_remote_retrieve_body( $wpcom_request ) );
|
||||
|
||||
// Pick the desired product...
|
||||
$product = $products->{$wpcom_product};
|
||||
|
||||
// ... and store it into the cache.
|
||||
update_user_meta( get_current_user_id(), self::CACHE_DATE_META_NAME, time() );
|
||||
update_user_meta( get_current_user_id(), self::CACHE_META_NAME, $product );
|
||||
|
||||
return $product;
|
||||
}
|
||||
|
||||
return new \WP_Error(
|
||||
'failed_to_fetch_data',
|
||||
esc_html__( 'Unable to fetch the requested data.', 'jetpack-protect' ),
|
||||
array(
|
||||
'status' => $response_code,
|
||||
'request' => $wpcom_request,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Has Required Plan
|
||||
*
|
||||
* @param bool $force_refresh Refresh the local plan cache from wpcom.
|
||||
* @return bool True when the site has a plan or product that supports the paid Protect tier.
|
||||
*/
|
||||
public static function has_required_plan( $force_refresh = false ) {
|
||||
static $has_scan = null;
|
||||
if ( null === $has_scan || $force_refresh ) {
|
||||
$products = array_column( Current_Plan::get_products(), 'product_slug' );
|
||||
|
||||
// Check for a plan or product that enables scan.
|
||||
$plan_supports_scan = Current_Plan::supports( 'scan', true );
|
||||
$has_scan_product = count( array_intersect( array( 'jetpack_scan', 'jetpack_scan_monthly' ), $products ) ) > 0;
|
||||
$has_scan = $plan_supports_scan || $has_scan_product;
|
||||
}
|
||||
|
||||
return $has_scan;
|
||||
}
|
||||
}
|
259
wp-content/plugins/jetpack-protect/src/class-protect-status.php
Normal file
259
wp-content/plugins/jetpack-protect/src/class-protect-status.php
Normal file
@ -0,0 +1,259 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle the Protect Status of Jetpack Protect
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Redirect;
|
||||
use Automattic\Jetpack\Sync\Functions as Sync_Functions;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class that handles fetching and caching the Status of vulnerabilities check from the WPCOM servers
|
||||
*/
|
||||
class Protect_Status extends Status {
|
||||
|
||||
/**
|
||||
* WPCOM endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const REST_API_BASE = '/sites/%d/jetpack-protect-status';
|
||||
|
||||
/**
|
||||
* Name of the option where status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_NAME = 'jetpack_protect_status';
|
||||
|
||||
/**
|
||||
* Name of the option where the timestamp of the status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_TIMESTAMP_NAME = 'jetpack_protect_status_time';
|
||||
|
||||
/**
|
||||
* Gets the current status of the Jetpack Protect checks
|
||||
*
|
||||
* @param bool $refresh_from_wpcom Refresh the local plan and status cache from wpcom.
|
||||
* @return Status_Model
|
||||
*/
|
||||
public static function get_status( $refresh_from_wpcom = false ) {
|
||||
if ( self::$status !== null ) {
|
||||
return self::$status;
|
||||
}
|
||||
|
||||
if ( $refresh_from_wpcom || ! self::should_use_cache() || self::is_cache_expired() ) {
|
||||
$status = self::fetch_from_server();
|
||||
} else {
|
||||
$status = self::get_from_options();
|
||||
}
|
||||
|
||||
if ( is_wp_error( $status ) ) {
|
||||
$status = new Status_Model(
|
||||
array(
|
||||
'error' => true,
|
||||
'error_code' => $status->get_error_code(),
|
||||
'error_message' => $status->get_error_message(),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$status = self::normalize_protect_report_data( $status );
|
||||
}
|
||||
|
||||
self::$status = $status;
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the WPCOM API endpoint
|
||||
*
|
||||
* @return WP_Error|string
|
||||
*/
|
||||
public static function get_api_url() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return new WP_Error( 'site_not_connected' );
|
||||
}
|
||||
|
||||
$api_url = sprintf( self::REST_API_BASE, $blog_id );
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the status from WPCOM servers
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
public static function fetch_from_server() {
|
||||
$api_url = self::get_api_url();
|
||||
if ( is_wp_error( $api_url ) ) {
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
self::get_api_url(),
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
|
||||
return new WP_Error( 'failed_fetching_status', 'Failed to fetch Protect Status data from server', array( 'status' => $response_code ) );
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
self::update_option( maybe_serialize( $body ) );
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize data from the Protect Report data source.
|
||||
*
|
||||
* @param object $report_data Data from the Protect Report.
|
||||
* @return Status_Model
|
||||
*/
|
||||
protected static function normalize_protect_report_data( $report_data ) {
|
||||
$status = new Status_Model();
|
||||
$status->data_source = 'protect_report';
|
||||
|
||||
// map report data properties directly into the Status_Model
|
||||
$status->status = isset( $report_data->status ) ? $report_data->status : null;
|
||||
$status->last_checked = isset( $report_data->last_checked ) ? $report_data->last_checked : null;
|
||||
$status->num_threats = isset( $report_data->num_vulnerabilities ) ? $report_data->num_vulnerabilities : null;
|
||||
$status->num_themes_threats = isset( $report_data->num_themes_vulnerabilities ) ? $report_data->num_themes_vulnerabilities : null;
|
||||
$status->num_plugins_threats = isset( $report_data->num_plugins_vulnerabilities ) ? $report_data->num_plugins_vulnerabilities : null;
|
||||
|
||||
// merge plugins from report with all installed plugins before mapping into the Status_Model
|
||||
$installed_plugins = Plugins_Installer::get_plugins();
|
||||
$last_report_plugins = isset( $report_data->plugins ) ? $report_data->plugins : new \stdClass();
|
||||
$status->plugins = self::merge_installed_and_checked_lists( $installed_plugins, $last_report_plugins, array( 'type' => 'plugins' ) );
|
||||
|
||||
// merge themes from report with all installed plugins before mapping into the Status_Model
|
||||
$installed_themes = Sync_Functions::get_themes();
|
||||
$last_report_themes = isset( $report_data->themes ) ? $report_data->themes : new \stdClass();
|
||||
$status->themes = self::merge_installed_and_checked_lists( $installed_themes, $last_report_themes, array( 'type' => 'themes' ) );
|
||||
|
||||
// normalize WordPress core report data and map into Status_Model
|
||||
$status->core = self::normalize_core_information( isset( $report_data->core ) ? $report_data->core : new \stdClass() );
|
||||
|
||||
// check if any installed items (themes, plugins, or core) have not been checked in the report
|
||||
$all_items = array_merge( $status->plugins, $status->themes, array( $status->core ) );
|
||||
$unchecked_items = array_filter(
|
||||
$all_items,
|
||||
function ( $item ) {
|
||||
return ! isset( $item->checked ) || ! $item->checked;
|
||||
}
|
||||
);
|
||||
$status->has_unchecked_items = ! empty( $unchecked_items );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the list of installed extensions with the list of extensions that were checked for known vulnerabilities and return a normalized list to be used in the UI
|
||||
*
|
||||
* @param array $installed The list of installed extensions, where each attribute key is the extension slug.
|
||||
* @param object $checked The list of checked extensions.
|
||||
* @param array $append Additional data to append to each result in the list.
|
||||
* @return array Normalized list of extensions.
|
||||
*/
|
||||
protected static function merge_installed_and_checked_lists( $installed, $checked, $append ) {
|
||||
$new_list = array();
|
||||
foreach ( array_keys( $installed ) as $slug ) {
|
||||
|
||||
$checked = (object) $checked;
|
||||
|
||||
$extension = new Extension_Model(
|
||||
array_merge(
|
||||
array(
|
||||
'name' => $installed[ $slug ]['Name'],
|
||||
'version' => $installed[ $slug ]['Version'],
|
||||
'slug' => $slug,
|
||||
'threats' => array(),
|
||||
'checked' => false,
|
||||
),
|
||||
$append
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( $checked->{ $slug } ) && $checked->{ $slug }->version === $installed[ $slug ]['Version'] ) {
|
||||
$extension->version = $checked->{ $slug }->version;
|
||||
$extension->checked = true;
|
||||
|
||||
if ( is_array( $checked->{ $slug }->vulnerabilities ) ) {
|
||||
foreach ( $checked->{ $slug }->vulnerabilities as $threat ) {
|
||||
$extension->threats[] = new Threat_Model(
|
||||
array(
|
||||
'id' => $threat->id,
|
||||
'title' => $threat->title,
|
||||
'fixed_in' => $threat->fixed_in,
|
||||
'description' => isset( $threat->description ) ? $threat->description : null,
|
||||
'source' => isset( $threat->id ) ? Redirect::get_url( 'jetpack-protect-vul-info', array( 'path' => $threat->id ) ) : null,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$new_list[] = $extension;
|
||||
|
||||
}
|
||||
|
||||
$new_list = parent::sort_threats( $new_list );
|
||||
|
||||
return $new_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the WordPress version that was checked matches the current installed version.
|
||||
*
|
||||
* @param object $core_check The object returned by Protect wpcom endpoint.
|
||||
* @return object The object representing the current status of core checks.
|
||||
*/
|
||||
protected static function normalize_core_information( $core_check ) {
|
||||
global $wp_version;
|
||||
|
||||
$core = new Extension_Model(
|
||||
array(
|
||||
'type' => 'core',
|
||||
'name' => 'WordPress',
|
||||
'version' => $wp_version,
|
||||
'checked' => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( $core_check->version ) && $core_check->version === $wp_version ) {
|
||||
if ( is_array( $core_check->vulnerabilities ) ) {
|
||||
$core->checked = true;
|
||||
$core->set_threats(
|
||||
array_map(
|
||||
function ( $vulnerability ) {
|
||||
$vulnerability->source = isset( $vulnerability->id ) ? Redirect::get_url( 'jetpack-protect-vul-info', array( 'path' => $vulnerability->id ) ) : null;
|
||||
return $vulnerability;
|
||||
},
|
||||
$core_check->vulnerabilities
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $core;
|
||||
}
|
||||
|
||||
}
|
359
wp-content/plugins/jetpack-protect/src/class-scan-status.php
Normal file
359
wp-content/plugins/jetpack-protect/src/class-scan-status.php
Normal file
@ -0,0 +1,359 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle the Scan Status of Jetpack Protect
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Sync\Functions as Sync_Functions;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class that handles fetching of threats from the Scan API
|
||||
*/
|
||||
class Scan_Status extends Status {
|
||||
|
||||
/**
|
||||
* Scan endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const SCAN_API_BASE = '/sites/%d/scan';
|
||||
|
||||
/**
|
||||
* Name of the option where status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_NAME = 'jetpack_scan_status';
|
||||
|
||||
/**
|
||||
* Name of the option where the timestamp of the status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_TIMESTAMP_NAME = 'jetpack_scan_status_timestamp';
|
||||
|
||||
/**
|
||||
* Time in seconds that the cache should last
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
const OPTION_EXPIRES_AFTER = 300; // 5 minutes.
|
||||
|
||||
/**
|
||||
* Gets the current status of the Jetpack Protect checks
|
||||
*
|
||||
* @param bool $refresh_from_wpcom Refresh the local plan and status cache from wpcom.
|
||||
* @return Status_Model
|
||||
*/
|
||||
public static function get_status( $refresh_from_wpcom = false ) {
|
||||
if ( self::$status !== null ) {
|
||||
return self::$status;
|
||||
}
|
||||
|
||||
if ( $refresh_from_wpcom || ! self::should_use_cache() || self::is_cache_expired() ) {
|
||||
$status = self::fetch_from_api();
|
||||
} else {
|
||||
$status = self::get_from_options();
|
||||
}
|
||||
|
||||
if ( is_wp_error( $status ) ) {
|
||||
$status = new Status_Model(
|
||||
array(
|
||||
'error' => true,
|
||||
'error_code' => $status->get_error_code(),
|
||||
'error_message' => $status->get_error_message(),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$status = self::normalize_api_data( $status );
|
||||
}
|
||||
|
||||
self::$status = $status;
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Scan API endpoint
|
||||
*
|
||||
* @return WP_Error|string
|
||||
*/
|
||||
public static function get_api_url() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return new WP_Error( 'site_not_connected' );
|
||||
}
|
||||
|
||||
$api_url = sprintf( self::SCAN_API_BASE, $blog_id );
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the status data from the Scan API
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
public static function fetch_from_api() {
|
||||
$api_url = self::get_api_url();
|
||||
if ( is_wp_error( $api_url ) ) {
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
self::get_api_url(),
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
|
||||
return new WP_Error( 'failed_fetching_status', 'Failed to fetch Scan data from the server', array( 'status' => $response_code ) );
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
self::update_option( maybe_serialize( $body ) );
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize API Data
|
||||
* Formats the payload from the Scan API into an instance of Status_Model.
|
||||
*
|
||||
* @param object $scan_data The data returned by the scan API.
|
||||
*
|
||||
* @return Status_Model
|
||||
*/
|
||||
private static function normalize_api_data( $scan_data ) {
|
||||
global $wp_version;
|
||||
|
||||
$status = new Status_Model();
|
||||
$status->data_source = 'scan_api';
|
||||
$status->status = isset( $scan_data->state ) ? $scan_data->state : null;
|
||||
$status->num_threats = 0;
|
||||
$status->num_themes_threats = 0;
|
||||
$status->num_plugins_threats = 0;
|
||||
$status->has_unchecked_items = false;
|
||||
|
||||
if ( ! empty( $scan_data->most_recent->timestamp ) ) {
|
||||
$date = new \DateTime( $scan_data->most_recent->timestamp );
|
||||
if ( $date ) {
|
||||
$status->last_checked = $date->format( 'Y-m-d H:i:s' );
|
||||
}
|
||||
}
|
||||
|
||||
$status->core = new Extension_Model(
|
||||
array(
|
||||
'type' => 'core',
|
||||
'name' => 'WordPress',
|
||||
'version' => $wp_version,
|
||||
'checked' => true, // to do: default to false once Scan API has manifest
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( $scan_data->threats ) && is_array( $scan_data->threats ) ) {
|
||||
foreach ( $scan_data->threats as $threat ) {
|
||||
if ( isset( $threat->extension->type ) ) {
|
||||
if ( 'plugin' === $threat->extension->type ) {
|
||||
// add the extension if it does not yet exist in the status
|
||||
if ( ! isset( $status->plugins[ $threat->extension->slug ] ) ) {
|
||||
$status->plugins[ $threat->extension->slug ] = new Extension_Model(
|
||||
array(
|
||||
'name' => isset( $threat->extension->name ) ? $threat->extension->name : null,
|
||||
'slug' => isset( $threat->extension->slug ) ? $threat->extension->slug : null,
|
||||
'version' => isset( $threat->extension->version ) ? $threat->extension->version : null,
|
||||
'type' => 'plugin',
|
||||
'checked' => true,
|
||||
'threats' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$status->plugins[ $threat->extension->slug ]->threats[] = new Threat_Model(
|
||||
array(
|
||||
'id' => isset( $threat->id ) ? $threat->id : null,
|
||||
'signature' => isset( $threat->signature ) ? $threat->signature : null,
|
||||
'title' => isset( $threat->title ) ? $threat->title : null,
|
||||
'description' => isset( $threat->description ) ? $threat->description : null,
|
||||
'vulnerability_description' => isset( $threat->vulnerability_description ) ? $threat->vulnerability_description : null,
|
||||
'fix_description' => isset( $threat->fix_description ) ? $threat->fix_description : null,
|
||||
'payload_subtitle' => isset( $threat->payload_subtitle ) ? $threat->payload_subtitle : null,
|
||||
'payload_description' => isset( $threat->payload_description ) ? $threat->payload_description : null,
|
||||
'first_detected' => isset( $threat->first_detected ) ? $threat->first_detected : null,
|
||||
'fixed_in' => isset( $threat->fixer->fixer ) && 'update' === $threat->fixer->fixer ? $threat->fixer->target : null,
|
||||
'severity' => isset( $threat->severity ) ? $threat->severity : null,
|
||||
'fixable' => isset( $threat->fixer ) ? $threat->fixer : null,
|
||||
'status' => isset( $threat->status ) ? $threat->status : null,
|
||||
'filename' => isset( $threat->filename ) ? $threat->filename : null,
|
||||
'context' => isset( $threat->context ) ? $threat->context : null,
|
||||
'source' => isset( $threat->source ) ? $threat->source : null,
|
||||
)
|
||||
);
|
||||
$status->num_threats++;
|
||||
$status->num_plugins_threats++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'theme' === $threat->extension->type ) {
|
||||
// add the extension if it does not yet exist in the status
|
||||
if ( ! isset( $status->themes[ $threat->extension->slug ] ) ) {
|
||||
$status->themes[ $threat->extension->slug ] = new Extension_Model(
|
||||
array(
|
||||
'name' => isset( $threat->extension->name ) ? $threat->extension->name : null,
|
||||
'slug' => isset( $threat->extension->slug ) ? $threat->extension->slug : null,
|
||||
'version' => isset( $threat->extension->version ) ? $threat->extension->version : null,
|
||||
'type' => 'theme',
|
||||
'checked' => true,
|
||||
'threats' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$status->themes[ $threat->extension->slug ]->threats[] = new Threat_Model(
|
||||
array(
|
||||
'id' => isset( $threat->id ) ? $threat->id : null,
|
||||
'signature' => isset( $threat->signature ) ? $threat->signature : null,
|
||||
'title' => isset( $threat->title ) ? $threat->title : null,
|
||||
'description' => isset( $threat->description ) ? $threat->description : null,
|
||||
'vulnerability_description' => isset( $threat->vulnerability_description ) ? $threat->vulnerability_description : null,
|
||||
'fix_description' => isset( $threat->fix_description ) ? $threat->fix_description : null,
|
||||
'payload_subtitle' => isset( $threat->payload_subtitle ) ? $threat->payload_subtitle : null,
|
||||
'payload_description' => isset( $threat->payload_description ) ? $threat->payload_description : null,
|
||||
'first_detected' => isset( $threat->first_detected ) ? $threat->first_detected : null,
|
||||
'fixed_in' => isset( $threat->fixer->fixer ) && 'update' === $threat->fixer->fixer ? $threat->fixer->target : null,
|
||||
'severity' => isset( $threat->severity ) ? $threat->severity : null,
|
||||
'fixable' => isset( $threat->fixer ) ? $threat->fixer : null,
|
||||
'status' => isset( $threat->status ) ? $threat->status : null,
|
||||
'filename' => isset( $threat->filename ) ? $threat->filename : null,
|
||||
'context' => isset( $threat->context ) ? $threat->context : null,
|
||||
'source' => isset( $threat->source ) ? $threat->source : null,
|
||||
)
|
||||
);
|
||||
$status->num_threats++;
|
||||
$status->num_themes_threats++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $threat->signature ) && 'Vulnerable.WP.Core' === $threat->signature ) {
|
||||
if ( $threat->version !== $wp_version ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$status->core->threats[] = new Threat_Model(
|
||||
array(
|
||||
'id' => $threat->id,
|
||||
'signature' => $threat->signature,
|
||||
'title' => $threat->title,
|
||||
'description' => $threat->description,
|
||||
'first_detected' => $threat->first_detected,
|
||||
'severity' => $threat->severity,
|
||||
)
|
||||
);
|
||||
$status->num_threats++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $threat->filename ) ) {
|
||||
$status->files[] = new Threat_Model( $threat );
|
||||
$status->num_threats++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! empty( $threat->table ) ) {
|
||||
$status->database[] = new Threat_Model( $threat );
|
||||
$status->num_threats++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$installed_plugins = Plugins_Installer::get_plugins();
|
||||
$status->plugins = self::merge_installed_and_checked_lists( $installed_plugins, $status->plugins, array( 'type' => 'plugins' ), true );
|
||||
|
||||
$installed_themes = Sync_Functions::get_themes();
|
||||
$status->themes = self::merge_installed_and_checked_lists( $installed_themes, $status->themes, array( 'type' => 'themes' ), true );
|
||||
|
||||
foreach ( array_merge( $status->themes, $status->plugins ) as $extension ) {
|
||||
if ( ! $extension->checked ) {
|
||||
$status->has_unchecked_items = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the list of installed extensions with the list of extensions that were checked for known vulnerabilities and return a normalized list to be used in the UI
|
||||
*
|
||||
* @param array $installed The list of installed extensions, where each attribute key is the extension slug.
|
||||
* @param object $checked The list of checked extensions.
|
||||
* @param array $append Additional data to append to each result in the list.
|
||||
* @return array Normalized list of extensions.
|
||||
*/
|
||||
protected static function merge_installed_and_checked_lists( $installed, $checked, $append ) {
|
||||
$new_list = array();
|
||||
$checked = (object) $checked;
|
||||
|
||||
foreach ( array_keys( $installed ) as $slug ) {
|
||||
/**
|
||||
* Extension Type Map
|
||||
*
|
||||
* @var array $extension_type_map Key value pairs of extension types and their corresponding
|
||||
* identifier used by the Scan API data source.
|
||||
*/
|
||||
$extension_type_map = array(
|
||||
'themes' => 'r1',
|
||||
'plugins' => 'r2',
|
||||
);
|
||||
|
||||
$version = $installed[ $slug ]['Version'];
|
||||
$short_slug = str_replace( '.php', '', explode( '/', $slug )[0] );
|
||||
$scanifest_slug = $extension_type_map[ $append['type'] ] . ":$short_slug@$version";
|
||||
|
||||
$extension = new Extension_Model(
|
||||
array_merge(
|
||||
array(
|
||||
'name' => $installed[ $slug ]['Name'],
|
||||
'version' => $version,
|
||||
'slug' => $slug,
|
||||
'threats' => array(),
|
||||
'checked' => false,
|
||||
),
|
||||
$append
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! isset( $checked->extensions ) // no extension data available from Scan API
|
||||
|| is_array( $checked->extensions ) && in_array( $scanifest_slug, $checked->extensions, true ) // extension data matches Scan API
|
||||
) {
|
||||
$extension->checked = true;
|
||||
if ( isset( $checked->{ $short_slug }->threats ) ) {
|
||||
$extension->threats = $checked->{ $short_slug }->threats;
|
||||
}
|
||||
}
|
||||
|
||||
$new_list[] = $extension;
|
||||
|
||||
}
|
||||
|
||||
$new_list = parent::sort_threats( $new_list );
|
||||
|
||||
return $new_list;
|
||||
}
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ namespace Automattic\Jetpack\Protect;
|
||||
/**
|
||||
* Site_Health.
|
||||
*
|
||||
* Displays vulnerabilities in WordPress site health page.
|
||||
* Displays threats in WordPress site health page.
|
||||
*/
|
||||
class Site_Health {
|
||||
|
||||
@ -50,20 +50,20 @@ class Site_Health {
|
||||
* @return array
|
||||
*/
|
||||
public static function do_checks() {
|
||||
$total_vuls = Status::get_total_vulnerabilities();
|
||||
$vulns = Status::get_all_vulnerabilities();
|
||||
$vulns = array_map(
|
||||
$total_threats = Status::get_total_threats();
|
||||
$threats = Status::get_all_threats();
|
||||
$threats = array_map(
|
||||
function ( $v ) {
|
||||
return $v->title;
|
||||
},
|
||||
$vulns
|
||||
$threats
|
||||
);
|
||||
|
||||
/**
|
||||
* Default, no vulnerabilities found
|
||||
* Default, no threats found
|
||||
*/
|
||||
$result = array(
|
||||
'label' => __( 'No known vulnerabilities found', 'jetpack-protect' ),
|
||||
'label' => __( 'No known threats found', 'jetpack-protect' ),
|
||||
'status' => 'good',
|
||||
'badge' => array(
|
||||
'label' => __( 'Security', 'jetpack-protect' ),
|
||||
@ -71,25 +71,25 @@ class Site_Health {
|
||||
),
|
||||
'description' => sprintf(
|
||||
'<p>%s</p>',
|
||||
__( 'Jetpack Protect did not find any known vulnerabilities in your site. Vulnerabilities can be exploited by hackers and cause harm to your website.', 'jetpack-protect' )
|
||||
__( 'Jetpack Protect did not find any known threats in your site. Threats can be exploited by hackers and cause harm to your website.', 'jetpack-protect' )
|
||||
),
|
||||
'actions' => '',
|
||||
'test' => 'jetpack_protect_checks',
|
||||
);
|
||||
|
||||
/**
|
||||
* If vulnerabilities found.
|
||||
* If threats found.
|
||||
*/
|
||||
if ( $total_vuls ) {
|
||||
if ( $total_threats ) {
|
||||
$result['status'] = 'critical';
|
||||
/* translators: $d is the number of vulnerabilities found. */
|
||||
$result['label'] = sprintf( _n( 'Your site is affected by %d security vulnerability', 'Your site is affected by %d security vulnerabilities', $total_vuls, 'jetpack-protect' ), $total_vuls );
|
||||
$result['description'] = __( 'Jetpack Protect detected the following security vulnerabilities in your site:', 'jetpack-protect' );
|
||||
/* translators: $d is the number of threats found. */
|
||||
$result['label'] = sprintf( _n( 'Your site is affected by %d security threat', 'Your site is affected by %d security threats', $total_threats, 'jetpack-protect' ), $total_threats );
|
||||
$result['description'] = __( 'Jetpack Protect detected the following security threats in your site:', 'jetpack-protect' );
|
||||
|
||||
foreach ( $vulns as $vuln ) {
|
||||
foreach ( $threats as $threat ) {
|
||||
$result['description'] .= '<p>';
|
||||
$result['description'] .= "<span class='dashicons dashicons-warning' style='color: crimson;'></span>  ";
|
||||
$result['description'] .= wp_kses( $vuln, array( 'a' => array( 'href' => array() ) ) ); // Only allow a href HTML tags.
|
||||
$result['description'] .= wp_kses( $threat, array( 'a' => array( 'href' => array() ) ) ); // Only allow a href HTML tags.
|
||||
$result['description'] .= '</p>';
|
||||
}
|
||||
$result['description'] .= '<p>';
|
||||
|
@ -7,38 +7,23 @@
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Sync\Functions as Sync_Functions;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class that handles fetching and caching the Status of vulnerabilities check from the WPCOM servers
|
||||
*/
|
||||
class Status {
|
||||
|
||||
/**
|
||||
* WPCOM endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const REST_API_BASE = '/sites/%d/jetpack-protect-status';
|
||||
|
||||
/**
|
||||
* Name of the option where status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_NAME = 'jetpack_protect_status';
|
||||
const OPTION_NAME = '';
|
||||
|
||||
/**
|
||||
* Name of the option where the timestamp of the status is stored
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const OPTION_TIMESTAMP_NAME = 'jetpack_protect_status_time';
|
||||
const OPTION_TIMESTAMP_NAME = '';
|
||||
|
||||
/**
|
||||
* Time in seconds that the cache should last
|
||||
@ -57,121 +42,31 @@ class Status {
|
||||
/**
|
||||
* Memoization for the current status
|
||||
*
|
||||
* @var null|array
|
||||
* @var null|Status_Model
|
||||
*/
|
||||
public static $status = null;
|
||||
|
||||
/**
|
||||
* Gets the current status of the Jetpack Protect checks
|
||||
*
|
||||
* @return array
|
||||
* @param bool $refresh_from_wpcom Refresh the local plan and status cache from wpcom.
|
||||
* @return Status_Model
|
||||
*/
|
||||
public static function get_status() {
|
||||
if ( self::$status !== null ) {
|
||||
return self::$status;
|
||||
}
|
||||
public static function get_status( $refresh_from_wpcom = false ) {
|
||||
$use_scan_status = Plan::has_required_plan();
|
||||
|
||||
if ( ! self::should_use_cache() || self::is_cache_expired() ) {
|
||||
$status = self::fetch_from_server();
|
||||
} else {
|
||||
$status = self::get_from_options();
|
||||
}
|
||||
if ( defined( 'JETPACK_PROTECT_DEV__DATA_SOURCE' ) ) {
|
||||
if ( 'scan_api' === JETPACK_PROTECT_DEV__DATA_SOURCE ) {
|
||||
$use_scan_status = true;
|
||||
}
|
||||
|
||||
if ( is_wp_error( $status ) ) {
|
||||
$status = array(
|
||||
'error' => true,
|
||||
'error_code' => $status->get_error_code(),
|
||||
'error_message' => $status->get_error_message(),
|
||||
);
|
||||
} else {
|
||||
$status = self::normalize_report_data( $status );
|
||||
}
|
||||
|
||||
self::$status = $status;
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the current status to see if there are any vulnerabilities found
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_vulnerabilities() {
|
||||
return 0 < self::get_total_vulnerabilities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total number of vulnerabilities found
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function get_total_vulnerabilities() {
|
||||
$status = self::get_status();
|
||||
return isset( $status->num_vulnerabilities ) && is_int( $status->num_vulnerabilities ) ? $status->num_vulnerabilities : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all vulnerabilities combined
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_vulnerabilities() {
|
||||
return array_merge(
|
||||
self::get_wordpress_vulnerabilities(),
|
||||
self::get_themes_vulnerabilities(),
|
||||
self::get_plugins_vulnerabilities()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vulnerabilities found for WordPress core
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_wordpress_vulnerabilities() {
|
||||
return self::get_vulnerabilities( 'core' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vulnerabilities found for themes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_themes_vulnerabilities() {
|
||||
return self::get_vulnerabilities( 'themes' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get vulnerabilities found for plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_plugins_vulnerabilities() {
|
||||
return self::get_vulnerabilities( 'plugins' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the vulnerabilities for one type of extension or core
|
||||
*
|
||||
* @param string $type What vulnerabilities you want to get. Possible values are 'core', 'themes' and 'plugins'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_vulnerabilities( $type ) {
|
||||
$status = self::get_status();
|
||||
if ( 'core' === $type ) {
|
||||
return isset( $status->$type ) && ! empty( $status->$type->vulnerabilities ) ? $status->$type->vulnerabilities : array();
|
||||
}
|
||||
|
||||
$vuls = array();
|
||||
if ( isset( $status->$type ) ) {
|
||||
foreach ( (array) $status->$type as $item ) {
|
||||
if ( ! empty( $item->vulnerabilities ) ) {
|
||||
$vuls = array_merge( $vuls, $item->vulnerabilities );
|
||||
}
|
||||
if ( 'protect_report' === JETPACK_PROTECT_DEV__DATA_SOURCE ) {
|
||||
$use_scan_status = false;
|
||||
}
|
||||
}
|
||||
return $vuls;
|
||||
|
||||
self::$status = $use_scan_status ? Scan_Status::get_status( $refresh_from_wpcom ) : Protect_Status::get_status( $refresh_from_wpcom );
|
||||
return self::$status;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -180,7 +75,7 @@ class Status {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_cache_expired() {
|
||||
$option_timestamp = get_option( self::OPTION_TIMESTAMP_NAME );
|
||||
$option_timestamp = get_option( static::OPTION_TIMESTAMP_NAME );
|
||||
|
||||
if ( ! $option_timestamp ) {
|
||||
return true;
|
||||
@ -198,61 +93,13 @@ class Status {
|
||||
return defined( 'JETPACK_PROTECT_DEV__BYPASS_CACHE' ) && JETPACK_PROTECT_DEV__BYPASS_CACHE ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the WPCOM API endpoint
|
||||
*
|
||||
* @return WP_Error|string
|
||||
*/
|
||||
public static function get_api_url() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return new WP_Error( 'site_not_connected' );
|
||||
}
|
||||
|
||||
$api_url = sprintf( self::REST_API_BASE, $blog_id );
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the status from WPCOM servers
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
public static function fetch_from_server() {
|
||||
$api_url = self::get_api_url();
|
||||
if ( is_wp_error( $api_url ) ) {
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
self::get_api_url(),
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code || empty( $response['body'] ) ) {
|
||||
return new WP_Error( 'failed_fetching_status', 'Failed to fetch Protect Status data from server', array( 'status' => $response_code ) );
|
||||
}
|
||||
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
self::update_option( $body );
|
||||
return $body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current cached status
|
||||
*
|
||||
* @return bool|array False if value is not found. Array with values if cache is found.
|
||||
*/
|
||||
public static function get_from_options() {
|
||||
return get_option( self::OPTION_NAME );
|
||||
return maybe_unserialize( get_option( static::OPTION_NAME ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -263,9 +110,9 @@ class Status {
|
||||
*/
|
||||
public static function update_option( $status ) {
|
||||
// TODO: Sanitize $status.
|
||||
update_option( self::OPTION_NAME, $status );
|
||||
update_option( static::OPTION_NAME, $status );
|
||||
$end_date = self::get_cache_end_date_by_status( $status );
|
||||
update_option( self::OPTION_TIMESTAMP_NAME, $end_date );
|
||||
update_option( static::OPTION_TIMESTAMP_NAME, $end_date );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -278,94 +125,175 @@ class Status {
|
||||
*/
|
||||
public static function get_cache_end_date_by_status( $status ) {
|
||||
if ( ! is_object( $status ) || empty( $status->last_checked ) ) {
|
||||
return time() + self::INITIAL_OPTION_EXPIRES_AFTER;
|
||||
return time() + static::INITIAL_OPTION_EXPIRES_AFTER;
|
||||
}
|
||||
return time() + self::OPTION_EXPIRES_AFTER;
|
||||
return time() + static::OPTION_EXPIRES_AFTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the cached status and its timestamp
|
||||
*
|
||||
* @return void
|
||||
* @return bool Whether all related status options were successfully deleted.
|
||||
*/
|
||||
public static function delete_option() {
|
||||
delete_option( self::OPTION_NAME );
|
||||
delete_option( self::OPTION_TIMESTAMP_NAME );
|
||||
$option_deleted = delete_option( static::OPTION_NAME );
|
||||
$option_timestamp_deleted = delete_option( static::OPTION_TIMESTAMP_NAME );
|
||||
|
||||
return $option_deleted && $option_timestamp_deleted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the report data for the UI
|
||||
* Checks the current status to see if there are any threats found
|
||||
*
|
||||
* @param string $report_data The report status report response.
|
||||
* @return object The normalized report data.
|
||||
* @return boolean
|
||||
*/
|
||||
private static function normalize_report_data( $report_data ) {
|
||||
$installed_plugins = Plugins_Installer::get_plugins();
|
||||
$last_report_plugins = isset( $report_data->plugins ) ? $report_data->plugins : new \stdClass();
|
||||
$report_data->plugins = self::merge_installed_and_checked_lists( $installed_plugins, $last_report_plugins, array( 'type' => 'plugin' ) );
|
||||
public static function has_threats() {
|
||||
return 0 < self::get_total_threats();
|
||||
}
|
||||
|
||||
$installed_themes = Sync_Functions::get_themes();
|
||||
$last_report_themes = isset( $report_data->themes ) ? $report_data->themes : new \stdClass();
|
||||
$report_data->themes = self::merge_installed_and_checked_lists( $installed_themes, $last_report_themes, array( 'type' => 'theme' ) );
|
||||
/**
|
||||
* Gets the total number of threats found
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public static function get_total_threats() {
|
||||
$status = static::get_status();
|
||||
return isset( $status->num_threats ) && is_int( $status->num_threats ) ? $status->num_threats : 0;
|
||||
}
|
||||
|
||||
$report_data->core = self::normalize_core_information( isset( $report_data->core ) ? $report_data->core : new \stdClass() );
|
||||
|
||||
$all_items = array_merge( $report_data->plugins, $report_data->themes, array( $report_data->core ) );
|
||||
$unchecked_items = array_filter(
|
||||
$all_items,
|
||||
function ( $item ) {
|
||||
return ! isset( $item->checked ) || ! $item->checked;
|
||||
}
|
||||
/**
|
||||
* Get all threats combined
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_all_threats() {
|
||||
return array_merge(
|
||||
self::get_wordpress_threats(),
|
||||
self::get_themes_threats(),
|
||||
self::get_plugins_threats(),
|
||||
self::get_files_threats(),
|
||||
self::get_database_threats()
|
||||
);
|
||||
// phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
$report_data->hasUncheckedItems = ! empty( $unchecked_items );
|
||||
|
||||
return $report_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges the list of installed extensions with the list of extensions that were checked for known vulnerabilities and return a normalized list to be used in the UI
|
||||
* Get threats found for WordPress core
|
||||
*
|
||||
* @param array $installed The list of installed extensions, where each attribute key is the extension slug.
|
||||
* @param array $checked The list of checked extensions.
|
||||
* @param array $append Additional data to append to each result in the list.
|
||||
* @return array Normalized list of extensions.
|
||||
* @return array
|
||||
*/
|
||||
private static function merge_installed_and_checked_lists( $installed, $checked, $append ) {
|
||||
$new_list = array();
|
||||
foreach ( $installed as $slug => $item ) {
|
||||
if ( isset( $checked->{ $slug } ) && $checked->{ $slug }->version === $installed[ $slug ]['Version'] ) {
|
||||
$new_list[] = (object) array_merge(
|
||||
array(
|
||||
'name' => $installed[ $slug ]['Name'],
|
||||
'version' => $checked->{ $slug }->version,
|
||||
'slug' => $slug,
|
||||
'vulnerabilities' => $checked->{ $slug }->vulnerabilities,
|
||||
'checked' => true,
|
||||
),
|
||||
$append
|
||||
);
|
||||
} else {
|
||||
$new_list[] = (object) array_merge(
|
||||
array(
|
||||
'name' => $installed[ $slug ]['Name'],
|
||||
'version' => $installed[ $slug ]['Version'],
|
||||
'slug' => $slug,
|
||||
'vulnerabilities' => array(),
|
||||
'checked' => false,
|
||||
),
|
||||
$append
|
||||
);
|
||||
public static function get_wordpress_threats() {
|
||||
return self::get_threats( 'core' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get threats found for themes
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_themes_threats() {
|
||||
return self::get_threats( 'themes' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get threats found for plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_plugins_threats() {
|
||||
return self::get_threats( 'plugins' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get threats found for files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_files_threats() {
|
||||
return self::get_threats( 'files' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get threats found for plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_database_threats() {
|
||||
return self::get_threats( 'database' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the threats for one type of extension or core
|
||||
*
|
||||
* @param string $type What threats you want to get. Possible values are 'core', 'themes' and 'plugins'.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_threats( $type ) {
|
||||
$status = static::get_status();
|
||||
|
||||
if ( 'core' === $type ) {
|
||||
return isset( $status->$type ) && ! empty( $status->$type->threats ) ? $status->$type->threats : array();
|
||||
}
|
||||
|
||||
if ( 'files' === $type || 'database' === $type ) {
|
||||
return isset( $status->$type ) && ! empty( $status->$type ) ? $status->$type : array();
|
||||
}
|
||||
|
||||
$threats = array();
|
||||
if ( isset( $status->$type ) ) {
|
||||
foreach ( (array) $status->$type as $item ) {
|
||||
if ( ! empty( $item->threats ) ) {
|
||||
$threats = array_merge( $threats, $item->threats );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $threats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the WordPress version that was checked matches the current installed version.
|
||||
*
|
||||
* @param object $core_check The object returned by Protect wpcom endpoint.
|
||||
* @return object The object representing the current status of core checks.
|
||||
*/
|
||||
protected static function normalize_core_information( $core_check ) {
|
||||
global $wp_version;
|
||||
|
||||
$core = new Extension_Model(
|
||||
array(
|
||||
'type' => 'core',
|
||||
'name' => 'WordPress',
|
||||
'version' => $wp_version,
|
||||
'checked' => false,
|
||||
)
|
||||
);
|
||||
|
||||
if ( isset( $core_check->version ) && $core_check->version === $wp_version ) {
|
||||
if ( is_array( $core_check->vulnerabilities ) ) {
|
||||
$core->checked = true;
|
||||
$core->set_threats( $core_check->vulnerabilities );
|
||||
}
|
||||
}
|
||||
|
||||
return $core;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort By Threats
|
||||
*
|
||||
* @param array<object> $threats Array of threats to sort.
|
||||
*
|
||||
* @return array<object> The sorted $threats array.
|
||||
*/
|
||||
protected static function sort_threats( $threats ) {
|
||||
usort(
|
||||
$new_list,
|
||||
$threats,
|
||||
function ( $a, $b ) {
|
||||
// sort primarily based on the presence of vulnerabilities
|
||||
if ( ! empty( $a->vulnerabilities ) && empty( $b->vulnerabilities ) ) {
|
||||
// sort primarily based on the presence of threats
|
||||
if ( ! empty( $a->threats ) && empty( $b->threats ) ) {
|
||||
return -1;
|
||||
}
|
||||
if ( empty( $a->vulnerabilities ) && ! empty( $b->vulnerabilities ) ) {
|
||||
if ( empty( $a->threats ) && ! empty( $b->threats ) ) {
|
||||
return 1;
|
||||
}
|
||||
// sort secondarily on whether the item has been checked
|
||||
@ -379,31 +307,8 @@ class Status {
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
return $new_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the WordPress version that was checked matches the current installed version.
|
||||
*
|
||||
* @param object $core_check The object returned by Protect wpcom endpoint.
|
||||
* @return object The object representing the current status of core checks.
|
||||
*/
|
||||
private static function normalize_core_information( $core_check ) {
|
||||
global $wp_version;
|
||||
|
||||
$core = new \stdClass();
|
||||
if ( isset( $core_check->version ) && $core_check->version === $wp_version ) {
|
||||
$core = $core_check;
|
||||
$core->name = 'WordPress';
|
||||
$core->type = 'core';
|
||||
} else {
|
||||
$core->version = $wp_version;
|
||||
$core->vulnerabilities = array();
|
||||
$core->checked = false;
|
||||
$core->name = 'WordPress';
|
||||
$core->type = 'core';
|
||||
}
|
||||
return $core;
|
||||
return $threats;
|
||||
}
|
||||
|
||||
}
|
||||
|
203
wp-content/plugins/jetpack-protect/src/class-threats.php
Normal file
203
wp-content/plugins/jetpack-protect/src/class-threats.php
Normal file
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Class to handle Threats
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class that handles management of individual threats.
|
||||
*/
|
||||
class Threats {
|
||||
/**
|
||||
* Gets the base "Alerts" (Threats) endpoint.
|
||||
*
|
||||
* @return WP_Error|string
|
||||
*/
|
||||
private static function get_api_base() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return new WP_Error( 'site_not_connected' );
|
||||
}
|
||||
|
||||
$api_url = sprintf( '/sites/%d/alerts', $blog_id );
|
||||
|
||||
return $api_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Threat
|
||||
*
|
||||
* @param string $threat_id The threat ID.
|
||||
* @param array $updates The keys/values to update.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function update_threat( $threat_id, $updates ) {
|
||||
$api_base = self::get_api_base( $threat_id );
|
||||
if ( is_wp_error( $api_base ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_user(
|
||||
"$api_base/$threat_id",
|
||||
'2',
|
||||
array( 'method' => 'POST' ),
|
||||
wp_json_encode( $updates ),
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear the now out-of-date cache
|
||||
Scan_Status::delete_option();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ignore Threat
|
||||
*
|
||||
* @param string $threat_id The threat ID.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function ignore_threat( $threat_id ) {
|
||||
return self::update_threat( $threat_id, array( 'ignore' => true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix Threats
|
||||
*
|
||||
* @param array<string> $threat_ids Threat IDs.
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function fix_threats( $threat_ids ) {
|
||||
$api_base = self::get_api_base();
|
||||
if ( is_wp_error( $api_base ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_user(
|
||||
"$api_base/fix",
|
||||
'2',
|
||||
array( 'method' => 'POST' ),
|
||||
wp_json_encode(
|
||||
array(
|
||||
'threat_ids' => $threat_ids,
|
||||
)
|
||||
),
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear the now out-of-date cache
|
||||
Scan_Status::delete_option();
|
||||
|
||||
$parsed_response = json_decode( $response['body'] );
|
||||
|
||||
if ( ! $parsed_response ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $parsed_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix Threats Status
|
||||
*
|
||||
* @param array<string> $threat_ids Threat IDs.
|
||||
*
|
||||
* @return bool|array
|
||||
*/
|
||||
public static function fix_threats_status( $threat_ids ) {
|
||||
$api_base = self::get_api_base();
|
||||
if ( is_wp_error( $api_base ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_user(
|
||||
add_query_arg( 'threat_ids', $threat_ids, "$api_base/fix" ),
|
||||
'2',
|
||||
array( 'method' => 'GET' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$parsed_response = json_decode( $response['body'] );
|
||||
|
||||
if ( ! $parsed_response ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear the potentially out-of-date cache
|
||||
Scan_Status::delete_option();
|
||||
|
||||
return $parsed_response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan enqueue
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function scan() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
$is_connected = ( new Connection_Manager() )->is_connected();
|
||||
|
||||
if ( ! $blog_id || ! $is_connected ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$api_base = sprintf( '/sites/%d/scan', $blog_id );
|
||||
|
||||
if ( is_wp_error( $api_base ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
"$api_base/enqueue",
|
||||
'2',
|
||||
array( 'method' => 'POST' ),
|
||||
null,
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// clear the now out-of-date cache
|
||||
Scan_Status::delete_option();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
<?php
|
||||
/**
|
||||
* Model class for extensions.
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
/**
|
||||
* Model class for extension data.
|
||||
*/
|
||||
class Extension_Model {
|
||||
|
||||
/**
|
||||
* The extension name.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* The extension slug.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $slug;
|
||||
|
||||
/**
|
||||
* The extension version.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $version;
|
||||
|
||||
/**
|
||||
* A collection of threats related to this version of the extension.
|
||||
*
|
||||
* @var array<Threat_Model>
|
||||
*/
|
||||
public $threats = array();
|
||||
|
||||
/**
|
||||
* Whether the extension has been checked for threats.
|
||||
*
|
||||
* @var null|bool
|
||||
*/
|
||||
public $checked;
|
||||
|
||||
/**
|
||||
* The type of extension ("plugins", "themes", or "core").
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* Extension Model Constructor
|
||||
*
|
||||
* @param array|object $extension Extension data to load into the model instance.
|
||||
*/
|
||||
public function __construct( $extension = array() ) {
|
||||
if ( is_object( $extension ) ) {
|
||||
$extension = (array) $extension;
|
||||
}
|
||||
|
||||
foreach ( $extension as $property => $value ) {
|
||||
if ( property_exists( $this, $property ) ) {
|
||||
// use the property's setter method when possible
|
||||
if ( method_exists( $this, "set_$property" ) ) {
|
||||
$this->{ "set_$property" }( $value );
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise, map the value directly into the class property
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Threats
|
||||
*
|
||||
* @param array<Threat_Model|array|object> $threats An array of threat data to add to the extension.
|
||||
*/
|
||||
public function set_threats( $threats ) {
|
||||
if ( ! is_array( $threats ) ) {
|
||||
$this->threats = array();
|
||||
return;
|
||||
}
|
||||
|
||||
// convert each provided threat item into an instance of Threat_Model
|
||||
$threats = array_map(
|
||||
function ( $threat ) {
|
||||
if ( is_a( $threat, 'Threat_Model' ) ) {
|
||||
return $threat;
|
||||
}
|
||||
|
||||
if ( is_object( $threat ) ) {
|
||||
$threat = (array) $threat;
|
||||
}
|
||||
|
||||
return new Threat_Model( $threat );
|
||||
},
|
||||
$threats
|
||||
);
|
||||
|
||||
$this->threats = $threats;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* Model class for Protect status report data.
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
/**
|
||||
* Model class for the Protect status report data.
|
||||
*/
|
||||
class Status_Model {
|
||||
/**
|
||||
* Data source.
|
||||
*
|
||||
* @var string protect_report|scan_api
|
||||
*/
|
||||
public $data_source;
|
||||
|
||||
/**
|
||||
* The date and time when the status was generated.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $last_checked;
|
||||
|
||||
/**
|
||||
* The number of threats.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $num_threats;
|
||||
|
||||
/**
|
||||
* The number of plugin threats.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $num_plugins_threats;
|
||||
|
||||
/**
|
||||
* The number of theme threats.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public $num_themes_threats;
|
||||
|
||||
/**
|
||||
* The current report status.
|
||||
*
|
||||
* @var string in_progress|scheduled|idle|scanning|provisioning|unavailable
|
||||
*/
|
||||
public $status;
|
||||
|
||||
/**
|
||||
* WordPress core status.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public $core;
|
||||
|
||||
/**
|
||||
* Status themes.
|
||||
*
|
||||
* @var array<Extension_Model>
|
||||
*/
|
||||
public $themes = array();
|
||||
|
||||
/**
|
||||
* Status plugins.
|
||||
*
|
||||
* @var array<Extension_Model>
|
||||
*/
|
||||
public $plugins = array();
|
||||
|
||||
/**
|
||||
* File threats.
|
||||
*
|
||||
* @var array<Extension_Model>
|
||||
*/
|
||||
public $files = array();
|
||||
|
||||
/**
|
||||
* Database threats.
|
||||
*
|
||||
* @var array<Extension_Model>
|
||||
*/
|
||||
public $database = array();
|
||||
|
||||
/**
|
||||
* Whether the site includes items that have not been checked.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $has_unchecked_items;
|
||||
|
||||
/**
|
||||
* Whether there was an error loading the status.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $error = false;
|
||||
|
||||
/**
|
||||
* The error code thrown when loading the status.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $error_code;
|
||||
|
||||
/**
|
||||
* The error message thrown when loading the status.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $error_message;
|
||||
|
||||
/**
|
||||
* Status constructor.
|
||||
*
|
||||
* @param array $status The status data to load into the class instance.
|
||||
*/
|
||||
public function __construct( $status = array() ) {
|
||||
// set status defaults
|
||||
$this->core = new \stdClass();
|
||||
|
||||
foreach ( $status as $property => $value ) {
|
||||
if ( property_exists( $this, $property ) ) {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* Model class for threat data.
|
||||
*
|
||||
* @package automattic/jetpack-protect-plugin
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Protect;
|
||||
|
||||
/**
|
||||
* Model class for threat data.
|
||||
*/
|
||||
class Threat_Model {
|
||||
|
||||
/**
|
||||
* Threat ID.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $id;
|
||||
|
||||
/**
|
||||
* Threat Signature.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $signature;
|
||||
|
||||
/**
|
||||
* Threat Title.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $title;
|
||||
|
||||
/**
|
||||
* Threat Description.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $description;
|
||||
|
||||
/**
|
||||
* The data the threat was first detected.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $first_detected;
|
||||
|
||||
/**
|
||||
* The version the threat is fixed in.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $fixed_in;
|
||||
|
||||
/**
|
||||
* The severity of the threat between 1-5.
|
||||
*
|
||||
* @var null|int
|
||||
*/
|
||||
public $severity;
|
||||
|
||||
/**
|
||||
* Information about the auto-fix available for this threat. False when not auto-fixable.
|
||||
*
|
||||
* @var null|bool|object
|
||||
*/
|
||||
public $fixable;
|
||||
|
||||
/**
|
||||
* The current status of the threat.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $status;
|
||||
|
||||
/**
|
||||
* The filename of the threat.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* The context of the threat.
|
||||
*
|
||||
* @var null|object
|
||||
*/
|
||||
public $context;
|
||||
|
||||
/**
|
||||
* The source URL of the threat.
|
||||
*
|
||||
* @var null|string
|
||||
*/
|
||||
public $source;
|
||||
|
||||
/**
|
||||
* Threat Constructor
|
||||
*
|
||||
* @param array|object $threat Threat data to load into the class instance.
|
||||
*/
|
||||
public function __construct( $threat ) {
|
||||
if ( is_object( $threat ) ) {
|
||||
$threat = (array) $threat;
|
||||
}
|
||||
|
||||
foreach ( $threat as $property => $value ) {
|
||||
if ( property_exists( $this, $property ) ) {
|
||||
$this->$property = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -9,4 +9,4 @@ if (PHP_VERSION_ID < 50600) {
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInitc4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_0_4::getLoader();
|
||||
return ComposerAutoloaderInitc4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_1_0::getLoader();
|
||||
|
@ -5,7 +5,7 @@
|
||||
* @package automattic/jetpack-autoloader
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\Autoloader\jpc4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_0_4;
|
||||
namespace Automattic\Jetpack\Autoloader\jpc4802e05bbcf59fd3b6350e8d3e5482c_protectⓥ1_1_0;
|
||||
|
||||
// phpcs:ignore
|
||||
|
||||
|
69
wp-content/plugins/jetpack-protect/vendor/automattic/jetpack-plans/CHANGELOG.md
vendored
Normal file
69
wp-content/plugins/jetpack-protect/vendor/automattic/jetpack-plans/CHANGELOG.md
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
# Changelog
|
||||
|
||||
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/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.2.6] - 2022-11-07
|
||||
### Changed
|
||||
- Updated package dependencies. [#27278]
|
||||
|
||||
## [0.2.5] - 2022-10-25
|
||||
### Changed
|
||||
- Updated package dependencies. [#26705]
|
||||
|
||||
## [0.2.4] - 2022-09-20
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.2.3] - 2022-09-08
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## [0.2.2] - 2022-08-30
|
||||
### Changed
|
||||
- Updated package dependencies. [#25694]
|
||||
|
||||
## [0.2.1] - 2022-08-23
|
||||
### Changed
|
||||
- Updated package dependencies. [#25628]
|
||||
|
||||
## [0.2.0] - 2022-08-16
|
||||
### Added
|
||||
- Tweaked the supports method of the plans package to refresh the plan data. [#25347]
|
||||
|
||||
## [0.1.3] - 2022-08-03
|
||||
### Changed
|
||||
- Updated package dependencies. [#25300, #25315]
|
||||
|
||||
## [0.1.2] - 2022-07-26
|
||||
### Changed
|
||||
- Add mirror repository information to package info. [#25142]
|
||||
- Updated package dependencies. [#25158]
|
||||
|
||||
## 0.1.1 - 2022-07-19
|
||||
### Changed
|
||||
- Updated package dependencies.
|
||||
|
||||
## 0.1.0 - 2022-07-06
|
||||
### Added
|
||||
- Add support for WordPress.com Starter plan. [#24496]
|
||||
- Package created. [#23503]
|
||||
|
||||
### Changed
|
||||
- Renaming master to trunk. [#24661]
|
||||
- Updated package dependencies.
|
||||
|
||||
### Deprecated
|
||||
- Moved the options class into Connection. [#24095]
|
||||
|
||||
[0.2.6]: https://github.com/Automattic/jetpack-plans/compare/v0.2.5...v0.2.6
|
||||
[0.2.5]: https://github.com/Automattic/jetpack-plans/compare/v0.2.4...v0.2.5
|
||||
[0.2.4]: https://github.com/Automattic/jetpack-plans/compare/v0.2.3...v0.2.4
|
||||
[0.2.3]: https://github.com/Automattic/jetpack-plans/compare/v0.2.2...v0.2.3
|
||||
[0.2.2]: https://github.com/Automattic/jetpack-plans/compare/v0.2.1...v0.2.2
|
||||
[0.2.1]: https://github.com/Automattic/jetpack-plans/compare/v0.2.0...v0.2.1
|
||||
[0.2.0]: https://github.com/Automattic/jetpack-plans/compare/v0.1.3...v0.2.0
|
||||
[0.1.3]: https://github.com/Automattic/jetpack-plans/compare/v0.1.2...v0.1.3
|
||||
[0.1.2]: https://github.com/Automattic/jetpack-plans/compare/v0.1.1...v0.1.2
|
357
wp-content/plugins/jetpack-protect/vendor/automattic/jetpack-plans/LICENSE.txt
vendored
Normal file
357
wp-content/plugins/jetpack-protect/vendor/automattic/jetpack-plans/LICENSE.txt
vendored
Normal file
@ -0,0 +1,357 @@
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
|
||||
===================================
|
||||
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user