updated plugin Jetpack Protect
version 1.4.2
This commit is contained in:
@ -5,6 +5,294 @@ 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).
|
||||
|
||||
## [3.9.1] - 2023-10-19
|
||||
### Changed
|
||||
- Make has_required_plan return true (as it was before #33410) as a way to revert the change. [#33697]
|
||||
- Updated package dependencies. [#33687]
|
||||
|
||||
## [3.9.0] - 2023-10-17
|
||||
### Added
|
||||
- Add has_required_plan method for VideoPress product class, check plan purchase exists for site [#33410]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#33646]
|
||||
|
||||
## [3.8.2] - 2023-10-16
|
||||
### Changed
|
||||
- Updated package dependencies. [#33429, #33584]
|
||||
|
||||
## [3.8.1] - 2023-10-10
|
||||
### Changed
|
||||
- Changes title of the my-jetpack page to "My Jetpack" [#33486]
|
||||
- Updated package dependencies. [#33428]
|
||||
|
||||
### Fixed
|
||||
- My Jetpack: fix fatal error [#33523]
|
||||
- My Jetpack: fix Stats card status when not connected [#33521]
|
||||
|
||||
## [3.8.0] - 2023-10-03
|
||||
### Added
|
||||
- Display a new section on My Jetpack to display the stats of the site. [#33283]
|
||||
|
||||
## [3.7.0] - 2023-09-28
|
||||
### Added
|
||||
- Add a section to display stats from Jetpack Stats in My Jetpack [#33160]
|
||||
|
||||
### Changed
|
||||
- Redirect to a proper upgrade page for free license owners [#33297]
|
||||
|
||||
## [3.6.0] - 2023-09-25
|
||||
### Added
|
||||
- Add barebones infrastructure for querying jetpack product data. [#33095]
|
||||
|
||||
### Changed
|
||||
- Stats: link to purchase page within WP Admin. [#33227]
|
||||
|
||||
## [3.5.0] - 2023-09-19
|
||||
### Changed
|
||||
- Added support for upgradable products. Updated the Stats card to handle upgradeable products. [#33058]
|
||||
- Updated Jetpack submenu sort order so individual features are alpha-sorted. [#32958]
|
||||
|
||||
### Fixed
|
||||
- My Jetpack: Add AI Assistant Monthly to required plan check [#33078]
|
||||
|
||||
## [3.4.5] - 2023-09-13
|
||||
### Changed
|
||||
- Updated package dependencies. [#33001]
|
||||
|
||||
## [3.4.4] - 2023-09-11
|
||||
### Changed
|
||||
- General: remove WP 6.1 backwards compatibility checks [#32772]
|
||||
|
||||
### Fixed
|
||||
- Stats: stop showing upgrade button for sites with Complete plan [#32870]
|
||||
|
||||
## [3.4.3] - 2023-09-04
|
||||
### Changed
|
||||
- Updated package dependencies. [#32803]
|
||||
- Updated package dependencies. [#32804]
|
||||
|
||||
## [3.4.2] - 2023-08-23
|
||||
### Changed
|
||||
- Updated package dependencies. [#32605]
|
||||
|
||||
## [3.4.1] - 2023-08-22
|
||||
### Changed
|
||||
- Connection: allow dismissing the IDC modal. [#32594]
|
||||
|
||||
## [3.4.0] - 2023-08-21
|
||||
### Added
|
||||
- Support Jetpack AI Yearly offering [#32130]
|
||||
|
||||
### Changed
|
||||
- Use the new method to render Connection initial state. [#32499]
|
||||
|
||||
## [3.3.3] - 2023-08-14
|
||||
### Added
|
||||
- Make My Jetpack the default WP-Admin page for Jetpack. [#32385]
|
||||
|
||||
### Changed
|
||||
- Start showing My Jetpack for authors, editors, and contributors [#32420]
|
||||
|
||||
## [3.3.2] - 2023-08-09
|
||||
### Fixed
|
||||
- Revert My Jetpack as first menu item. [#32384]
|
||||
|
||||
## [3.3.1] - 2023-08-09
|
||||
### Changed
|
||||
- Updated package dependencies. [#32166]
|
||||
|
||||
## [3.3.0] - 2023-08-07
|
||||
### Added
|
||||
- Add Identity Crisis screen modal. [#32249]
|
||||
|
||||
### Changed
|
||||
- Move 'My Jetpack' sub-menu item to first position. [#32240]
|
||||
|
||||
### Fixed
|
||||
- Fix IDC modal height issue. [#32316]
|
||||
|
||||
## [3.2.1] - 2023-08-01
|
||||
### Added
|
||||
- Add transient caching for zendesk jwt auth token. [#32140]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Rename the namespace of the JWT endpoint, and register it only when it isn't already registered [#32081]
|
||||
|
||||
## [3.2.0] - 2023-07-25
|
||||
### Added
|
||||
- My Jetpack: register jetpack-ai-jwt endpoint [#31965]
|
||||
- My Jetpack: release Paid Stats to the public [#32020]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: changed Stats features wording [#32046]
|
||||
- Updated package dependencies. [#31999]
|
||||
- Updated package dependencies. [#32040]
|
||||
|
||||
### Fixed
|
||||
- Make Jetpack logo in footer smaller [#31627]
|
||||
- My Jetpack: enabled Stats purchase flow returning to Stats Dashboard [#31959]
|
||||
|
||||
## [3.1.3] - 2023-07-17
|
||||
### Changed
|
||||
- Updated package dependencies. [#31872]
|
||||
|
||||
### Fixed
|
||||
- Hide connection owner information if the data is invalid
|
||||
- Don't suggest user connection if user is already connected, but connection owner is invalid [#31618]
|
||||
|
||||
## [3.1.2] - 2023-07-11
|
||||
### Changed
|
||||
- Updated package dependencies. [#31785]
|
||||
|
||||
## [3.1.1] - 2023-07-10
|
||||
### Fixed
|
||||
- Make product card primary buttons links when applicable [#31611]
|
||||
|
||||
## [3.1.0] - 2023-07-05
|
||||
### Added
|
||||
- Added Jetpack Stats card to My Jetpack [#31589]
|
||||
|
||||
### Changed
|
||||
- Jetpack Stats: Enable skipping interstitial page [#31629]
|
||||
- Updated package dependencies. [#31659]
|
||||
|
||||
### Fixed
|
||||
- My Jetpack: hide Stats card for standalone plugins [#31689]
|
||||
- Organize product cards in list [#31606]
|
||||
|
||||
## [3.0.0] - 2023-06-26
|
||||
### Added
|
||||
- Add authentication to Zendesk chat. [#31339]
|
||||
- Stats: add stats card to my Jetpack. [#31531]
|
||||
|
||||
## [2.15.0] - 2023-06-23
|
||||
### Added
|
||||
- My Jetpack: add Stats product [#31368]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#31468]
|
||||
|
||||
## [2.14.3] - 2023-06-12
|
||||
### Added
|
||||
- My Jetpack: populate the Jetpack AI product with feature data [#31238]
|
||||
|
||||
## [2.14.2] - 2023-06-06
|
||||
### Changed
|
||||
- Filter out revoked licenses from the license activation options. [#31088]
|
||||
- Updated package dependencies. [#31129]
|
||||
|
||||
## [2.14.1] - 2023-05-29
|
||||
### Added
|
||||
- My Jetpack: Add new Jetpack AI card [#30904]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Enable Jetpack AI card [#30988]
|
||||
- My Jetpack: Update AI class to be product and not module [#30905]
|
||||
- My Jetpack: Update AI interstitial background [#30992]
|
||||
|
||||
## [2.14.0] - 2023-05-22
|
||||
### Added
|
||||
- Added ability to purchase Jetpack AI monthly product [#30793]
|
||||
- Added tier data to the Boost product to support a pricing table interstitial page. [#29931]
|
||||
|
||||
## [2.13.0] - 2023-05-15
|
||||
### Added
|
||||
- Added My Jetpack interstitial for Jetpack AI [#30543]
|
||||
|
||||
## [2.12.2] - 2023-05-11
|
||||
### Changed
|
||||
- PHP 8.1 compatibility updates [#30517]
|
||||
|
||||
## [2.12.1] - 2023-05-08
|
||||
### Added
|
||||
- My Jetpack: Add deactivate plugin menu action on product card [#30489]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Remove icon from plugin activation action in product card [#30458]
|
||||
- My Jetpack: Remove manage option from menu [#30440]
|
||||
- My Jetpack: Remove product card icon [#30441]
|
||||
- My Jetpack: Set a post-checkout redirect destination on the "Purchase a plan" link. [#27693]
|
||||
|
||||
### Fixed
|
||||
- My Jetpack: Add check for product status before requesting stats [#30430]
|
||||
- My Jetpack: Reload page after successful license activation [#30364]
|
||||
- My Jetpack: Use a single column for the page title section [#30406]
|
||||
|
||||
## [2.12.0] - 2023-05-02
|
||||
### Added
|
||||
- Add API to query Zendesk chat availability and use it to conditionally display zendesk chat. [#29942]
|
||||
- Add pricing table interstitial view for Jetpack Protect. [#29930]
|
||||
- My Jetpack: Add product detail table component for comparing product tiers. [#29759]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Move logic out of Product Card component. [#30274]
|
||||
- Updated package dependencies.
|
||||
|
||||
### Fixed
|
||||
- Fix activation and layout on Protect interstatial page. [#29525]
|
||||
- My Jetpack: Keep product card action button disabled while installing standalone plugin. [#30346]
|
||||
|
||||
## [2.11.0] - 2023-05-01
|
||||
### Added
|
||||
- Added Jetpack Starter bundle post-activation screen and plan header [#30368]
|
||||
|
||||
## [2.10.3] - 2023-04-25
|
||||
### Added
|
||||
- My Jetpack: Add flags field in initial state [#30241]
|
||||
- My Jetpack: Add Install/Activate menu actions based on the standalone plugin status. [#30153]
|
||||
- My Jetpack: Add neutral color in contextual card [#30250]
|
||||
- My Jetpack: Add side-effect action to request the standalone plugin installation on the backend. [#30143]
|
||||
- My Jetpack: Add stats to VideoPress card [#30197]
|
||||
- My Jetpack: Enable menu for all hybrid products [#30247]
|
||||
- My Jetpack: Reload page after standalone action [#30221]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Connect the standalone plugin menu options so they trigger the installation and activation when clicked. [#30168]
|
||||
- MyJetpack: set the Social standalone page as the default admin one [#30193]
|
||||
- MyJetpack: Try to activate the product module after installing the standalone plugin [#30215]
|
||||
- Updated package dependencies. [#30015]
|
||||
|
||||
## [2.10.2] - 2023-04-17
|
||||
### Added
|
||||
- Ad missing TOS in Jetpack interstitial. [#29683]
|
||||
- My Jetpack: Add endpoint to install the standalone plugin for hybrid products. [#30045]
|
||||
- My Jetpack: Expose information about standalone plugin status on My Jetpack product initial state. [#29977]
|
||||
|
||||
### Changed
|
||||
- Backup and Scan: redirect after checkout to Jetpack recommendations page if Jetpack plugin is active. Otherwise, redirect back to plugin admin page. [#29708]
|
||||
- My Jetpack: Adjustments in Product Card [#30014]
|
||||
- Updated package dependencies. [#30019]
|
||||
|
||||
## [2.10.1] - 2023-04-10
|
||||
### Added
|
||||
- Add Jetpack Autoloader package suggestion. [#29988]
|
||||
- My Jetpack: Introduce absent_with_plan status [#29920]
|
||||
|
||||
### Changed
|
||||
- My Jetpack: Turn Search into a hybrid product to handle it as module and as standalone plugin. [#29946]
|
||||
- My Jetpack: Turn Social into a hybrid product to handle it as module and as standalone plugin. [#29935]
|
||||
- My Jetpack: Turn VaultPress Backup into a Hybrid product to handle it as module and as standalone plugin. [#29928]
|
||||
- My Jetpack: Turn VideoPress into a Hybrid product to handle it as module and as standalone plugin. [#29918]
|
||||
|
||||
## [2.10.0] - 2023-04-04
|
||||
### Added
|
||||
- My Jetpack: Adds a selector, reducer and resolver machinery to fetch product stats. [#29764]
|
||||
- My Jetpack: Enhance Product Card [#29787]
|
||||
- My Jetpack: Introduce menu in Product Card [#29815]
|
||||
|
||||
### Changed
|
||||
- * Updated add-anti-spam path to add-akismet to match the product key
|
||||
* Updated product interstitial component to accept an existingLicenseKeyUrl
|
||||
* Updated product interstitial component to display a product name instead of a title where preferProductName is set
|
||||
* Make is_plugin_active available from the API [#29598]
|
||||
- My Jetpack: Change the bottom of My Jetpack screen to use single-column rows on small viewports. [#29844]
|
||||
- Updated package dependencies. [#29854]
|
||||
|
||||
## [2.9.2] - 2023-04-03
|
||||
### Changed
|
||||
- Internal updates.
|
||||
|
||||
## [2.9.1] - 2023-03-28
|
||||
### Changed
|
||||
- Move GoldenTokenModal component to licensing package. [#29748]
|
||||
@ -781,6 +1069,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- Created package
|
||||
|
||||
[3.9.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.9.0...3.9.1
|
||||
[3.9.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.8.2...3.9.0
|
||||
[3.8.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.8.1...3.8.2
|
||||
[3.8.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.8.0...3.8.1
|
||||
[3.8.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.7.0...3.8.0
|
||||
[3.7.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.6.0...3.7.0
|
||||
[3.6.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.5.0...3.6.0
|
||||
[3.5.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.5...3.5.0
|
||||
[3.4.5]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.4...3.4.5
|
||||
[3.4.4]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.3...3.4.4
|
||||
[3.4.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.2...3.4.3
|
||||
[3.4.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.1...3.4.2
|
||||
[3.4.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.4.0...3.4.1
|
||||
[3.4.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.3.3...3.4.0
|
||||
[3.3.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.3.2...3.3.3
|
||||
[3.3.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.3.1...3.3.2
|
||||
[3.3.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.3.0...3.3.1
|
||||
[3.3.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.2.1...3.3.0
|
||||
[3.2.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.2.0...3.2.1
|
||||
[3.2.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.1.3...3.2.0
|
||||
[3.1.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.1.2...3.1.3
|
||||
[3.1.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.1.1...3.1.2
|
||||
[3.1.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.1.0...3.1.1
|
||||
[3.1.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/3.0.0...3.1.0
|
||||
[3.0.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.15.0...3.0.0
|
||||
[2.15.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.14.3...2.15.0
|
||||
[2.14.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.14.2...2.14.3
|
||||
[2.14.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.14.1...2.14.2
|
||||
[2.14.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.14.0...2.14.1
|
||||
[2.14.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.13.0...2.14.0
|
||||
[2.13.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.12.2...2.13.0
|
||||
[2.12.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.12.1...2.12.2
|
||||
[2.12.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.12.0...2.12.1
|
||||
[2.12.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.11.0...2.12.0
|
||||
[2.11.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.10.3...2.11.0
|
||||
[2.10.3]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.10.2...2.10.3
|
||||
[2.10.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.10.1...2.10.2
|
||||
[2.10.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.10.0...2.10.1
|
||||
[2.10.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.9.2...2.10.0
|
||||
[2.9.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.9.1...2.9.2
|
||||
[2.9.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.9.0...2.9.1
|
||||
[2.9.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.8.1...2.9.0
|
||||
[2.8.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.8.0...2.8.1
|
||||
[2.8.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/2.7.13...2.8.0
|
||||
|
@ -4,11 +4,20 @@ Full details of the Automattic Security Policy can be found on [automattic.com](
|
||||
|
||||
## 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.
|
||||
Generally, only the latest version of Jetpack and its associated plugins have continued support. If a critical vulnerability is found in the current version of a plugin, 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.
|
||||
Our HackerOne program covers the below plugin software, as well as a variety of related projects and infrastructure:
|
||||
|
||||
* [Jetpack](https://jetpack.com/)
|
||||
* Jetpack Backup
|
||||
* Jetpack Boost
|
||||
* Jetpack CRM
|
||||
* Jetpack Protect
|
||||
* Jetpack Search
|
||||
* Jetpack Social
|
||||
* Jetpack VideoPress
|
||||
|
||||
**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.**
|
||||
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '9fc14b80f5a467303947');
|
||||
<?php return array('dependencies' => array('react', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '86d713f826cd96de9db1');
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -7,9 +7,9 @@
|
||||
*/
|
||||
|
||||
/*!
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
Copyright (c) 2018 Jed Watson.
|
||||
Licensed under the MIT License (MIT), see
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/**
|
||||
|
File diff suppressed because one or more lines are too long
@ -4,20 +4,23 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-admin-ui": "^0.2.17",
|
||||
"automattic/jetpack-assets": "^1.17.34",
|
||||
"automattic/jetpack-connection": "^1.51.4",
|
||||
"automattic/jetpack-jitm": "^2.3.4",
|
||||
"automattic/jetpack-licensing": "^1.8.1",
|
||||
"automattic/jetpack-plugins-installer": "^0.2.3",
|
||||
"automattic/jetpack-redirect": "^1.7.24",
|
||||
"automattic/jetpack-constants": "^1.6.21"
|
||||
"automattic/jetpack-admin-ui": "^0.2.23",
|
||||
"automattic/jetpack-assets": "^1.18.13",
|
||||
"automattic/jetpack-connection": "^1.58.2",
|
||||
"automattic/jetpack-jitm": "^2.5.1",
|
||||
"automattic/jetpack-licensing": "^1.8.4",
|
||||
"automattic/jetpack-plugins-installer": "^0.2.5",
|
||||
"automattic/jetpack-redirect": "^1.7.27",
|
||||
"automattic/jetpack-constants": "^1.6.23"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "1.0.4",
|
||||
"automattic/jetpack-changelogger": "^3.3.2",
|
||||
"yoast/phpunit-polyfills": "1.1.0",
|
||||
"automattic/jetpack-changelogger": "^3.3.11",
|
||||
"automattic/wordbless": "@dev",
|
||||
"automattic/jetpack-videopress": "^0.13.4-alpha"
|
||||
"automattic/jetpack-videopress": "^0.18.0"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
@ -62,7 +65,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "2.9.x-dev"
|
||||
"dev-trunk": "3.9.x-dev"
|
||||
},
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-initializer.php"
|
||||
|
@ -9,14 +9,16 @@ namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Admin_UI\Admin_Menu;
|
||||
use Automattic\Jetpack\Assets;
|
||||
use Automattic\Jetpack\Connection\Client as Client;
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State;
|
||||
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\Constants as Jetpack_Constants;
|
||||
use Automattic\Jetpack\JITMS\JITM;
|
||||
use Automattic\Jetpack\Licensing;
|
||||
use Automattic\Jetpack\Modules;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Automattic\Jetpack\Status as Status;
|
||||
use Automattic\Jetpack\Status;
|
||||
use Automattic\Jetpack\Terms_Of_Service;
|
||||
use Automattic\Jetpack\Tracking;
|
||||
|
||||
@ -30,7 +32,12 @@ class Initializer {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PACKAGE_VERSION = '2.9.1';
|
||||
const PACKAGE_VERSION = '3.9.1';
|
||||
|
||||
/**
|
||||
* HTML container ID for the IDC screen on My Jetpack page.
|
||||
*/
|
||||
const IDC_CONTAINER_ID = 'my-jetpack-identity-crisis-container';
|
||||
|
||||
/**
|
||||
* Initialize My Jetpack
|
||||
@ -58,10 +65,10 @@ class Initializer {
|
||||
$page_suffix = Admin_Menu::add_menu(
|
||||
__( 'My Jetpack', 'jetpack-my-jetpack' ),
|
||||
__( 'My Jetpack', 'jetpack-my-jetpack' ),
|
||||
'manage_options',
|
||||
'edit_posts',
|
||||
'my-jetpack',
|
||||
array( __CLASS__, 'admin_page' ),
|
||||
999
|
||||
-1
|
||||
);
|
||||
|
||||
add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) );
|
||||
@ -116,6 +123,7 @@ class Initializer {
|
||||
* @return void
|
||||
*/
|
||||
public static function admin_init() {
|
||||
add_filter( 'identity_crisis_container_id', array( static::class, 'get_idc_container_id' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
|
||||
// Product statuses are constantly changing, so we never want to cache the page.
|
||||
header( 'Cache-Control: no-cache, no-store, must-revalidate' );
|
||||
@ -150,6 +158,7 @@ class Initializer {
|
||||
'textdomain' => 'jetpack-my-jetpack',
|
||||
)
|
||||
);
|
||||
$modules = new Modules();
|
||||
wp_localize_script(
|
||||
'my_jetpack_main_app',
|
||||
'myJetpackInitialState',
|
||||
@ -165,9 +174,13 @@ class Initializer {
|
||||
'topJetpackMenuItemUrl' => Admin_Menu::get_top_level_menu_item_url(),
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'myJetpackVersion' => self::PACKAGE_VERSION,
|
||||
'myJetpackFlags' => self::get_my_jetpack_flags(),
|
||||
'fileSystemWriteAccess' => self::has_file_system_write_access(),
|
||||
'loadAddLicenseScreen' => self::is_licensing_ui_enabled(),
|
||||
'adminUrl' => esc_url( admin_url() ),
|
||||
'IDCContainerID' => static::get_idc_container_id(),
|
||||
'userIsAdmin' => current_user_can( 'manage_options' ),
|
||||
'isStatsModuleActive' => $modules->is_active( 'stats' ),
|
||||
)
|
||||
);
|
||||
|
||||
@ -181,7 +194,7 @@ class Initializer {
|
||||
);
|
||||
|
||||
// Connection Initial State.
|
||||
wp_add_inline_script( 'my_jetpack_main_app', Connection_Initial_State::render(), 'before' );
|
||||
Connection_Initial_State::render_script( 'my_jetpack_main_app' );
|
||||
|
||||
// Required for Analytics.
|
||||
if ( self::can_use_analytics() ) {
|
||||
@ -189,6 +202,20 @@ class Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Build flags for My Jetpack UI
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_my_jetpack_flags() {
|
||||
$flags = array(
|
||||
'videoPressStats' => Jetpack_Constants::is_true( 'JETPACK_MY_JETPACK_VIDEOPRESS_STATS_ENABLED' ),
|
||||
'showJetpackStatsCard' => class_exists( 'Jetpack' ),
|
||||
);
|
||||
|
||||
return $flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Echoes the admin page content.
|
||||
*
|
||||
@ -206,6 +233,9 @@ class Initializer {
|
||||
public static function register_rest_endpoints() {
|
||||
new REST_Products();
|
||||
new REST_Purchases();
|
||||
new REST_Zendesk_Chat();
|
||||
new REST_Product_Data();
|
||||
new REST_AI();
|
||||
|
||||
register_rest_route(
|
||||
'my-jetpack/v1',
|
||||
@ -311,4 +341,12 @@ class Initializer {
|
||||
return $write_access;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get container IDC for the IDC screen.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_idc_container_id() {
|
||||
return static::IDC_CONTAINER_ID;
|
||||
}
|
||||
}
|
||||
|
@ -27,12 +27,14 @@ class Products {
|
||||
'boost' => Products\Boost::class,
|
||||
'crm' => Products\Crm::class,
|
||||
'extras' => Products\Extras::class,
|
||||
'jetpack-ai' => Products\Jetpack_Ai::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,
|
||||
'stats' => Products\Stats::class,
|
||||
);
|
||||
|
||||
/**
|
||||
@ -178,5 +180,4 @@ class Products {
|
||||
$class_name::extend_plugin_action_links();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* Sets up the AI REST API endpoints.
|
||||
*
|
||||
* @package automattic/my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Registers the REST routes for AI.
|
||||
*/
|
||||
class REST_AI {
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
/*
|
||||
* Check if the `jetpack/v4/jetpack-ai-jwt` endpoint is registered
|
||||
* by the Jetpack plugin to avoid registering it again.
|
||||
* In case it's not registered, register it
|
||||
* to make it available for Jetpack products that depend on it.
|
||||
*/
|
||||
if ( ! self::is_rest_endpoint_registered( 'jetpack/v4', '/jetpack-ai-jwt' ) ) {
|
||||
register_rest_route(
|
||||
'jetpack/v4',
|
||||
'jetpack-ai-jwt',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'callback' => __CLASS__ . '::get_openai_jwt',
|
||||
'permission_callback' => function () {
|
||||
return ( new Connection_Manager( 'jetpack' ) )->is_user_connected() && current_user_can( 'edit_posts' );
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific REST endpoint is registered.
|
||||
*
|
||||
* @param string $namespace - The namespace of the endpoint.
|
||||
* @param string $route - The route of the endpoint.
|
||||
* @return bool True if the endpoint is registered, false otherwise.
|
||||
*/
|
||||
public static function is_rest_endpoint_registered( $namespace, $route ) {
|
||||
$server = rest_get_server();
|
||||
$routes = $server->get_routes();
|
||||
$full_endpoint = '/' . trim( $namespace, '/' ) . $route;
|
||||
return isset( $routes[ $full_endpoint ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask WPCOM for a JWT token to use for OpenAI completion.
|
||||
*/
|
||||
public static function get_openai_jwt() {
|
||||
$blog_id = Jetpack_Options::get_option( 'id' );
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_user(
|
||||
"/sites/$blog_id/jetpack-openai-query/jwt",
|
||||
'2',
|
||||
array(
|
||||
'method' => 'POST',
|
||||
'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
|
||||
),
|
||||
wp_json_encode( array() ),
|
||||
'wpcom'
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$json = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
if ( ! isset( $json->token ) ) {
|
||||
return new WP_Error( 'no-token', 'No token returned from WPCOM' );
|
||||
}
|
||||
|
||||
return array(
|
||||
'token' => $json->token,
|
||||
'blog_id' => $blog_id,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/**
|
||||
* Sets up the Product Data REST API endpoints.
|
||||
*
|
||||
* @package automattic/my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Registers the REST routes for Product Data
|
||||
*/
|
||||
class REST_Product_Data {
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
register_rest_route(
|
||||
'my-jetpack/v1',
|
||||
'site/product-data',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => __CLASS__ . '::get_all_product_data',
|
||||
'permission_callback' => __CLASS__ . '::permissions_callback',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user has the correct permissions
|
||||
*/
|
||||
public static function permissions_callback() {
|
||||
return current_user_can( 'manage_options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the product data for all products
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public static function get_all_product_data() {
|
||||
$site_id = \Jetpack_Options::get_option( 'id' );
|
||||
$wpcom_endpoint = sprintf( 'sites/%d/jetpack-product-data?locale=%2$s&force=wpcom', $site_id, get_user_locale() );
|
||||
$api_version = '2';
|
||||
$response = Client::wpcom_json_api_request_as_blog( $wpcom_endpoint, $api_version, array(), null, 'wpcom' );
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
if ( is_wp_error( $response ) || empty( $response['body'] ) || 200 !== $response_code ) {
|
||||
return new WP_Error( 'site_products_data_fetch_failed', 'Site products data fetch failed', array( 'status' => $response_code ? $response_code : 400 ) );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $body, 200 );
|
||||
}
|
||||
}
|
@ -68,6 +68,21 @@ class REST_Products {
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'my-jetpack/v1',
|
||||
'site/products/(?P<product>[a-z\-]+)/install-standalone',
|
||||
array(
|
||||
array(
|
||||
'methods' => \WP_REST_Server::EDITABLE,
|
||||
'callback' => __CLASS__ . '::install_standalone',
|
||||
'permission_callback' => __CLASS__ . '::edit_permissions_callback',
|
||||
'args' => array(
|
||||
'product' => $product_arg,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -205,4 +220,40 @@ class REST_Products {
|
||||
return rest_ensure_response( Products::get_product( $product_slug ), 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for installing the standalone plugin on a Hybrid Product.
|
||||
*
|
||||
* @param \WP_REST_Request $request The request object.
|
||||
* @return \WP_REST_Response
|
||||
*/
|
||||
public static function install_standalone( $request ) {
|
||||
$product_slug = $request->get_param( 'product' );
|
||||
$product = Products::get_product( $product_slug );
|
||||
if ( ! isset( $product['class'] ) ) {
|
||||
return new \WP_Error(
|
||||
'not_implemented',
|
||||
__( 'The product class handler is not implemented', 'jetpack-my-jetpack' ),
|
||||
array( 'status' => 501 )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the product is not hybrid, there is no need to deal with a standalone plugin.
|
||||
*/
|
||||
if ( ! is_subclass_of( $product['class'], Hybrid_Product::class ) ) {
|
||||
return new \WP_Error(
|
||||
'not_hybrid',
|
||||
__( 'This product does not have a standalone plugin to install', 'jetpack-my-jetpack' ),
|
||||
array( 'status' => 400 )
|
||||
);
|
||||
}
|
||||
|
||||
$install_product_result = call_user_func( array( $product['class'], 'install_and_activate_standalone' ) );
|
||||
if ( is_wp_error( $install_product_result ) ) {
|
||||
$install_product_result->add_data( array( 'status' => 400 ) );
|
||||
return $install_product_result;
|
||||
}
|
||||
|
||||
return rest_ensure_response( Products::get_product( $product_slug ), 200 );
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client as Client;
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
|
||||
/**
|
||||
@ -51,7 +51,7 @@ class REST_Purchases {
|
||||
);
|
||||
}
|
||||
|
||||
return current_user_can( 'manage_options' );
|
||||
return current_user_can( 'edit_posts' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
/**
|
||||
* Sets up the Zendesk Chat REST API endpoints.
|
||||
*
|
||||
* @package automattic/my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
|
||||
/**
|
||||
* Registers the REST routes for Zendesk Chat.
|
||||
*/
|
||||
class REST_Zendesk_Chat {
|
||||
const TRANSIENT_EXPIRY = 1 * MINUTE_IN_SECONDS * 60 * 24 * 7; // 1 week (JWT is actually 2 weeks, but lets be on the safe side)
|
||||
const ZENDESK_AUTH_TOKEN = 'zendesk_auth_token';
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
register_rest_route(
|
||||
'my-jetpack/v1',
|
||||
'chat/availability',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => __CLASS__ . '::get_chat_availability',
|
||||
'permission_callback' => __CLASS__ . '::chat_authentication_permissions_callback',
|
||||
)
|
||||
);
|
||||
|
||||
register_rest_route(
|
||||
'my-jetpack/v1',
|
||||
'chat/authentication',
|
||||
array(
|
||||
'methods' => \WP_REST_Server::READABLE,
|
||||
'callback' => __CLASS__ . '::get_chat_authentication',
|
||||
'args' => array(
|
||||
'type' => array(
|
||||
'required' => false,
|
||||
'type' => 'string',
|
||||
),
|
||||
'test_mode' => array(
|
||||
'required' => false,
|
||||
'type' => 'boolean',
|
||||
),
|
||||
),
|
||||
'permission_callback' => __CLASS__ . '::chat_authentication_permissions_callback',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure user is logged in if making an authentication request
|
||||
*
|
||||
* @access public
|
||||
* @static
|
||||
*
|
||||
* @return \WP_Error|true
|
||||
*/
|
||||
public static function chat_authentication_permissions_callback() {
|
||||
if ( ! get_current_user_id() ) {
|
||||
return new \WP_Error( 'unauthorized', 'You must be logged in to access this resource.', array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the chat authentication token.
|
||||
*
|
||||
* @return \WP_Error|object Object: { token: string }
|
||||
*/
|
||||
public static function get_chat_authentication() {
|
||||
$authentication = get_transient( self::ZENDESK_AUTH_TOKEN );
|
||||
if ( $authentication ) {
|
||||
return rest_ensure_response( $authentication, 200 );
|
||||
}
|
||||
|
||||
$proxied = function_exists( 'wpcom_is_proxied_request' ) ? wpcom_is_proxied_request() : false;
|
||||
$wpcom_endpoint = 'help/authenticate/chat';
|
||||
$wpcom_api_version = '2';
|
||||
|
||||
$body = array(
|
||||
'type' => 'zendesk',
|
||||
'test_mode' => $proxied ? true : false,
|
||||
);
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_user( $wpcom_endpoint, $wpcom_api_version, array( 'method' => 'POST' ), $body );
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
|
||||
return new \WP_Error( 'chat_authentication_failed', 'Chat authentication failed', array( 'status' => $response_code ) );
|
||||
}
|
||||
|
||||
set_transient( self::ZENDESK_AUTH_TOKEN, $body, self::TRANSIENT_EXPIRY );
|
||||
return rest_ensure_response( $body, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls `wpcom/v2/presales/chat?group=jp_presales` endpoint.
|
||||
* This endpoint returns whether or not the Jetpack presales chat group is available
|
||||
*
|
||||
* @return \WP_Error/object Object: { is_available: bool }
|
||||
*/
|
||||
public static function get_chat_availability() {
|
||||
$wpcom_endpoint = '/presales/chat?group=jp_presales';
|
||||
$wpcom_api_version = '2';
|
||||
$response = Client::wpcom_json_api_request_as_user( $wpcom_endpoint, $wpcom_api_version );
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
$body = json_decode( wp_remote_retrieve_body( $response ) );
|
||||
|
||||
if ( is_wp_error( $response ) || empty( $response['body'] ) ) {
|
||||
return new \WP_Error( 'chat_config_data_fetch_failed', 'Chat config data fetch failed', array( 'status' => $response_code ) );
|
||||
}
|
||||
|
||||
return rest_ensure_response( $body, 200 );
|
||||
}
|
||||
}
|
@ -7,8 +7,9 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client as Client;
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Status\Visitor;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
/**
|
||||
* Stores the list of products available for purchase in WPCOM
|
||||
@ -189,6 +190,7 @@ class Wpcom_Products {
|
||||
'discount_price' => $discount_price,
|
||||
'is_introductory_offer' => $is_introductory_offer,
|
||||
'introductory_offer' => $introductory_offer,
|
||||
'product_term' => $product->product_term,
|
||||
);
|
||||
|
||||
return self::populate_with_discount( $product, $pricing, $discount_price );
|
||||
@ -226,4 +228,37 @@ class Wpcom_Products {
|
||||
|
||||
return $pricing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the site purchases from WPCOM.
|
||||
*
|
||||
* @todo Maybe add caching.
|
||||
*
|
||||
* @return Object|WP_Error
|
||||
*/
|
||||
public static function get_site_current_purchases() {
|
||||
// TODO: Add a short-lived cache (less than a minute) to accommodate repeated invocation of this function.
|
||||
static $purchases = null;
|
||||
|
||||
if ( $purchases !== null ) {
|
||||
return $purchases;
|
||||
}
|
||||
|
||||
$site_id = Jetpack_Options::get_option( 'id' );
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
sprintf( '/sites/%d/purchases', $site_id ),
|
||||
'1.1',
|
||||
array(
|
||||
'method' => 'GET',
|
||||
)
|
||||
);
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'purchases_state_fetch_failed' );
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$purchases = json_decode( $body );
|
||||
return $purchases;
|
||||
}
|
||||
}
|
||||
|
@ -87,7 +87,6 @@ class Anti_Spam extends Product {
|
||||
public static function get_features() {
|
||||
return array(
|
||||
_x( 'Comment and form spam protection', 'Anti-Spam Product Feature', 'jetpack-my-jetpack' ),
|
||||
_x( 'Powered by Akismet', 'Anti-Spam Product Feature', 'jetpack-my-jetpack' ),
|
||||
_x( 'Block spam without CAPTCHAs', 'Anti-Spam Product Feature', 'jetpack-my-jetpack' ),
|
||||
_x( 'Advanced stats', 'Anti-Spam Product Feature', 'jetpack-my-jetpack' ),
|
||||
);
|
||||
|
@ -8,7 +8,7 @@
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Automattic\Jetpack\Redirect;
|
||||
use Jetpack_Options;
|
||||
@ -17,7 +17,7 @@ use WP_Error;
|
||||
/**
|
||||
* Class responsible for handling the Backup product
|
||||
*/
|
||||
class Backup extends Product {
|
||||
class Backup extends Hybrid_Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
@ -44,6 +44,13 @@ class Backup extends Product {
|
||||
*/
|
||||
public static $plugin_slug = 'jetpack-backup';
|
||||
|
||||
/**
|
||||
* Backup has a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
@ -198,7 +205,9 @@ class Backup extends Product {
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
if ( static::is_plugin_active() ) {
|
||||
if ( static::is_jetpack_plugin_active() ) {
|
||||
return Redirect::get_url( 'my-jetpack-manage-backup' );
|
||||
} elseif ( static::is_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack-backup' );
|
||||
}
|
||||
}
|
||||
@ -211,4 +220,15 @@ class Backup extends Product {
|
||||
public static function is_active() {
|
||||
return parent::is_active() && static::has_required_plan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user should be redirected after checkout
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
if ( static::is_jetpack_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack#/recommendations' );
|
||||
} elseif ( static::is_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack-backup' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,12 +8,17 @@
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Boost product
|
||||
*/
|
||||
class Boost extends Product {
|
||||
|
||||
const FREE_TIER_SLUG = 'free';
|
||||
const UPGRADED_TIER_SLUG = 'upgraded';
|
||||
const UPGRADED_TIER_PRODUCT_SLUG = 'jetpack_boost_yearly';
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
@ -69,7 +74,7 @@ class Boost extends Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Instant speed and SEO', 'jetpack-my-jetpack' );
|
||||
return __( 'The easiest speed optimization plugin for WordPress', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -94,6 +99,144 @@ class Boost extends Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product's available tiers
|
||||
*
|
||||
* @return string[] Slugs of the available tiers
|
||||
*/
|
||||
public static function get_tiers() {
|
||||
return array(
|
||||
self::UPGRADED_TIER_SLUG,
|
||||
self::FREE_TIER_SLUG,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized comparison of free vs upgraded features
|
||||
*
|
||||
* @return array[] Protect features comparison
|
||||
*/
|
||||
public static function get_features_by_tier() {
|
||||
return array(
|
||||
array(
|
||||
'name' => __( 'Optimize CSS Loading', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'Move important styling information to the start of the page, which helps pages display your content sooner, so your users don’t have to wait for the entire page to load. Commonly referred to as Critical CSS.',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Must be done manually', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'title' => __( 'Manual Critical CSS regeneration', 'jetpack-my-jetpack' ),
|
||||
'content' => __(
|
||||
'<p>To enhance the speed of your site, with this plan you will need to optimize CSS by using the Manual Critical CSS generation feature whenever you:</p>
|
||||
<ul>
|
||||
<li>Make theme changes.</li>
|
||||
<li>Write a new post/page.</li>
|
||||
<li>Edit a post/page.</li>
|
||||
<li>Activate, deactivate, or update plugins that impact your site layout or HTML structure.</li>
|
||||
<li>Change settings of plugins that impact your site layout or HTML structure.</li>
|
||||
<li>Upgrade your WordPress version if the new release includes core CSS changes.</li>
|
||||
</ul>',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
),
|
||||
self::UPGRADED_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Automatically updated', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'title' => __( 'Automatic Critical CSS regeneration', 'jetpack-my-jetpack' ),
|
||||
'content' => __(
|
||||
'<p>It’s essential to regenerate Critical CSS to optimize your site speed whenever your HTML or CSS structure changes. Being on top of this can be tedious and time-consuming.</p>
|
||||
<p>Boost’s cloud service can automatically detect when your site needs the Critical CSS regenerated, and perform this function behind the scenes without requiring you to monitor it manually.</p>',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Defer non-essential JavaScript', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'Run non-essential JavaScript after the page has loaded so that styles and images can load more quickly.',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
'link' => array(
|
||||
'id' => 'jetpack-boost-defer-js',
|
||||
'title' => 'web.dev',
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Lazy image loading', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'Improve page loading speed by only loading images when they are required.',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
'link' => array(
|
||||
'id' => 'jetpack-boost-lazy-load',
|
||||
'title' => 'web.dev',
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Image guide', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'Discover and fix images with a suboptimal resolution, aspect ratio, or file size, improving user experience and page speed.',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Image CDN', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'Deliver images from Jetpack\'s Content Delivery Network. Automatically resizes your images to an appropriate size, converts them to modern efficient formats like WebP, and serves them from a worldwide network of servers.',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Dedicated email support', 'jetpack-my-jetpack' ),
|
||||
'info' => array(
|
||||
'content' => __(
|
||||
'<p>Paid customers get dedicated email support from our world-class Happiness Engineers to help with any issue.</p>
|
||||
<p>All other questions are handled by our team as quickly as we are able to go through the WordPress support forum.</p>',
|
||||
'jetpack-my-jetpack'
|
||||
),
|
||||
),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => false ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
@ -101,8 +244,19 @@ class Boost extends Product {
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
return array(
|
||||
'available' => true,
|
||||
'is_free' => true,
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array(
|
||||
'available' => true,
|
||||
'is_free' => true,
|
||||
),
|
||||
self::UPGRADED_TIER_SLUG => array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => self::UPGRADED_TIER_PRODUCT_SLUG,
|
||||
),
|
||||
Wpcom_Products::get_product_pricing( self::UPGRADED_TIER_PRODUCT_SLUG )
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -114,4 +268,25 @@ class Boost extends Product {
|
||||
public static function get_manage_url() {
|
||||
return admin_url( 'admin.php?page=jetpack-boost' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the product by installing and activating its plugin
|
||||
*
|
||||
* @param bool|WP_Error $current_result Is the result of the top level activation actions. You probably won't do anything if it is an WP_Error.
|
||||
* @return boolean|\WP_Error
|
||||
*/
|
||||
public static function do_product_specific_activation( $current_result ) {
|
||||
|
||||
$product_activation = parent::do_product_specific_activation( $current_result );
|
||||
|
||||
if ( is_wp_error( $product_activation ) && 'module_activation_failed' === $product_activation->get_error_code() ) {
|
||||
// A bundle is not a module. There's nothing in the plugin to be activated, so it's ok to fail to activate the module.
|
||||
$product_activation = true;
|
||||
}
|
||||
|
||||
// We just "got started" in My Jetpack, so skip the in-plugin experience.
|
||||
update_option( 'jb_get_started', false );
|
||||
|
||||
return $product_activation;
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,6 @@ use Automattic\Jetpack\Plugins_Installer;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
*
|
||||
* DEPRECATED: This class is deprecated and will be removed in a future version.
|
||||
*
|
||||
* All product classes have been moved out of the hybrid class concept
|
||||
*
|
||||
* @deprecated 2.7.2
|
||||
*
|
||||
* Class responsible for handling the hybrid products
|
||||
*
|
||||
* Hybrid products are those that may work both as a stand-alone plugin or with the Jetpack plugin.
|
||||
@ -29,6 +22,13 @@ use WP_Error;
|
||||
*/
|
||||
abstract class Hybrid_Product extends Product {
|
||||
|
||||
/**
|
||||
* All hybrid products have a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* Checks whether the Product is active
|
||||
*
|
||||
@ -38,6 +38,15 @@ abstract class Hybrid_Product extends Product {
|
||||
return parent::is_plugin_active() || parent::is_jetpack_plugin_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the standalone plugin for this product is active
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_standalone_plugin_active() {
|
||||
return parent::is_plugin_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin is installed
|
||||
*
|
||||
@ -129,4 +138,55 @@ abstract class Hybrid_Product extends Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install and activate the standalone plugin in the case it's missing.
|
||||
*
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
final public static function install_and_activate_standalone() {
|
||||
/**
|
||||
* Check for the presence of the standalone plugin, ignoring Jetpack presence.
|
||||
*
|
||||
* If the standalone plugin is not installed and the user can install plugins, proceed with the installation.
|
||||
*/
|
||||
if ( ! parent::is_plugin_installed() ) {
|
||||
/**
|
||||
* Check for permissions
|
||||
*/
|
||||
if ( ! current_user_can( 'install_plugins' ) ) {
|
||||
return new WP_Error( 'not_allowed', __( 'You are not allowed to install plugins on this site.', 'jetpack-my-jetpack' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the plugin
|
||||
*/
|
||||
$installed = Plugins_Installer::install_plugin( static::get_plugin_slug() );
|
||||
if ( is_wp_error( $installed ) ) {
|
||||
return $installed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the installed plugin
|
||||
*/
|
||||
$result = static::activate_plugin();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate the module as well, if the user has a plan
|
||||
* or the product does not require a plan to work
|
||||
*/
|
||||
if ( static::has_required_plan() ) {
|
||||
$module_activation = ( new Modules() )->activate( static::$module_name, false, false );
|
||||
|
||||
if ( ! $module_activation ) {
|
||||
return new WP_Error( 'module_activation_failed', __( 'Error activating Jetpack module', 'jetpack-my-jetpack' ) );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,205 @@
|
||||
<?php
|
||||
/**
|
||||
* Boost product
|
||||
*
|
||||
* @package my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Jetpack AI product
|
||||
*/
|
||||
class Jetpack_Ai extends Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $slug = 'jetpack-ai';
|
||||
|
||||
/**
|
||||
* Get the Product info for the API
|
||||
*
|
||||
* @throws \Exception If required attribute is not declared in the child class.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_info() {
|
||||
// Call parent method to get the default info.
|
||||
$info = parent::get_info();
|
||||
|
||||
// Populate the product with the feature data.
|
||||
$info['ai-assistant-feature'] = self::get_ai_assistant_feature();
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin slug - ovewrite it and return Jetpack's
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_plugin_slug() {
|
||||
return self::JETPACK_PLUGIN_SLUG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plugin filename - ovewrite it and return Jetpack's
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_plugin_filename() {
|
||||
return self::JETPACK_PLUGIN_FILENAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Jetpack AI', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack AI', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Experimental tool to add AI to your editor', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product long description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_long_description() {
|
||||
return __( 'Jetpack AI Assistant brings the power of AI right into your WordPress editor, letting your content creation soar to new heights.', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized features list
|
||||
*
|
||||
* @return array CRM features list
|
||||
*/
|
||||
public static function get_features() {
|
||||
return array(
|
||||
__( 'Artificial intelligence chatbot', 'jetpack-my-jetpack' ),
|
||||
__( 'Generate text, tables, lists, and forms', 'jetpack-my-jetpack' ),
|
||||
__( 'Refine the tone and content to your liking', 'jetpack-my-jetpack' ),
|
||||
__( 'Get feedback about your post', 'jetpack-my-jetpack' ),
|
||||
__( 'Seamless WordPress editor Integration', 'jetpack-my-jetpack' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
return array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
),
|
||||
Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_product_slug() {
|
||||
return 'jetpack_ai_yearly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM monthly product slug used to make the purchase
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_monthly_product_slug() {
|
||||
return 'jetpack_ai_monthly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
if ( 0 === strpos( $purchase->product_slug, static::get_wpcom_product_slug() ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( 0 === strpos( $purchase->product_slug, static::get_wpcom_monthly_product_slug() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get data about the AI Assistant feature
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_ai_assistant_feature() {
|
||||
// Bail early if the plugin is not active.
|
||||
if ( ! self::is_jetpack_plugin_installed() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Check if the global constant is defined.
|
||||
if ( ! defined( 'JETPACK__PLUGIN_DIR' ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Check if class exists. If not, try to require it once.
|
||||
if ( ! class_exists( 'Jetpack_AI_Helper' ) ) {
|
||||
$class_file_path = JETPACK__PLUGIN_DIR . '_inc/lib/class-jetpack-ai-helper.php';
|
||||
|
||||
// Check whether the file exists
|
||||
if ( ! file_exists( $class_file_path ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
require_once $class_file_path;
|
||||
}
|
||||
|
||||
return \Jetpack_AI_Helper::get_ai_assistance_feature();
|
||||
}
|
||||
}
|
@ -130,5 +130,4 @@ abstract class Module_Product extends Product {
|
||||
}
|
||||
return Jetpack::deactivate_module( static::$module_name );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -61,6 +61,13 @@ abstract class Product {
|
||||
*/
|
||||
public static $requires_user_connection = true;
|
||||
|
||||
/**
|
||||
* Whether this product has a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = false;
|
||||
|
||||
/**
|
||||
* Get the plugin slug
|
||||
*
|
||||
@ -117,19 +124,26 @@ abstract class Product {
|
||||
'title' => static::get_title(),
|
||||
'description' => static::get_description(),
|
||||
'long_description' => static::get_long_description(),
|
||||
'tiers' => static::get_tiers(),
|
||||
'features' => static::get_features(),
|
||||
'features_by_tier' => static::get_features_by_tier(),
|
||||
'disclaimers' => static::get_disclaimers(),
|
||||
'status' => static::get_status(),
|
||||
'pricing_for_ui' => static::get_pricing_for_ui(),
|
||||
'is_bundle' => static::is_bundle_product(),
|
||||
'is_plugin_active' => static::is_plugin_active(),
|
||||
'is_upgradable_by_bundle' => static::is_upgradable_by_bundle(),
|
||||
'supported_products' => static::get_supported_products(),
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
'requires_user_connection' => static::$requires_user_connection,
|
||||
'has_required_plan' => static::has_required_plan(),
|
||||
'has_required_tier' => static::has_required_tier(),
|
||||
'manage_url' => static::get_manage_url(),
|
||||
'purchase_url' => static::get_purchase_url(),
|
||||
'post_activation_url' => static::get_post_activation_url(),
|
||||
'class' => get_called_class(),
|
||||
'standalone_plugin_info' => static::get_standalone_info(),
|
||||
'class' => static::class,
|
||||
'post_checkout_url' => static::get_post_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
@ -161,6 +175,15 @@ abstract class Product {
|
||||
*/
|
||||
abstract public static function get_long_description();
|
||||
|
||||
/**
|
||||
* Get the tiers for the product
|
||||
*
|
||||
* @return boolean|string[] The slugs of the tiers (i.e. [ "free", "basic", "advanced" ]), or False if the product has no tiers.
|
||||
*/
|
||||
public static function get_tiers() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized features list
|
||||
*
|
||||
@ -168,6 +191,15 @@ abstract class Product {
|
||||
*/
|
||||
abstract public static function get_features();
|
||||
|
||||
/**
|
||||
* Get the internationalized comparison of features grouped by each tier
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_features_by_tier() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product pricing
|
||||
*
|
||||
@ -175,6 +207,16 @@ abstract class Product {
|
||||
*/
|
||||
abstract public static function get_pricing_for_ui();
|
||||
|
||||
/**
|
||||
* Get the URL where the user can purchase the product iff it doesn't have an interstitial page in My Jetpack.
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_purchase_url() {
|
||||
// Declare as concrete method as most Jetpack products use an interstitial page within My Jetpack.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
@ -191,6 +233,15 @@ abstract class Product {
|
||||
return static::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
@ -209,6 +260,22 @@ abstract class Product {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the standalone plugin related info
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_standalone_info() {
|
||||
$is_standalone_installed = static::$has_standalone_plugin && self::is_plugin_installed();
|
||||
$is_standalone_active = static::$has_standalone_plugin && self::is_plugin_active();
|
||||
|
||||
return array(
|
||||
'has_standalone_plugin' => static::$has_standalone_plugin,
|
||||
'is_standalone_installed' => $is_standalone_installed,
|
||||
'is_standalone_active' => $is_standalone_active,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
@ -222,6 +289,15 @@ abstract class Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the tiers
|
||||
*
|
||||
* @return array Key/value pairs of tier slugs and whether they are supported or not.
|
||||
*/
|
||||
public static function has_required_tier() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product supports trial or not
|
||||
*
|
||||
@ -235,6 +311,15 @@ abstract class Product {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product can be upgraded to a different product.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_upgradable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether product is a bundle.
|
||||
*
|
||||
@ -271,14 +356,19 @@ abstract class Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_status() {
|
||||
|
||||
if ( ! static::is_plugin_installed() ) {
|
||||
$status = 'plugin_absent';
|
||||
if ( static::has_required_plan() ) {
|
||||
$status = 'plugin_absent_with_plan';
|
||||
}
|
||||
} elseif ( static::is_active() ) {
|
||||
$status = 'active';
|
||||
// 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::is_upgradable() ) {
|
||||
// Upgradable plans should ignore whether or not they have the required plan.
|
||||
$status = 'can_upgrade';
|
||||
} 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';
|
||||
@ -464,5 +554,4 @@ abstract class Product {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -8,12 +8,17 @@
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Protect product
|
||||
*/
|
||||
class Protect extends Product {
|
||||
|
||||
const FREE_TIER_SLUG = 'free';
|
||||
const UPGRADED_TIER_SLUG = 'upgraded';
|
||||
const UPGRADED_TIER_PRODUCT_SLUG = 'jetpack_scan';
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
@ -70,7 +75,7 @@ class Protect extends Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Protect your site and scan for security vulnerabilities.', 'jetpack-my-jetpack' );
|
||||
return __( 'Stay one step ahead of threats', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -97,14 +102,118 @@ class Protect extends Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
* Get the product's available tiers
|
||||
*
|
||||
* @return string[] Slugs of the available tiers
|
||||
*/
|
||||
public static function get_tiers() {
|
||||
return array(
|
||||
self::UPGRADED_TIER_SLUG,
|
||||
self::FREE_TIER_SLUG,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized comparison of free vs upgraded features
|
||||
*
|
||||
* @return array[] Protect features comparison
|
||||
*/
|
||||
public static function get_features_by_tier() {
|
||||
return array(
|
||||
array(
|
||||
'name' => __( 'Scan for threats and vulnerabilities', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Check items against database', 'jetpack-my-jetpack' ),
|
||||
),
|
||||
self::UPGRADED_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Line by line malware scanning', 'jetpack-my-jetpack' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Daily automated scans', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Plus on-demand manual scans', 'jetpack-my-jetpack' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Web Application Firewall', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array(
|
||||
'included' => false,
|
||||
'description' => __( 'Manual rules only', 'jetpack-my-jetpack' ),
|
||||
),
|
||||
self::UPGRADED_TIER_SLUG => array(
|
||||
'included' => true,
|
||||
'description' => __( 'Automatic protection and rule updates', 'jetpack-my-jetpack' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Brute force protection', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => true ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Access to scan on Cloud', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => false ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'One-click auto fixes', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => false ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Notifications', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => false ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Severity labels', 'jetpack-my-jetpack' ),
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array( 'included' => false ),
|
||||
self::UPGRADED_TIER_SLUG => array( 'included' => true ),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product pricing details
|
||||
*
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
return array(
|
||||
'available' => true,
|
||||
'is_free' => true,
|
||||
'tiers' => array(
|
||||
self::FREE_TIER_SLUG => array(
|
||||
'available' => true,
|
||||
'is_free' => true,
|
||||
),
|
||||
self::UPGRADED_TIER_SLUG => array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => self::UPGRADED_TIER_PRODUCT_SLUG,
|
||||
),
|
||||
Wpcom_Products::get_product_pricing( self::UPGRADED_TIER_PRODUCT_SLUG )
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -116,4 +225,14 @@ class Protect extends Product {
|
||||
public static function get_manage_url() {
|
||||
return admin_url( 'admin.php?page=jetpack-protect' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return product bundles list
|
||||
* that supports the product.
|
||||
*
|
||||
* @return array Products bundle list.
|
||||
*/
|
||||
public static function is_upgradable_by_bundle() {
|
||||
return array( 'security' );
|
||||
}
|
||||
}
|
||||
|
@ -214,4 +214,18 @@ class Scan extends Module_Product {
|
||||
public static function get_manage_url() {
|
||||
return Redirect::get_url( 'my-jetpack-manage-scan' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user should be redirected after checkout
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
if ( static::is_jetpack_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack#/recommendations' );
|
||||
}
|
||||
|
||||
// If Jetpack is not active, it means that the user has another standalone plugin active
|
||||
// and it follows the `Protect` plugin flow instead of `Scan` so for now it would be safe
|
||||
// to return null and let the user go back to the My Jetpack page.
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Automattic\Jetpack\Search\Module_Control as Search_Module_Control;
|
||||
use Jetpack_Options;
|
||||
@ -18,7 +18,7 @@ use WP_Error;
|
||||
/**
|
||||
* Class responsible for handling the Search product
|
||||
*/
|
||||
class Search extends Product {
|
||||
class Search extends Hybrid_Product {
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
@ -40,6 +40,13 @@ class Search extends Product {
|
||||
*/
|
||||
public static $plugin_slug = 'jetpack-search';
|
||||
|
||||
/**
|
||||
* Search has a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* The filename (id) of the plugin associated with this product.
|
||||
*
|
||||
@ -320,5 +327,4 @@ class Search extends Product {
|
||||
public static function get_manage_url() {
|
||||
return admin_url( 'admin.php?page=jetpack-search' );
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,10 +7,8 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\My_Jetpack\Module_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
@ -162,45 +160,13 @@ class Security extends Module_Product {
|
||||
return static::is_jetpack_plugin_active() && static::has_required_plan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hits the wpcom api to check scan status.
|
||||
*
|
||||
* @todo Maybe add caching.
|
||||
*
|
||||
* @return Object|WP_Error
|
||||
*/
|
||||
private static function get_state_from_wpcom() {
|
||||
static $status = null;
|
||||
|
||||
if ( $status !== null ) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
$site_id = Jetpack_Options::get_option( 'id' );
|
||||
|
||||
$response = Client::wpcom_json_api_request_as_blog(
|
||||
sprintf( '/sites/%d/purchases', $site_id ),
|
||||
'1.1',
|
||||
array(
|
||||
'method' => 'GET',
|
||||
)
|
||||
);
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'purchases_state_fetch_failed' );
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$status = json_decode( $body );
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
$purchases_data = static::get_state_from_wpcom();
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
@ -7,13 +7,13 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Social product
|
||||
*/
|
||||
class Social extends Product {
|
||||
class Social extends Hybrid_Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
@ -36,6 +36,13 @@ class Social extends Product {
|
||||
*/
|
||||
public static $plugin_slug = 'jetpack-social';
|
||||
|
||||
/**
|
||||
* Social has a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* The filename (id) of the plugin associated with this product.
|
||||
*
|
||||
@ -121,13 +128,19 @@ class Social extends Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
* Get the URL where the user manages the product.
|
||||
*
|
||||
* If the standalone plugin is active,
|
||||
* it will redirect to the standalone plugin settings page.
|
||||
* Otherwise, it will redirect to the Jetpack settings page.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
if ( static::is_plugin_active() ) {
|
||||
if ( static::is_standalone_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack-social' );
|
||||
}
|
||||
|
||||
return admin_url( 'admin.php?page=jetpack#/settings?term=publicize' );
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,203 @@
|
||||
<?php
|
||||
/**
|
||||
* Starter plan
|
||||
*
|
||||
* @package my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Module_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Starter plan
|
||||
*/
|
||||
class Starter extends Module_Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $slug = 'starter';
|
||||
|
||||
/**
|
||||
* The Jetpack module name
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $module_name = 'starter';
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return _x( 'Starter', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return _x( 'Jetpack Starter', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Essential security tools: real-time backups and comment spam protection.', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product long description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_long_description() {
|
||||
return __( 'Essential security tools: real-time backups and comment spam protection.', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized features list
|
||||
*
|
||||
* @return array Starter features list
|
||||
*/
|
||||
public static function get_features() {
|
||||
return array(
|
||||
_x( 'Real-time cloud backups with 1GB storage', 'Starter Product Feature', 'jetpack-my-jetpack' ),
|
||||
_x( 'One-click fixes for most threats', 'Starter Product Feature', 'jetpack-my-jetpack' ),
|
||||
_x( 'Comment & form spam protection', 'Starter Product Feature', 'jetpack-my-jetpack' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
return array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
),
|
||||
Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_product_slug() {
|
||||
return 'jetpack_starter_yearly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Jetpack module is active
|
||||
*
|
||||
* This is a bundle and not a product. We should not use this information for anything
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_module_active() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the product by installing and activating its plugin
|
||||
*
|
||||
* @param bool|WP_Error $current_result Is the result of the top level activation actions. You probably won't do anything if it is an WP_Error.
|
||||
* @return boolean|\WP_Error
|
||||
*/
|
||||
public static function do_product_specific_activation( $current_result ) {
|
||||
|
||||
$product_activation = parent::do_product_specific_activation( $current_result );
|
||||
|
||||
if ( is_wp_error( $product_activation ) && 'module_activation_failed' === $product_activation->get_error_code() ) {
|
||||
// A bundle is not a module. There's nothing in the plugin to be activated, so it's ok to fail to activate the module.
|
||||
$product_activation = true;
|
||||
}
|
||||
|
||||
// At this point, Jetpack plugin is installed. Let's activate each individual product.
|
||||
$activation = Anti_Spam::activate();
|
||||
if ( is_wp_error( $activation ) ) {
|
||||
return $activation;
|
||||
}
|
||||
|
||||
$activation = Backup::activate();
|
||||
if ( is_wp_error( $activation ) ) {
|
||||
return $activation;
|
||||
}
|
||||
|
||||
return $activation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Product is active
|
||||
*
|
||||
* Jetpack Starter is a bundle and not a module. Activation takes place on WPCOM. So lets consider it active if jetpack is active and has the plan.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_active() {
|
||||
return static::is_jetpack_plugin_active() && static::has_required_plan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
if ( 0 === strpos( $purchase->product_slug, 'jetpack_starter' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether product is a bundle.
|
||||
*
|
||||
* @return boolean True
|
||||
*/
|
||||
public static function is_bundle_product() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the products it contains.
|
||||
*
|
||||
* @return Array Product slugs
|
||||
*/
|
||||
public static function get_supported_products() {
|
||||
return array( 'backup', 'anti-spam' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
return '';
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
<?php
|
||||
/**
|
||||
* Jetpack Stats product
|
||||
*
|
||||
* @package my-jetpack
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Module_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Jetpack_Options;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Jetpack Stats product
|
||||
*/
|
||||
class Stats extends Module_Product {
|
||||
/**
|
||||
* The product slug
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $slug = 'stats';
|
||||
|
||||
/**
|
||||
* The Jetpack module name associated with this product
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
public static $module_name = 'stats';
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Stats', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Stats', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Simple, yet powerful analytics', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product long description
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_long_description() {
|
||||
return __( 'With Jetpack Stats, you don’t need to be a data scientist to see how your site is performing.', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized features list
|
||||
*
|
||||
* @return array CRM features list
|
||||
*/
|
||||
public static function get_features() {
|
||||
return array(
|
||||
__( 'Instant access to upcoming features', 'jetpack-my-jetpack' ),
|
||||
__( 'Priority support', 'jetpack-my-jetpack' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
return array_merge(
|
||||
array(
|
||||
'available' => true,
|
||||
'wpcom_product_slug' => static::get_wpcom_product_slug(),
|
||||
'wpcom_free_product_slug' => static::get_wpcom_free_product_slug(),
|
||||
'wpcom_pwyw_product_slug' => static::get_wpcom_pwyw_product_slug(),
|
||||
),
|
||||
// TODO: replace with `Wpcom_Products::get_product_pricing` once available.
|
||||
// This is not yet used anywhere, so it's fine to leave it as is for now.
|
||||
array(
|
||||
'currency_code' => 'USD',
|
||||
'full_price' => 10,
|
||||
'discount_price' => 10,
|
||||
'product_term' => 'month',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_product_slug() {
|
||||
return 'jetpack_stats_monthly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM Pay Whatever You Want product slug used to make the purchase
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_pwyw_product_slug() {
|
||||
return 'jetpack_stats_pwyw_yearly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM free product slug
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_wpcom_free_product_slug() {
|
||||
return 'jetpack_stats_free_yearly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the site already supports this product through an existing plan or purchase
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
if ( 0 === strpos( $purchase->product_slug, 'jetpack_stats' ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( 0 === strpos( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product can be upgraded to a different product.
|
||||
* Only Jetpack Stats Commercial plan is not upgradable.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_upgradable() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
if (
|
||||
(
|
||||
// Purchase is Jetpack Stats...
|
||||
0 === strpos( $purchase->product_slug, 'jetpack_stats' ) &&
|
||||
// but not Jetpack Stats Free...
|
||||
false === strpos( $purchase->product_slug, 'free' )
|
||||
) || 0 === strpos( $purchase->product_slug, 'jetpack_complete' )
|
||||
) {
|
||||
// Only Jetpack Stats paid plans should be eligible for this conditional.
|
||||
// Sample product slugs: jetpack_stats_monthly
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a redirect parameter for an upgrade URL if current purchase license is a free license
|
||||
* or an empty string otherwise.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_url_redirect_string() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return '';
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
if (
|
||||
0 === strpos( $purchase->product_slug, static::get_wpcom_free_product_slug() )
|
||||
) {
|
||||
return '&productType=personal';
|
||||
}
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the product supports trial or not.
|
||||
* Since Jetpack Stats has been widely available as a free product in the past, it "supports" a trial.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_trial_support() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WordPress.com URL for purchasing Jetpack Stats for the current site.
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_purchase_url() {
|
||||
// The returning URL could be customized by changing the `redirect_uri` param with relative path.
|
||||
return sprintf(
|
||||
'%s#!/stats/purchase/%d?from=jetpack-my-jetpack%s&redirect_uri=%s',
|
||||
admin_url( 'admin.php?page=stats' ),
|
||||
Jetpack_Options::get_option( 'id' ),
|
||||
static::get_url_redirect_string(),
|
||||
rawurlencode( 'admin.php?page=stats' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
return admin_url( 'admin.php?page=stats' );
|
||||
}
|
||||
}
|
@ -7,13 +7,13 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\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 Product {
|
||||
class Videopress extends Hybrid_Product {
|
||||
|
||||
/**
|
||||
* The product slug
|
||||
@ -54,6 +54,13 @@ class Videopress extends Product {
|
||||
*/
|
||||
public static $requires_user_connection = true;
|
||||
|
||||
/**
|
||||
* VideoPress has a standalone plugin
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
*
|
||||
@ -145,7 +152,18 @@ class Videopress extends Product {
|
||||
public static function get_manage_url() {
|
||||
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' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
// TODO: import and perform a proper check with Current_Plan. See #33410.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user