updated plugin Jetpack Protect
version 2.1.0
This commit is contained in:
@ -5,6 +5,155 @@ 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).
|
||||
|
||||
## [4.17.0] - 2024-03-14
|
||||
### Changed
|
||||
- Rewrite My Jetpack hooks to Typescript [#36288]
|
||||
|
||||
## [4.16.0] - 2024-03-12
|
||||
### Added
|
||||
- Add a red bubble notification that shows if the site is disconnected [#36263]
|
||||
- Add README to data directory [#36301]
|
||||
- Add whitelist to show errors only for certain queries [#36261]
|
||||
|
||||
### Changed
|
||||
- Migrate Stats counts out of redux and into tanstack queries [#36195]
|
||||
- Replace window state calls with util function [#36271]
|
||||
- Rewrite My Jetpack utils to typescript [#36296]
|
||||
- Show small stats card in table if large stats card isn't showing [#36136]
|
||||
- Updated package dependencies. [#36325]
|
||||
- Update query hooks for my-jetpack data" [#36257]
|
||||
- Update useMyJetpackConnection hook to TypeScript [#36300]
|
||||
|
||||
### Removed
|
||||
- Removing redux store [#36256]
|
||||
|
||||
## [4.15.0] - 2024-03-07
|
||||
### Added
|
||||
- Refactor My Jetpack's backup related redux state to react query. [#35982]
|
||||
|
||||
### Changed
|
||||
- Migrate dismiss welcome banner to tanstack [#36199]
|
||||
- Migrate global notices to context [#36201]
|
||||
- Migrate My Jetpack's licenses query and state to react-query [#36029]
|
||||
- Moved lifecycle stats function out of redux [#36205]
|
||||
- Updating purchase related redux data to tanstack/react [#35994]
|
||||
|
||||
### Removed
|
||||
- Connected Product offer is not being used, removing it to clean up a bit [#36203]
|
||||
|
||||
### Fixed
|
||||
- fix a few My Jetpack bugs when main plugin is not installed [#36139]
|
||||
- Intersitital tables were not visibly loading when pressed [#36236]
|
||||
|
||||
## [4.14.0] - 2024-03-04
|
||||
### Changed
|
||||
- Migrate My Jetpack zendesk state to react-query [#36028]
|
||||
- Updated package dependencies.
|
||||
|
||||
### Fixed
|
||||
- Add registration nonce to connect screen in My Jetpack [#36133]
|
||||
|
||||
## [4.13.0] - 2024-03-01
|
||||
### Added
|
||||
- Add site lifecycle status guess to My Jetpack [#35815]
|
||||
|
||||
### Changed
|
||||
- Changed product plan checks on My Jetpack cards [#36046]
|
||||
- Display different Boost card tooltip content based on score letter grade. [#35863]
|
||||
- Improve consistency and fix bugs in product start and checkout flows [#35908]
|
||||
- Instanciate the Boost Score API (new Speed_Score()) in My Jetpack. [#36080]
|
||||
- My Jetpack: add Tracks events to connection section [#35804]
|
||||
- Refactor react-query to reduce code repetition [#35990]
|
||||
|
||||
### Fixed
|
||||
- fixed the purchase query for the boost card [#36004]
|
||||
|
||||
## [4.12.1] - 2024-02-27
|
||||
### Added
|
||||
- My Jetpack: Add an info popover in the Boost product card. [#35731]
|
||||
|
||||
## [4.12.0] - 2024-02-26
|
||||
### Changed
|
||||
- My Jetpack: decouple Jetpack AI insterstitial component [#35836]
|
||||
- Remove translation of product names [#35830]
|
||||
- Updating purchases state to use data query instead of redux [#35697]
|
||||
|
||||
### Removed
|
||||
- Remove kebab menu on My Jetpack cards [#35829]
|
||||
|
||||
## [4.11.0] - 2024-02-22
|
||||
### Added
|
||||
- Adding accesible text for external links on connection page and footer [#35733]
|
||||
|
||||
### Changed
|
||||
- change status and action of My Jetpack cards when plugin is missing [#35718]
|
||||
- ESlint: disabled redundant role rule [#35800]
|
||||
- My Jetpack: add product slugs to click events on interstitials [#35740]
|
||||
- My Jetpack: let tier data pass on quantity data to checkout process for proper checkout URL crafting [#35817]
|
||||
- Updated package dependencies. [#35793]
|
||||
|
||||
### Fixed
|
||||
- Backup Card: made stats readable by screen readers [#35786]
|
||||
- Connection Screen: make VoiceOver announce lists as such [#35736]
|
||||
- Do not initialize My Jetpack when in Offline mode. [#35807]
|
||||
- Fix wrong prop type passed to ConnectedProductCard [#35789]
|
||||
|
||||
## [4.10.0] - 2024-02-19
|
||||
### Added
|
||||
- Add Boost Speed Score into My Jetpack Boost product card [#35606]
|
||||
- Add connection indicator for screen readers [#35714]
|
||||
|
||||
### Fixed
|
||||
- Improved accessibility of Dismiss button in Connection Banner [#35694]
|
||||
- My Jeptack Connection: Make footer logos a list for better screen readers interpretation. [#35667]
|
||||
- My Jetpack: add label for screen readers to connect page close button [#35712]
|
||||
|
||||
## [4.9.2] - 2024-02-13
|
||||
### Changed
|
||||
- My Jetpack: various improvements to the Stats card. [#35355]
|
||||
- Updated package dependencies. [#35608]
|
||||
|
||||
## [4.9.1] - 2024-02-12
|
||||
### Added
|
||||
- Add My Jetpack link to standalone plugins missing it [#35523]
|
||||
|
||||
## [4.9.0] - 2024-02-07
|
||||
### Changed
|
||||
- Add pricing info for AI and CRM on My Jetpack [#35457]
|
||||
- Update the description of some cards to better describe the product on My Jetpack page [#35428]
|
||||
|
||||
### Fixed
|
||||
- Fixes issue on My Jetpack interstitials where some prices are 1 cent off [#35492]
|
||||
|
||||
## [4.8.0] - 2024-02-05
|
||||
### Added
|
||||
- Add tracking info to the Jetpack Manage Banner CTA [#35378]
|
||||
- My Jetpack: support redirect_to parameter on the product interstitial. [#35263]
|
||||
|
||||
### Changed
|
||||
- Update CTA copy on the connection banner to make it clear which type of connection we are going to request [#35401]
|
||||
- Updated package dependencies.
|
||||
- Update product cards on My Jetpack to always display the status indidicator. [#35377]
|
||||
|
||||
### Fixed
|
||||
- Fix issue where most products are not installing their standalone product upon purchase [#35399]
|
||||
|
||||
## [4.7.0] - 2024-01-29
|
||||
### Changed
|
||||
- Update the UpsellBanner to use the Card component from WP components. [#35223]
|
||||
|
||||
### Removed
|
||||
- UpsellBanner component moved to js-packages/components [#35228]
|
||||
|
||||
## [4.6.2] - 2024-01-22
|
||||
### Added
|
||||
- My Jetpack: add contact us event for Jetpack AI [#35136]
|
||||
|
||||
## [4.6.1] - 2024-01-22
|
||||
### Changed
|
||||
- Display Jetpack Protect product card for all users. [#35142]
|
||||
- Ensure that interstitial tables go straight to checkout just like insterstitial cards [#35049]
|
||||
|
||||
## [4.6.0] - 2024-01-18
|
||||
### Added
|
||||
- Add hosting provider check. [#34864]
|
||||
@ -1198,6 +1347,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Added
|
||||
- Created package
|
||||
|
||||
[4.17.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.16.0...4.17.0
|
||||
[4.16.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.15.0...4.16.0
|
||||
[4.15.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.14.0...4.15.0
|
||||
[4.14.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.13.0...4.14.0
|
||||
[4.13.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.12.1...4.13.0
|
||||
[4.12.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.12.0...4.12.1
|
||||
[4.12.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.11.0...4.12.0
|
||||
[4.11.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.10.0...4.11.0
|
||||
[4.10.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.9.2...4.10.0
|
||||
[4.9.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.9.1...4.9.2
|
||||
[4.9.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.9.0...4.9.1
|
||||
[4.9.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.8.0...4.9.0
|
||||
[4.8.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.7.0...4.8.0
|
||||
[4.7.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.6.2...4.7.0
|
||||
[4.6.2]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.6.1...4.6.2
|
||||
[4.6.1]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.6.0...4.6.1
|
||||
[4.6.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.5.0...4.6.0
|
||||
[4.5.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.4.0...4.5.0
|
||||
[4.4.0]: https://github.com/Automattic/jetpack-my-jetpack/compare/4.3.0...4.4.0
|
||||
|
@ -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' => '8b33ddffd4b0e82ce03c');
|
||||
<?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' => '5782f9bf704638c25046');
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -12,6 +12,16 @@
|
||||
http://jedwatson.github.io/classnames
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @remix-run/router v1.2.1
|
||||
*
|
||||
|
File diff suppressed because one or more lines are too long
@ -5,21 +5,23 @@
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"php": ">=7.0",
|
||||
"automattic/jetpack-admin-ui": "^0.3.1",
|
||||
"automattic/jetpack-assets": "^2.0.4",
|
||||
"automattic/jetpack-connection": "^2.2.0",
|
||||
"automattic/jetpack-jitm": "^3.0.2",
|
||||
"automattic/jetpack-licensing": "^2.0.1",
|
||||
"automattic/jetpack-plugins-installer": "^0.3.1",
|
||||
"automattic/jetpack-redirect": "^2.0.0",
|
||||
"automattic/jetpack-constants": "^2.0.0",
|
||||
"automattic/jetpack-plans": "^0.4.1"
|
||||
"automattic/jetpack-admin-ui": "^0.4.1",
|
||||
"automattic/jetpack-assets": "^2.1.4",
|
||||
"automattic/jetpack-boost-speed-score": "^0.3.6",
|
||||
"automattic/jetpack-connection": "^2.4.1",
|
||||
"automattic/jetpack-jitm": "^3.1.1",
|
||||
"automattic/jetpack-licensing": "^2.0.2",
|
||||
"automattic/jetpack-plugins-installer": "^0.3.2",
|
||||
"automattic/jetpack-redirect": "^2.0.1",
|
||||
"automattic/jetpack-constants": "^2.0.1",
|
||||
"automattic/jetpack-plans": "^0.4.3",
|
||||
"automattic/jetpack-status": "^2.1.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"yoast/phpunit-polyfills": "1.1.0",
|
||||
"automattic/jetpack-changelogger": "^4.0.5",
|
||||
"automattic/jetpack-changelogger": "^4.1.1",
|
||||
"automattic/wordbless": "@dev",
|
||||
"automattic/jetpack-videopress": "^0.22.2"
|
||||
"automattic/jetpack-videopress": "^0.23.10"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
@ -67,7 +69,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-my-jetpack/compare/${old}...${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "4.6.x-dev"
|
||||
"dev-trunk": "4.17.x-dev"
|
||||
},
|
||||
"version-constants": {
|
||||
"::PACKAGE_VERSION": "src/class-initializer.php"
|
||||
|
245
wp-content/plugins/jetpack-protect/jetpack_vendor/automattic/jetpack-my-jetpack/global.d.ts
vendored
Normal file
245
wp-content/plugins/jetpack-protect/jetpack_vendor/automattic/jetpack-my-jetpack/global.d.ts
vendored
Normal file
@ -0,0 +1,245 @@
|
||||
interface Window {
|
||||
myJetpackInitialState?: {
|
||||
siteSuffix: string;
|
||||
latestBoostSpeedScores: {
|
||||
scores: {
|
||||
desktop: number;
|
||||
mobile: number;
|
||||
};
|
||||
theme: string;
|
||||
timestamp: number;
|
||||
};
|
||||
IDCContainerID: string;
|
||||
adminUrl: string;
|
||||
blogID: string;
|
||||
fileSystemWriteAccess: 'yes' | 'no';
|
||||
isStatsModuleActive: string;
|
||||
isUserFromKnownHost: string;
|
||||
jetpackManage: {
|
||||
isAgencyAccount: boolean;
|
||||
isEnabled: boolean;
|
||||
};
|
||||
loadAddLicenseScreen: string;
|
||||
myJetpackCheckoutUri: string;
|
||||
myJetpackFlags: {
|
||||
showFullJetpackStatsCard: boolean;
|
||||
videoPressStats: boolean;
|
||||
};
|
||||
lifecycleStats: {
|
||||
isSiteConnected: boolean;
|
||||
isUserConnected: boolean;
|
||||
jetpackPlugins: Array< string >;
|
||||
modules: Array< string >;
|
||||
purchases: Array< string >;
|
||||
};
|
||||
myJetpackUrl: string;
|
||||
myJetpackVersion: string;
|
||||
plugins: {
|
||||
[ key: string ]: {
|
||||
Name: string;
|
||||
PluginURI: string;
|
||||
Version: string;
|
||||
Title: string;
|
||||
Description: string;
|
||||
Author: string;
|
||||
AuthorName: string;
|
||||
AuthorURI: string;
|
||||
DomainPath: string;
|
||||
textDomain: string;
|
||||
RequiresPHP: string;
|
||||
RequiresWP: string;
|
||||
UpdateURI: string;
|
||||
Network: boolean;
|
||||
active: boolean;
|
||||
};
|
||||
};
|
||||
products: {
|
||||
items: {
|
||||
[ key: string ]: {
|
||||
class: string;
|
||||
description: string;
|
||||
disclaimers: Array< string[] >;
|
||||
features: string[];
|
||||
has_paid_plan_for_product: boolean;
|
||||
features_by_tier: Array< string >;
|
||||
has_required_plan: boolean;
|
||||
has_required_tier: Array< string >;
|
||||
is_bundle: boolean;
|
||||
is_plugin_active: boolean;
|
||||
is_upgradable_by_bundle: string[];
|
||||
long_description: string;
|
||||
manage_url: string;
|
||||
name: string;
|
||||
plugin_slug: string;
|
||||
post_activation_url: string;
|
||||
post_checkout_url?: string;
|
||||
pricing_for_ui?: {
|
||||
available: boolean;
|
||||
wpcom_product_slug: string;
|
||||
product_term: string;
|
||||
currency_code: string;
|
||||
full_price: number;
|
||||
discount_price: number;
|
||||
coupon_discount: number;
|
||||
is_introductory_offer: boolean;
|
||||
introductory_offer?: {
|
||||
cost_per_interval: number;
|
||||
interval_count: number;
|
||||
interval_unit: string;
|
||||
should_prorate_when_offer_ends: boolean;
|
||||
transition_after_renewal_count: number;
|
||||
usage_limit?: number;
|
||||
};
|
||||
};
|
||||
purchase_url?: string;
|
||||
requires_user_connection: boolean;
|
||||
slug: string;
|
||||
standalone_plugin_info: {
|
||||
has_standalone_plugin: boolean;
|
||||
is_standalone_installed: boolean;
|
||||
is_standalone_active: boolean;
|
||||
};
|
||||
status: string;
|
||||
supported_products: string[];
|
||||
tiers: string[];
|
||||
title: string;
|
||||
wpcom_product_slug: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
purchases: {
|
||||
items: Array< {
|
||||
ID: string;
|
||||
user_id: string;
|
||||
blog_id: string;
|
||||
product_id: string;
|
||||
subscribed_date: string;
|
||||
renew: string;
|
||||
auto_renew: string;
|
||||
renew_date: string;
|
||||
inactive_date: string | null;
|
||||
active: string;
|
||||
meta: string | object;
|
||||
ownership_id: string;
|
||||
most_recent_renew_date: string;
|
||||
amount: number;
|
||||
expiry_date: string;
|
||||
expiry_message: string;
|
||||
expiry_sub_message: string;
|
||||
expiry_status: string;
|
||||
partner_name: string | null;
|
||||
partner_slug: string | null;
|
||||
partner_key_id: string | null;
|
||||
subscription_status: string;
|
||||
product_name: string;
|
||||
product_slug: string;
|
||||
product_type: string;
|
||||
blog_created_date: string;
|
||||
blogname: string;
|
||||
domain: string;
|
||||
description: string;
|
||||
attached_to_purchase_id: string | null;
|
||||
included_domain: string;
|
||||
included_domain_purchase_amount: number;
|
||||
currency_code: string;
|
||||
currency_symbol: string;
|
||||
renewal_price_tier_slug: string | null;
|
||||
renewal_price_tier_usage_quantity: number | null;
|
||||
current_price_tier_slug: string | null;
|
||||
current_price_tier_usage_quantity: number | null;
|
||||
price_tier_list: Array< object >;
|
||||
price_text: string;
|
||||
bill_period_label: string;
|
||||
bill_period_days: number;
|
||||
regular_price_text: string;
|
||||
regular_price_integer: number;
|
||||
product_display_price: string;
|
||||
price_integer: number;
|
||||
is_cancelable: boolean;
|
||||
can_explicit_renew: boolean;
|
||||
can_disable_auto_renew: boolean;
|
||||
can_reenable_auto_renewal: boolean;
|
||||
iap_purchase_management_link: string | null;
|
||||
is_iap_purchase: boolean;
|
||||
is_locked: boolean;
|
||||
is_refundable: boolean;
|
||||
refund_period_in_days: number;
|
||||
is_renewable: boolean;
|
||||
is_renewal: boolean;
|
||||
has_private_registration: boolean;
|
||||
refund_amount: number;
|
||||
refund_integer: number;
|
||||
refund_currency_symbol: string;
|
||||
refund_text: string;
|
||||
refund_options: object | null;
|
||||
total_refund_amount: number;
|
||||
total_refund_integer: number;
|
||||
total_refund_currency: string;
|
||||
total_refund_text: string;
|
||||
check_dns: boolean;
|
||||
} >;
|
||||
};
|
||||
topJetpackMenuItemUrl: string;
|
||||
userIsAdmin: string;
|
||||
userIsNewToJetpack: string;
|
||||
welcomeBanner: {
|
||||
hasBeenDismissed: boolean;
|
||||
};
|
||||
};
|
||||
JP_CONNECTION_INITIAL_STATE: {
|
||||
apiRoot: string;
|
||||
apiNonce: string;
|
||||
registrationNonce: string;
|
||||
connectionStatus: {
|
||||
isActive: boolean;
|
||||
isStaging: boolean;
|
||||
isRegistered: boolean;
|
||||
isUserConnected: boolean;
|
||||
hasConnectedOwner: boolean;
|
||||
offlineMode: {
|
||||
isActive: boolean;
|
||||
constant: boolean;
|
||||
url: boolean;
|
||||
filter: boolean;
|
||||
wpLocalConstant: boolean;
|
||||
};
|
||||
isPublic: boolean;
|
||||
};
|
||||
userConnectionData: {
|
||||
currentUser: {
|
||||
isConnected: boolean;
|
||||
isMaster: boolean;
|
||||
username: string;
|
||||
id: number;
|
||||
blogId: number;
|
||||
wpcomUser: {
|
||||
avatar: boolean;
|
||||
};
|
||||
gravatar: string;
|
||||
permissions: {
|
||||
admin_page?: boolean;
|
||||
connect: boolean;
|
||||
connect_user: boolean;
|
||||
disconnect: boolean;
|
||||
edit_posts?: boolean;
|
||||
manage_modules?: boolean;
|
||||
manage_options?: boolean;
|
||||
manage_plugins?: boolean;
|
||||
network_admin?: boolean;
|
||||
network_sites_page?: boolean;
|
||||
publish_posts?: boolean;
|
||||
view_stats?: boolean;
|
||||
};
|
||||
};
|
||||
connectionOwner: null;
|
||||
};
|
||||
connectedPlugins: object;
|
||||
wpVersion: string;
|
||||
siteSuffix: string;
|
||||
connectionErrors: Array< string | object >;
|
||||
};
|
||||
myJetpackRest?: {
|
||||
apiRoot: string;
|
||||
apiNonce: string;
|
||||
};
|
||||
}
|
@ -9,6 +9,9 @@ namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Admin_UI\Admin_Menu;
|
||||
use Automattic\Jetpack\Assets;
|
||||
use Automattic\Jetpack\Boost_Speed_Score\Jetpack_Boost_Modules;
|
||||
use Automattic\Jetpack\Boost_Speed_Score\Speed_Score;
|
||||
use Automattic\Jetpack\Boost_Speed_Score\Speed_Score_History;
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Initial_State as Connection_Initial_State;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
@ -34,7 +37,7 @@ class Initializer {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const PACKAGE_VERSION = '4.6.0';
|
||||
const PACKAGE_VERSION = '4.17.0';
|
||||
|
||||
/**
|
||||
* HTML container ID for the IDC screen on My Jetpack page.
|
||||
@ -52,6 +55,17 @@ class Initializer {
|
||||
'jetpack-search',
|
||||
);
|
||||
|
||||
const MY_JETPACK_SITE_INFO_TRANSIENT_KEY = 'my-jetpack-site-info';
|
||||
|
||||
const MISSING_SITE_CONNECTION_NOTIFICATION_KEY = 'missing-site-connection';
|
||||
|
||||
/**
|
||||
* Holds info/data about the site (from the /sites/%d endpoint)
|
||||
*
|
||||
* @var stdClass Object
|
||||
*/
|
||||
public static $site_info;
|
||||
|
||||
/**
|
||||
* Initialize My Jetpack
|
||||
*
|
||||
@ -72,6 +86,10 @@ class Initializer {
|
||||
Licensing::instance()->initialize();
|
||||
}
|
||||
|
||||
// Initialize Boost Speed Score
|
||||
$boost_modules = Jetpack_Boost_Modules::init();
|
||||
new Speed_Score( $boost_modules, 'jetpack-my-jetpack' );
|
||||
|
||||
// Add custom WP REST API endoints.
|
||||
add_action( 'rest_api_init', array( __CLASS__, 'register_rest_endpoints' ) );
|
||||
|
||||
@ -85,6 +103,8 @@ class Initializer {
|
||||
);
|
||||
|
||||
add_action( 'load-' . $page_suffix, array( __CLASS__, 'admin_init' ) );
|
||||
// This is later than the admin-ui package, which runs on 1000
|
||||
add_action( 'admin_init', array( __CLASS__, 'maybe_show_red_bubble' ), 1001 );
|
||||
|
||||
// Sets up JITMS.
|
||||
JITM::configure();
|
||||
@ -142,6 +162,7 @@ class Initializer {
|
||||
* @return void
|
||||
*/
|
||||
public static function admin_init() {
|
||||
self::$site_info = self::get_site_info();
|
||||
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.
|
||||
@ -177,40 +198,53 @@ class Initializer {
|
||||
'textdomain' => 'jetpack-my-jetpack',
|
||||
)
|
||||
);
|
||||
$modules = new Modules();
|
||||
$modules = new Modules();
|
||||
$connection = new Connection_Manager();
|
||||
$speed_score_history = new Speed_Score_History( wp_parse_url( get_site_url(), PHP_URL_HOST ) );
|
||||
wp_localize_script(
|
||||
'my_jetpack_main_app',
|
||||
'myJetpackInitialState',
|
||||
array(
|
||||
'products' => array(
|
||||
'products' => array(
|
||||
'items' => Products::get_products(),
|
||||
),
|
||||
'purchases' => array(
|
||||
'purchases' => array(
|
||||
'items' => array(),
|
||||
),
|
||||
'plugins' => Plugins_Installer::get_plugins(),
|
||||
'myJetpackUrl' => admin_url( 'admin.php?page=my-jetpack' ),
|
||||
'myJetpackCheckoutUri' => 'admin.php?page=my-jetpack',
|
||||
'topJetpackMenuItemUrl' => Admin_Menu::get_top_level_menu_item_url(),
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'blogID' => Connection_Manager::get_site_id( true ),
|
||||
'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' ),
|
||||
'userIsNewToJetpack' => self::is_jetpack_user_new(),
|
||||
'isStatsModuleActive' => $modules->is_active( 'stats' ),
|
||||
'isUserFromKnownHost' => self::is_user_from_known_host(),
|
||||
'welcomeBanner' => array(
|
||||
'plugins' => Plugins_Installer::get_plugins(),
|
||||
'myJetpackUrl' => admin_url( 'admin.php?page=my-jetpack' ),
|
||||
'myJetpackCheckoutUri' => admin_url( 'admin.php?page=my-jetpack' ),
|
||||
'topJetpackMenuItemUrl' => Admin_Menu::get_top_level_menu_item_url(),
|
||||
'siteSuffix' => ( new Status() )->get_site_suffix(),
|
||||
'blogID' => Connection_Manager::get_site_id( true ),
|
||||
'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' ),
|
||||
'userIsNewToJetpack' => self::is_jetpack_user_new(),
|
||||
'lifecycleStats' => array(
|
||||
'jetpackPlugins' => self::get_installed_jetpack_plugins(),
|
||||
'isSiteConnected' => $connection->is_connected(),
|
||||
'isUserConnected' => $connection->is_user_connected(),
|
||||
'purchases' => self::get_purchases(),
|
||||
'modules' => self::get_active_modules(),
|
||||
),
|
||||
'redBubbleAlerts' => self::get_red_bubble_alerts(),
|
||||
'isStatsModuleActive' => $modules->is_active( 'stats' ),
|
||||
'isUserFromKnownHost' => self::is_user_from_known_host(),
|
||||
'isCommercial' => self::is_commercial_site(),
|
||||
'isAtomic' => ( new Status_Host() )->is_woa_site(),
|
||||
'welcomeBanner' => array(
|
||||
'hasBeenDismissed' => \Jetpack_Options::get_option( 'dismissed_welcome_banner', false ),
|
||||
),
|
||||
'jetpackManage' => array(
|
||||
'jetpackManage' => array(
|
||||
'isEnabled' => Jetpack_Manage::could_use_jp_manage(),
|
||||
'isAgencyAccount' => Jetpack_Manage::is_agency_account(),
|
||||
),
|
||||
'latestBoostSpeedScores' => $speed_score_history->latest(),
|
||||
)
|
||||
);
|
||||
|
||||
@ -232,6 +266,63 @@ class Initializer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product slugs of the active purchases
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_purchases() {
|
||||
$purchases = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function ( $purchase ) {
|
||||
return $purchase->product_slug;
|
||||
},
|
||||
$purchases
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get installed Jetpack plugins
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_installed_jetpack_plugins() {
|
||||
$plugin_slugs = array_keys( Plugins_Installer::get_plugins() );
|
||||
$plugin_slugs = array_map(
|
||||
static function ( $slug ) {
|
||||
$parts = explode( '/', $slug );
|
||||
if ( empty( $parts ) ) {
|
||||
return '';
|
||||
}
|
||||
// Return the last segment of the filepath without the PHP extension
|
||||
return str_replace( '.php', '', $parts[ count( $parts ) - 1 ] );
|
||||
},
|
||||
$plugin_slugs
|
||||
);
|
||||
|
||||
return array_values( array_intersect( self::JETPACK_PLUGIN_SLUGS, $plugin_slugs ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get active modules (except ones enabled by default)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_active_modules() {
|
||||
$modules = new Modules();
|
||||
$active_modules = $modules->get_active();
|
||||
|
||||
// if the Jetpack plugin is active, filter out the modules that are active by default
|
||||
if ( class_exists( 'Jetpack' ) && ! empty( $active_modules ) ) {
|
||||
$active_modules = array_diff( $active_modules, Jetpack::get_default_modules() );
|
||||
}
|
||||
return $active_modules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user is "new" to Jetpack
|
||||
* This is used to vary some messaging in My Jetpack
|
||||
@ -305,8 +396,8 @@ class Initializer {
|
||||
*/
|
||||
public static function get_my_jetpack_flags() {
|
||||
$flags = array(
|
||||
'videoPressStats' => Jetpack_Constants::is_true( 'JETPACK_MY_JETPACK_VIDEOPRESS_STATS_ENABLED' ),
|
||||
'showJetpackStatsCard' => class_exists( 'Jetpack' ),
|
||||
'videoPressStats' => Jetpack_Constants::is_true( 'JETPACK_MY_JETPACK_VIDEOPRESS_STATS_ENABLED' ),
|
||||
'showFullJetpackStatsCard' => class_exists( 'Jetpack' ),
|
||||
);
|
||||
|
||||
return $flags;
|
||||
@ -376,6 +467,11 @@ class Initializer {
|
||||
$should = false;
|
||||
}
|
||||
|
||||
// All options presented in My Jetpack require a connection to WordPress.com.
|
||||
if ( ( new Status() )->is_offline_mode() ) {
|
||||
$should = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows filtering whether My Jetpack should be initialized.
|
||||
*
|
||||
@ -406,6 +502,56 @@ class Initializer {
|
||||
return rest_ensure_response( $body, 200 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the self::$site_info var with site data from the /sites/%d endpoint
|
||||
*
|
||||
* @return Object|WP_Error
|
||||
*/
|
||||
public static function get_site_info() {
|
||||
static $site_info = null;
|
||||
|
||||
if ( $site_info !== null ) {
|
||||
return $site_info;
|
||||
}
|
||||
|
||||
// Check for a cached value before doing lookup
|
||||
$stored_site_info = get_transient( self::MY_JETPACK_SITE_INFO_TRANSIENT_KEY );
|
||||
if ( $stored_site_info !== false ) {
|
||||
return $stored_site_info;
|
||||
}
|
||||
|
||||
$response = self::get_site();
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return $response;
|
||||
}
|
||||
$site_info = $response->data;
|
||||
set_transient( self::MY_JETPACK_SITE_INFO_TRANSIENT_KEY, $site_info, DAY_IN_SECONDS );
|
||||
|
||||
return $site_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a site has been determined "commercial" or not.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_commercial_site() {
|
||||
if ( is_wp_error( self::$site_info ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return empty( self::$site_info->options->is_commercial ) ? false : self::$site_info->options->is_commercial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if site is registered (has been connected before).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_registered() {
|
||||
return (bool) \Jetpack_Options::get_option( 'id' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss the welcome banner.
|
||||
*
|
||||
@ -465,4 +611,59 @@ class Initializer {
|
||||
public static function get_idc_container_id() {
|
||||
return static::IDC_CONTAINER_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Conditionally append the red bubble notification to the "Jetpack" menu item if there are alerts to show
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function maybe_show_red_bubble() {
|
||||
global $menu;
|
||||
// filters for the items in this file
|
||||
add_filter( 'my_jetpack_red_bubble_notification_slugs', array( __CLASS__, 'alert_if_missing_site_connection' ) );
|
||||
$red_bubble_alerts = self::get_red_bubble_alerts();
|
||||
|
||||
// The Jetpack menu item should be on index 3
|
||||
if (
|
||||
! empty( $red_bubble_alerts ) &&
|
||||
is_countable( $red_bubble_alerts ) &&
|
||||
isset( $menu[3] ) &&
|
||||
$menu[3][0] === 'Jetpack'
|
||||
) {
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$menu[3][0] .= sprintf( ' <span class="awaiting-mod">%d</span>', count( $red_bubble_alerts ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all possible alerts that we might use a red bubble notification for
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_red_bubble_alerts() {
|
||||
static $red_bubble_alerts = array();
|
||||
|
||||
// using a static cache since we call this function more than once in the class
|
||||
if ( ! empty( $red_bubble_alerts ) ) {
|
||||
return $red_bubble_alerts;
|
||||
}
|
||||
// go find the alerts
|
||||
$red_bubble_alerts = apply_filters( 'my_jetpack_red_bubble_notification_slugs', $red_bubble_alerts );
|
||||
|
||||
return $red_bubble_alerts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an alert slug if the site is missing a site connection
|
||||
*
|
||||
* @param array $red_bubble_slugs - slugs that describe the reasons the red bubble is showing.
|
||||
* @return array
|
||||
*/
|
||||
public static function alert_if_missing_site_connection( array $red_bubble_slugs ) {
|
||||
if ( ! ( new Connection_Manager() )->is_connected() ) {
|
||||
$red_bubble_slugs[] = self::MISSING_SITE_CONNECTION_NOTIFICATION_KEY;
|
||||
}
|
||||
|
||||
return $red_bubble_slugs;
|
||||
}
|
||||
}
|
||||
|
@ -174,8 +174,17 @@ class Products {
|
||||
'backup',
|
||||
'boost',
|
||||
'crm',
|
||||
'videopress', // we use videopress here to add the plugin action to the Jetpack plugin itself
|
||||
'videopress',
|
||||
'social',
|
||||
'protect',
|
||||
'crm',
|
||||
'search',
|
||||
);
|
||||
|
||||
// Add plugin action links for the core Jetpack plugin.
|
||||
Product::extend_core_plugin_action_links();
|
||||
|
||||
// Add plugin action links to standalone products.
|
||||
foreach ( $products as $product ) {
|
||||
$class_name = self::get_product_class( $product );
|
||||
$class_name::extend_plugin_action_links();
|
||||
|
@ -237,17 +237,6 @@ class REST_Products {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) );
|
||||
|
@ -44,21 +44,21 @@ class Anti_Spam extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Akismet Anti-spam', 'jetpack-my-jetpack' );
|
||||
return 'Akismet Anti-spam';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Akismet Anti-spam', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Akismet Anti-spam';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -52,21 +52,21 @@ class Backup extends Hybrid_Product {
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'VaultPress Backup', 'jetpack-my-jetpack' );
|
||||
return 'VaultPress Backup';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack VaultPress Backup', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack VaultPress Backup';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -129,6 +129,13 @@ class Backup extends Hybrid_Product {
|
||||
return 'jetpack_backup_t1_yearly';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user should be redirected after checkout
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
@ -209,10 +216,12 @@ class Backup extends Hybrid_Product {
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_manage_url() {
|
||||
if ( static::is_jetpack_plugin_active() ) {
|
||||
return Redirect::get_url( 'my-jetpack-manage-backup' );
|
||||
} elseif ( static::is_plugin_active() ) {
|
||||
// check standalone first
|
||||
if ( static::is_standalone_plugin_active() ) {
|
||||
return admin_url( 'admin.php?page=jetpack-backup' );
|
||||
// otherwise, check for the main Jetpack plugin
|
||||
} elseif ( static::is_jetpack_plugin_active() ) {
|
||||
return Redirect::get_url( 'my-jetpack-manage-backup' );
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,15 +233,4 @@ class Backup extends Hybrid_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.php?page=jetpack#/recommendations';
|
||||
} elseif ( static::is_plugin_active() ) {
|
||||
return 'admin.php?page=jetpack-backup';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,21 +51,21 @@ class Boost extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Boost', 'jetpack-my-jetpack' );
|
||||
return 'Boost';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Boost', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Boost';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -74,7 +74,7 @@ class Boost extends Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'The easiest speed optimization plugin for WordPress', 'jetpack-my-jetpack' );
|
||||
return __( 'Speed up your site in seconds', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -237,6 +237,15 @@ class Boost extends Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product princing details
|
||||
*
|
||||
@ -260,6 +269,27 @@ class Boost extends Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_paid_plan_for_product() {
|
||||
$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 ) {
|
||||
// Boost is available as standalone bundle and as part of the Complete plan.
|
||||
if ( strpos( $purchase->product_slug, 'jetpack_boost' ) !== false || str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
|
@ -50,21 +50,21 @@ class Creator extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Creator', 'jetpack-my-jetpack' );
|
||||
return 'Creator';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Creator', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Creator';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,6 +8,7 @@
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the CRM product
|
||||
@ -26,7 +27,10 @@ class Crm extends Product {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $plugin_filename = 'zero-bs-crm/ZeroBSCRM.php';
|
||||
public static $plugin_filename = array(
|
||||
'zero-bs-crm/ZeroBSCRM.php',
|
||||
'crm/ZeroBSCRM.php',
|
||||
);
|
||||
|
||||
/**
|
||||
* The slug of the plugin associated with this product. If not defined, it will default to the Jetpack plugin
|
||||
@ -43,21 +47,21 @@ class Crm extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'CRM', 'jetpack-my-jetpack' );
|
||||
return 'CRM';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack CRM', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack CRM';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +70,7 @@ class Crm extends Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Connect with your people', 'jetpack-my-jetpack' );
|
||||
return __( 'Nurture your contacts to grow your business', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,9 +102,17 @@ class Crm extends Product {
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui() {
|
||||
// We are hard coding pricing info for CRM because it is not available to us through the CRM API.
|
||||
return array(
|
||||
'available' => true,
|
||||
'is_free' => true,
|
||||
'available' => true,
|
||||
'is_free' => false,
|
||||
'full_price' => 132,
|
||||
'discount_price' => 132,
|
||||
'is_introductory_offer' => false,
|
||||
'product_term' => 'year',
|
||||
'introductory_offer' => null,
|
||||
// CRM is only sold in USD
|
||||
'currency_code' => 'USD',
|
||||
);
|
||||
}
|
||||
|
||||
@ -121,4 +133,27 @@ class Crm extends Product {
|
||||
public static function get_manage_url() {
|
||||
return admin_url( 'admin.php?page=zerobscrm-dash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the product
|
||||
* CRM is available as part of Jetpack Complete
|
||||
*
|
||||
* @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 ( str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -38,21 +38,21 @@ class Extras extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Extras', 'jetpack-my-jetpack' );
|
||||
return 'Extras';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Extras', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Extras';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,10 +15,6 @@ use WP_Error;
|
||||
* 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.
|
||||
*
|
||||
* In case Jetpack plugin is active, it will not attempt to install its stand-alone plugin.
|
||||
*
|
||||
* But if Jetpack plugin is not active, then it will prompt to install and activate its stand-alone plugin.
|
||||
*/
|
||||
abstract class Hybrid_Product extends Product {
|
||||
|
||||
@ -29,6 +25,15 @@ abstract class Hybrid_Product extends Product {
|
||||
*/
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* For Hybrid products, we can use either the standalone or Jetpack plugin
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_plugin_installed() {
|
||||
return parent::is_plugin_installed() || parent::is_jetpack_plugin_installed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Product is active
|
||||
*
|
||||
@ -47,15 +52,6 @@ abstract class Hybrid_Product extends Product {
|
||||
return parent::is_plugin_active();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the plugin is installed
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_plugin_installed() {
|
||||
return parent::is_plugin_installed() || static::is_jetpack_plugin_installed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the Jetpack module is active only if a module_name is defined
|
||||
*
|
||||
@ -122,12 +118,11 @@ abstract class Hybrid_Product extends Product {
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( static::$module_name ) ) {
|
||||
if ( ! static::has_required_plan() ) {
|
||||
// translators: %s is the product name. e.g. Jetpack Search.
|
||||
return new WP_Error( 'not_supported', sprintf( __( 'Your plan does not support %s.', 'jetpack-my-jetpack' ), static::get_title() ) );
|
||||
}
|
||||
// Only activate the module if the plan supports it
|
||||
// We don't want to throw an error for a missing plan here since we try activation before purchase
|
||||
if ( static::has_required_plan() && ! empty( static::$module_name ) ) {
|
||||
$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' ) );
|
||||
}
|
||||
@ -143,33 +138,8 @@ abstract class Hybrid_Product extends Product {
|
||||
*
|
||||
* @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();
|
||||
public static function install_and_activate_standalone() {
|
||||
$result = parent::install_and_activate_standalone();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
return $result;
|
||||
@ -179,7 +149,7 @@ abstract class Hybrid_Product extends Product {
|
||||
* 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() ) {
|
||||
if ( static::has_required_plan() && isset( static::$module_name ) ) {
|
||||
$module_activation = ( new Modules() )->activate( static::$module_name, false, false );
|
||||
|
||||
if ( ! $module_activation ) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
/**
|
||||
* Boost product
|
||||
* AI product
|
||||
*
|
||||
* @package my-jetpack
|
||||
*/
|
||||
@ -58,21 +58,21 @@ class Jetpack_Ai extends Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Jetpack AI', 'jetpack-my-jetpack' );
|
||||
return 'AI';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack AI', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack AI';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +103,7 @@ class Jetpack_Ai extends Product {
|
||||
* @return int
|
||||
*/
|
||||
public static function get_next_usage_tier() {
|
||||
if ( ! self::is_site_connected() ) {
|
||||
if ( ! self::is_site_connected() || ! self::has_required_plan() ) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
@ -205,12 +205,6 @@ class Jetpack_Ai extends Product {
|
||||
* @return array Pricing details
|
||||
*/
|
||||
public static function get_pricing_for_ui_by_usage_tier( $tier ) {
|
||||
|
||||
// Bail early if the site is not connected.
|
||||
if ( ! self::is_site_connected() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$product = Wpcom_Products::get_product( static::get_wpcom_product_slug() );
|
||||
|
||||
if ( empty( $product ) ) {
|
||||
@ -316,24 +310,7 @@ class Jetpack_Ai extends 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 ( str_starts_with( $purchase->product_slug, static::get_wpcom_product_slug() ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( str_starts_with( $purchase->product_slug, static::get_wpcom_monthly_product_slug() ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( str_starts_with( $purchase->product_slug, static::get_wpcom_bi_yearly_product_slug() ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return static::does_site_have_feature( 'ai-assistant' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,7 +86,7 @@ abstract class Module_Product extends Product {
|
||||
*/
|
||||
public static function get_status() {
|
||||
$status = parent::get_status();
|
||||
if ( 'active' === $status && ! static::is_module_active() ) {
|
||||
if ( 'inactive' === $status && ! static::is_module_active() ) {
|
||||
$status = 'module_disabled';
|
||||
}
|
||||
return $status;
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Automattic\Jetpack\Plugins_Installer;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
@ -47,13 +49,20 @@ abstract class Product {
|
||||
/**
|
||||
* The Jetpack plugin filename
|
||||
*
|
||||
* @var string
|
||||
* @var array
|
||||
*/
|
||||
const JETPACK_PLUGIN_FILENAME = array(
|
||||
'jetpack/jetpack.php',
|
||||
'jetpack-dev/jetpack.php',
|
||||
);
|
||||
|
||||
/**
|
||||
* Whether this product requires a site connection
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $requires_site_connection = true;
|
||||
|
||||
/**
|
||||
* Whether this product requires a user connection
|
||||
*
|
||||
@ -118,44 +127,91 @@ abstract class Product {
|
||||
throw new \Exception( 'Product classes must declare the $slug attribute.' );
|
||||
}
|
||||
return array(
|
||||
'slug' => static::$slug,
|
||||
'plugin_slug' => static::$plugin_slug,
|
||||
'name' => static::get_name(),
|
||||
'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(),
|
||||
'standalone_plugin_info' => static::get_standalone_info(),
|
||||
'class' => static::class,
|
||||
'post_checkout_url' => static::get_post_checkout_url(),
|
||||
'slug' => static::$slug,
|
||||
'plugin_slug' => static::$plugin_slug,
|
||||
'name' => static::get_name(),
|
||||
'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_paid_plan_for_product' => static::has_paid_plan_for_product(),
|
||||
'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(),
|
||||
'standalone_plugin_info' => static::get_standalone_info(),
|
||||
'class' => static::class,
|
||||
'post_checkout_url' => static::get_post_checkout_url(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Collect the site's active features
|
||||
*
|
||||
* @return WP_Error|array
|
||||
*/
|
||||
private static function get_site_features_from_wpcom() {
|
||||
static $features = null;
|
||||
|
||||
if ( $features !== null ) {
|
||||
return $features;
|
||||
}
|
||||
|
||||
$site_id = Jetpack_Options::get_option( 'id' );
|
||||
$response = Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d/features', $site_id ), '1.1' );
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'site_features_fetch_failed' );
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$feature_return = json_decode( $body );
|
||||
$features = $feature_return->active;
|
||||
|
||||
return $features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the site has a feature
|
||||
* This will check the features provided by the site plans and products (including free ones)
|
||||
*
|
||||
* @param string $feature - the feature to check for.
|
||||
* @return bool
|
||||
*/
|
||||
public static function does_site_have_feature( $feature ) {
|
||||
if ( ! $feature ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$features = self::get_site_features_from_wpcom();
|
||||
if ( is_wp_error( $features ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return in_array( $feature, $features, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public static function get_name();
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@ -289,6 +345,19 @@ abstract class Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the site has a paid plan for the product
|
||||
* This ignores free products, it only checks if there is a purchase that supports the product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_paid_plan_for_product() {
|
||||
// TODO: this is not always the same.
|
||||
// There should be checks on each individual product class for paid plans if the product has a free offering
|
||||
// For products with no free offering, checking has_required_plan works fine
|
||||
return static::has_required_plan();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current plan (or purchases) of the site already supports the tiers
|
||||
*
|
||||
@ -358,13 +427,15 @@ abstract class Product {
|
||||
public static function get_status() {
|
||||
if ( ! static::is_plugin_installed() ) {
|
||||
$status = 'plugin_absent';
|
||||
if ( static::has_required_plan() ) {
|
||||
if ( static::has_paid_plan_for_product() ) {
|
||||
$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() ) {
|
||||
// We only consider missing site & user connection an error when the Product is active.
|
||||
if ( static::$requires_site_connection && ! ( new Connection_Manager() )->is_connected() ) {
|
||||
$status = 'error';
|
||||
} elseif ( 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.
|
||||
@ -452,7 +523,8 @@ abstract class Product {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! static::is_plugin_installed() ) {
|
||||
// Default to installing the standalone plugin for the product
|
||||
if ( ! self::is_plugin_installed() ) {
|
||||
$installed = Plugins_Installer::install_plugin( static::get_plugin_slug() );
|
||||
if ( is_wp_error( $installed ) ) {
|
||||
return $installed;
|
||||
@ -537,15 +609,11 @@ abstract class Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the plugin action links.
|
||||
* Filter the action links for the plugins specified.
|
||||
*
|
||||
* @param string|string[] $filenames The plugin filename(s) to filter the action links for.
|
||||
*/
|
||||
public static function extend_plugin_action_links() {
|
||||
|
||||
$filenames = static::get_plugin_filename();
|
||||
if ( ! is_array( $filenames ) ) {
|
||||
$filenames = array( $filenames );
|
||||
}
|
||||
|
||||
private static function filter_action_links( $filenames ) {
|
||||
foreach ( $filenames as $filename ) {
|
||||
$hook = 'plugin_action_links_' . $filename;
|
||||
$callback = array( static::class, 'get_plugin_actions_links' );
|
||||
@ -554,4 +622,65 @@ abstract class Product {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the plugin action links.
|
||||
*/
|
||||
public static function extend_plugin_action_links() {
|
||||
$filenames = static::get_plugin_filename();
|
||||
if ( ! is_array( $filenames ) ) {
|
||||
$filenames = array( $filenames );
|
||||
}
|
||||
|
||||
self::filter_action_links( $filenames );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the Jetpack plugin action links.
|
||||
*/
|
||||
public static function extend_core_plugin_action_links() {
|
||||
$filenames = self::JETPACK_PLUGIN_FILENAME;
|
||||
|
||||
self::filter_action_links( $filenames );
|
||||
}
|
||||
|
||||
/**
|
||||
* Install and activate the standalone plugin in the case it's missing.
|
||||
*
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
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 ( ! static::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;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,11 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client;
|
||||
use Automattic\Jetpack\My_Jetpack\Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Jetpack_Options;
|
||||
use WP_Error;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Protect product
|
||||
@ -52,21 +55,21 @@ class Protect extends Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Protect', 'jetpack-my-jetpack' );
|
||||
return 'Protect';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Protect', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Protect';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,7 +78,7 @@ class Protect extends Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Stay one step ahead of threats', 'jetpack-my-jetpack' );
|
||||
return __( 'Powerful, automated site security', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -101,6 +104,33 @@ class Protect extends Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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/scan', $site_id ) . '?force=wpcom', '2', array( 'timeout' => 2 ), null, 'wpcom' );
|
||||
|
||||
if ( 200 !== wp_remote_retrieve_response_code( $response ) ) {
|
||||
return new WP_Error( 'scan_state_fetch_failed' );
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
$status = json_decode( $body );
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the product's available tiers
|
||||
*
|
||||
@ -217,6 +247,28 @@ class Protect extends Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the site has a paid plan for the product
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function has_paid_plan_for_product() {
|
||||
$scan_data = static::get_state_from_wpcom();
|
||||
if ( is_wp_error( $scan_data ) ) {
|
||||
return false;
|
||||
}
|
||||
return is_object( $scan_data ) && isset( $scan_data->state ) && 'unavailable' !== $scan_data->state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL where the user manages the product
|
||||
*
|
||||
|
@ -34,21 +34,21 @@ class Scan extends Module_Product {
|
||||
public static $module_name = 'scan';
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Scan', 'jetpack-my-jetpack' );
|
||||
return 'Scan';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Scan', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Scan';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +57,7 @@ class Scan extends Module_Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Stay one step ahead of threats', 'jetpack-my-jetpack' );
|
||||
return __( 'Powerful, automated site security', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -66,21 +66,21 @@ class Search extends Hybrid_Product {
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Search', 'jetpack-my-jetpack' );
|
||||
return 'Search';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Search', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Search';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -89,7 +89,7 @@ class Search extends Hybrid_Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Help them find what they need', 'jetpack-my-jetpack' );
|
||||
return __( 'Custom instant site search', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -144,6 +144,15 @@ class Search extends Hybrid_Product {
|
||||
return array_merge( $pricing, $search_pricing );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
|
@ -31,21 +31,21 @@ class Security extends Module_Product {
|
||||
public static $module_name = 'security';
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return _x( 'Security', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
return 'Security';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return _x( 'Security', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Security';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -9,6 +9,7 @@ namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
|
||||
/**
|
||||
* Class responsible for handling the Social product
|
||||
@ -55,21 +56,21 @@ class Social extends Hybrid_Product {
|
||||
);
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Social', 'jetpack-my-jetpack' );
|
||||
return 'Social';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Social', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Social';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +79,7 @@ class Social extends Hybrid_Product {
|
||||
* @return string
|
||||
*/
|
||||
public static function get_description() {
|
||||
return __( 'Reach your audience on social media', 'jetpack-my-jetpack' );
|
||||
return __( 'Auto-publish to social media', 'jetpack-my-jetpack' );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -118,6 +119,15 @@ class Social extends Hybrid_Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
@ -133,6 +143,12 @@ class Social extends Hybrid_Product {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
// For atomic sites, do a feature check to see if the republicize feature is available
|
||||
// This feature is available by default on all Jetpack sites
|
||||
if ( ( new Host() )->is_woa_site() ) {
|
||||
return static::does_site_have_feature( 'republicize' );
|
||||
}
|
||||
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return false;
|
||||
|
@ -31,21 +31,21 @@ class Starter extends Module_Product {
|
||||
public static $module_name = 'starter';
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return _x( 'Starter', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
return 'Starter';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return _x( 'Jetpack Starter', 'Jetpack product name', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Starter';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,8 +7,10 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\My_Jetpack\Initializer;
|
||||
use Automattic\Jetpack\My_Jetpack\Module_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
use Jetpack_Options;
|
||||
|
||||
/**
|
||||
@ -44,21 +46,35 @@ class Stats extends Module_Product {
|
||||
public static $plugin_filename = self::JETPACK_PLUGIN_FILENAME;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Stats only requires site connection, not user connection
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $requires_user_connection = false;
|
||||
|
||||
/**
|
||||
* Stats does not have a standalone plugin (yet?)
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $has_standalone_plugin = false;
|
||||
|
||||
/**
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'Stats', 'jetpack-my-jetpack' );
|
||||
return 'Stats';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack Stats', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack Stats';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -140,21 +156,72 @@ class Stats extends Module_Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the site already supports this product through an existing plan or purchase
|
||||
* Gets the 'status' of the Stats product
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_status() {
|
||||
$status = parent::get_status();
|
||||
if ( 'module_disabled' === $status && ! Initializer::is_registered() ) {
|
||||
// If the site has never been connected before, show the "Learn more" CTA,
|
||||
// that points to the add Stats product interstitial.
|
||||
$status = 'needs_purchase_or_free';
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
/**
|
||||
* Checks whether the product can be upgraded to a different product.
|
||||
* Stats Commercial plan (highest tier) & Jetpack Complete are not upgradable.
|
||||
* Also we don't push PWYW users to upgrade.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
public static function is_upgradable() {
|
||||
// For now, atomic sites with stats are not in a position to upgrade
|
||||
if ( ( new Host() )->is_woa_site() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
if ( ! is_wp_error( $purchases_data ) && is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
// Jetpack complete includes Stats commercial & cannot be upgraded
|
||||
if ( str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
return false;
|
||||
} elseif (
|
||||
// Stats commercial purchased with highest tier cannot be upgraded.
|
||||
in_array(
|
||||
$purchase->product_slug,
|
||||
array( 'jetpack_stats_yearly', 'jetpack_stats_monthly', 'jetpack_stats_bi_yearly' ),
|
||||
true
|
||||
) && $purchase->current_price_tier_slug === 'more_than_1m_views'
|
||||
) {
|
||||
return false;
|
||||
} elseif (
|
||||
// If user already has Stats PWYW, we won't push them to upgrade.
|
||||
$purchase->product_slug === 'jetpack_stats_pwyw_yearly'
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the site has a paid plan that supports this product
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_paid_plan_for_product() {
|
||||
$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 ( str_starts_with( $purchase->product_slug, 'jetpack_stats' ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
// Stats is available as standalone product and as part of the Complete plan.
|
||||
if ( strpos( $purchase->product_slug, 'jetpack_stats' ) !== false || str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -163,58 +230,19 @@ class Stats extends Module_Product {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) ) {
|
||||
// For now, only the free and commercial tiered subs show as upgradable
|
||||
$upgradeable_stats_purchases = array_filter(
|
||||
$purchases_data,
|
||||
static function ( $purchase ) {
|
||||
// Free plan is upgradeable
|
||||
if ( $purchase->product_slug === 'jetpack_stats_free_yearly' ) {
|
||||
return true;
|
||||
// Commercial plans are upgradeable if they have a tier
|
||||
} elseif (
|
||||
in_array(
|
||||
$purchase->product_slug,
|
||||
array( 'jetpack_stats_yearly', 'jetpack_stats_monthly', 'jetpack_stats_bi_yearly' ),
|
||||
true
|
||||
) &&
|
||||
! empty( $purchase->current_price_tier_slug )
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return ! empty( $upgradeable_stats_purchases );
|
||||
}
|
||||
|
||||
// If there are no plans found, don't consider the product as upgradeable
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a redirect parameter for an upgrade URL if current purchase license is a free license
|
||||
* or an empty string otherwise.
|
||||
* Returns a productType parameter for an upgrade URL, determining whether
|
||||
* to show the PWYW upgrade interstitial or commercial upgrade interstitial.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_url_redirect_string() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
public static function get_url_product_type() {
|
||||
$purchases_data = Wpcom_Products::get_site_current_purchases();
|
||||
$is_commercial_site = Initializer::is_commercial_site();
|
||||
if ( is_wp_error( $purchases_data ) ) {
|
||||
return '';
|
||||
return $is_commercial_site ? '&productType=commercial' : '';
|
||||
}
|
||||
if ( $is_commercial_site ) {
|
||||
return '&productType=commercial';
|
||||
}
|
||||
if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
|
||||
foreach ( $purchases_data as $purchase ) {
|
||||
@ -258,7 +286,7 @@ class Stats extends Module_Product {
|
||||
'%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(),
|
||||
static::get_url_product_type(),
|
||||
rawurlencode( 'admin.php?page=stats' )
|
||||
);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@
|
||||
|
||||
namespace Automattic\Jetpack\My_Jetpack\Products;
|
||||
|
||||
use Automattic\Jetpack\Current_Plan;
|
||||
use Automattic\Jetpack\My_Jetpack\Hybrid_Product;
|
||||
use Automattic\Jetpack\My_Jetpack\Wpcom_Products;
|
||||
|
||||
@ -63,21 +62,21 @@ class Videopress extends Hybrid_Product {
|
||||
public static $has_standalone_plugin = true;
|
||||
|
||||
/**
|
||||
* Get the internationalized product name
|
||||
* Get the product name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return __( 'VideoPress', 'jetpack-my-jetpack' );
|
||||
return 'VideoPress';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the internationalized product title
|
||||
* Get the product title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_title() {
|
||||
return __( 'Jetpack VideoPress', 'jetpack-my-jetpack' );
|
||||
return 'Jetpack VideoPress';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,6 +126,15 @@ class Videopress extends Hybrid_Product {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL the user is taken after purchasing the product through the checkout
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public static function get_post_checkout_url() {
|
||||
return self::get_manage_url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the WPCOM product slug used to make the purchase
|
||||
*
|
||||
@ -164,7 +172,6 @@ class Videopress extends Hybrid_Product {
|
||||
* @return boolean
|
||||
*/
|
||||
public static function has_required_plan() {
|
||||
// using second argument `true` to force fetching from wpcom
|
||||
return Current_Plan::supports( 'videopress-1tb-storage', true );
|
||||
return static::does_site_have_feature( 'videopress' );
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user