PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.8.3
Jetpack – WP Security, Backup, Speed, & Growth v12.8.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / _inc / lib / admin-pages / class-jetpack-redux-state-helper.php
jetpack / _inc / lib / admin-pages Last commit date
class-jetpack-about-page.php 3 years ago class-jetpack-redux-state-helper.php 2 years ago class.jetpack-admin-page.php 3 years ago class.jetpack-landing-page.php 2 years ago class.jetpack-react-page.php 3 years ago class.jetpack-settings-page.php 3 years ago
class-jetpack-redux-state-helper.php
558 lines
1 <?php
2 /**
3 * A utility class that generates the initial state for Redux in wp-admin.
4 * Modularized from `class.jetpack-react-page.php`.
5 *
6 * @package automattic/jetpack
7 */
8
9 use Automattic\Jetpack\Blaze;
10 use Automattic\Jetpack\Boost_Speed_Score\Speed_Score_History;
11 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12 use Automattic\Jetpack\Connection\Plugin_Storage as Connection_Plugin_Storage;
13 use Automattic\Jetpack\Connection\REST_Connector;
14 use Automattic\Jetpack\Constants;
15 use Automattic\Jetpack\Current_Plan as Jetpack_Plan;
16 use Automattic\Jetpack\Device_Detection\User_Agent_Info;
17 use Automattic\Jetpack\Identity_Crisis;
18 use Automattic\Jetpack\Image_CDN\Image_CDN_Core;
19 use Automattic\Jetpack\Image_CDN\Image_CDN_Image;
20 use Automattic\Jetpack\IP\Utils as IP_Utils;
21 use Automattic\Jetpack\Licensing;
22 use Automattic\Jetpack\Licensing\Endpoints as Licensing_Endpoints;
23 use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer;
24 use Automattic\Jetpack\Partner;
25 use Automattic\Jetpack\Partner_Coupon as Jetpack_Partner_Coupon;
26 use Automattic\Jetpack\Stats\Options as Stats_Options;
27 use Automattic\Jetpack\Status;
28 use Automattic\Jetpack\Status\Host;
29
30 /**
31 * Responsible for populating the initial Redux state.
32 */
33 class Jetpack_Redux_State_Helper {
34 /**
35 * Generate minimal state for React to fetch its own data asynchronously after load
36 * This can improve user experience, reducing time spent on server requests before serving the page
37 * e.g. used by React Disconnect Dialog on plugins page where the full initial state is not needed
38 */
39 public static function get_minimal_state() {
40 return array(
41 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
42 /* This filter is documented in class.jetpack-connection-banner.php */
43 'preConnectionHelpers' => apply_filters( 'jetpack_pre_connection_prompt_helpers', false ),
44 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
45 'WP_API_root' => esc_url_raw( rest_url() ),
46 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
47 );
48 }
49
50 /**
51 * Generate the initial state array to be used by the Redux store.
52 */
53 public static function get_initial_state() {
54 global $is_safari;
55
56 // Load API endpoint base classes and endpoints for getting the module list fed into the JS Admin Page.
57 require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php';
58 require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php';
59 require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php';
60
61 $module_list_endpoint = new Jetpack_Core_API_Module_List_Endpoint();
62 $modules = $module_list_endpoint->get_modules();
63
64 // Preparing translated fields for JSON encoding by transforming all HTML entities to
65 // respective characters.
66 foreach ( $modules as $slug => $data ) {
67 $modules[ $slug ]['name'] = html_entity_decode( $data['name'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
68 $modules[ $slug ]['description'] = html_entity_decode( $data['description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
69 $modules[ $slug ]['short_description'] = html_entity_decode( $data['short_description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
70 $modules[ $slug ]['long_description'] = html_entity_decode( $data['long_description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
71 }
72
73 // "mock" a block module in order to get it searchable in the settings.
74 $modules['blocks']['module'] = 'blocks';
75 $modules['blocks']['additional_search_queries'] = esc_html_x( 'blocks, block, gutenberg', 'Search terms', 'jetpack' );
76
77 // "mock" an Earn module in order to get it searchable in the settings.
78 $modules['earn']['module'] = 'earn';
79 $modules['earn']['additional_search_queries'] = esc_html_x( 'earn, paypal, stripe, payments, pay', 'Search terms', 'jetpack' );
80
81 // Collecting roles that can view site stats.
82 $stats_roles = array();
83 $enabled_roles = Stats_Options::get_option( 'roles' );
84
85 if ( ! function_exists( 'get_editable_roles' ) ) {
86 require_once ABSPATH . 'wp-admin/includes/user.php';
87 }
88 foreach ( get_editable_roles() as $slug => $role ) {
89 $stats_roles[ $slug ] = array(
90 'name' => translate_user_role( $role['name'] ),
91 'canView' => is_array( $enabled_roles ) ? in_array( $slug, $enabled_roles, true ) : false,
92 );
93 }
94
95 // Get information about current theme.
96 $current_theme = wp_get_theme();
97
98 // Get all themes that Infinite Scroll provides support for natively.
99 $inf_scr_support_themes = array();
100 foreach ( Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules/infinite-scroll/themes' ) as $path ) {
101 if ( is_readable( $path ) ) {
102 $inf_scr_support_themes[] = basename( $path, '.php' );
103 }
104 }
105
106 // Get last post, to build the link to Customizer in the Related Posts module.
107 $last_post = get_posts( array( 'posts_per_page' => 1 ) );
108 $last_post = isset( $last_post[0] ) && $last_post[0] instanceof WP_Post
109 ? get_permalink( $last_post[0]->ID )
110 : get_home_url();
111
112 $current_user_data = jetpack_current_user_data();
113
114 /**
115 * Adds information to the `connectionStatus` API field that is unique to the Jetpack React dashboard.
116 */
117 $connection_status = array(
118 'isInIdentityCrisis' => Identity_Crisis::validate_sync_error_idc_option(),
119 'sandboxDomain' => JETPACK__SANDBOX_DOMAIN,
120
121 /**
122 * Filter to add connection errors
123 * Format: array( array( 'code' => '...', 'message' => '...', 'action' => '...' ), ... )
124 *
125 * @since 8.7.0
126 *
127 * @param array $errors Connection errors.
128 */
129 'errors' => apply_filters( 'react_connection_errors_initial_state', array() ),
130 );
131
132 $connection_status = array_merge( REST_Connector::connection_status( false ), $connection_status );
133
134 $host = new Host();
135
136 $speed_score_history = new Speed_Score_History( wp_parse_url( get_site_url(), PHP_URL_HOST ) );
137
138 return array(
139 'WP_API_root' => esc_url_raw( rest_url() ),
140 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ),
141 'registrationNonce' => wp_create_nonce( 'jetpack-registration-nonce' ),
142 'purchaseToken' => self::get_purchase_token(),
143 'partnerCoupon' => Jetpack_Partner_Coupon::get_coupon(),
144 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ),
145 'connectionStatus' => $connection_status,
146 'connectedPlugins' => Connection_Plugin_Storage::get_all(),
147 'connectUrl' => false == $current_user_data['isConnected'] // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
148 ? Jetpack::init()->build_connect_url( true, false, false )
149 : '',
150 'dismissedNotices' => self::get_dismissed_jetpack_notices(),
151 'isDevVersion' => Jetpack::is_development_version(),
152 'currentVersion' => JETPACK__VERSION,
153 'is_gutenberg_available' => true,
154 'getModules' => $modules,
155 'rawUrl' => ( new Status() )->get_site_suffix(),
156 'adminUrl' => esc_url( admin_url() ),
157 'siteTitle' => (string) htmlspecialchars_decode( get_option( 'blogname' ), ENT_QUOTES ),
158 'stats' => array(
159 // data is populated asynchronously on page load.
160 'data' => array(
161 'general' => false,
162 'day' => false,
163 'week' => false,
164 'month' => false,
165 ),
166 'roles' => $stats_roles,
167 ),
168 'aff' => Partner::init()->get_partner_code( Partner::AFFILIATE_CODE ),
169 'partnerSubsidiaryId' => Partner::init()->get_partner_code( Partner::SUBSIDIARY_CODE ),
170 'settings' => self::get_flattened_settings(),
171 'userData' => array(
172 'currentUser' => $current_user_data,
173 ),
174 'siteData' => array(
175 'blog_id' => Jetpack_Options::get_option( 'id', 0 ),
176 'icon' => has_site_icon()
177 ? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) )
178 : '',
179 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ), // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual
180 /**
181 * Whether promotions are visible or not.
182 *
183 * @since 4.8.0
184 *
185 * @param bool $are_promotions_active Status of promotions visibility. True by default.
186 */
187 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ),
188 'isAtomicSite' => $host->is_woa_site(),
189 'isWoASite' => $host->is_woa_site(),
190 'isAtomicPlatform' => $host->is_atomic_platform(),
191 'plan' => Jetpack_Plan::get(),
192 'showBackups' => Jetpack::show_backups_ui(),
193 'showRecommendations' => Jetpack_Recommendations::is_enabled(),
194 /** This filter is documented in my-jetpack/src/class-initializer.php */
195 'showMyJetpack' => My_Jetpack_Initializer::should_initialize(),
196 'isMultisite' => is_multisite(),
197 'dateFormat' => get_option( 'date_format' ),
198 'latestBoostSpeedScores' => $speed_score_history->latest(),
199 ),
200 'themeData' => array(
201 'name' => $current_theme->get( 'Name' ),
202 'stylesheet' => $current_theme->get_stylesheet(),
203 'hasUpdate' => (bool) get_theme_update_available( $current_theme ),
204 'isBlockTheme' => (bool) $current_theme->is_block_theme(),
205 'support' => array(
206 'infinite-scroll' => current_theme_supports( 'infinite-scroll' ) || in_array( $current_theme->get_stylesheet(), $inf_scr_support_themes, true ),
207 'widgets' => current_theme_supports( 'widgets' ),
208 'webfonts' => wp_theme_has_theme_json()
209 && ( function_exists( 'wp_register_webfont_provider' ) || function_exists( 'wp_register_webfonts' ) ),
210 ),
211 ),
212 'jetpackStateNotices' => array(
213 'messageCode' => Jetpack::state( 'message' ),
214 'errorCode' => Jetpack::state( 'error' ),
215 'errorDescription' => Jetpack::state( 'error_description' ),
216 'messageContent' => Jetpack::state( 'display_update_modal' ) ? self::get_update_modal_data() : null,
217 ),
218 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
219 'currentIp' => IP_Utils::get_ip(),
220 'lastPostUrl' => esc_url( $last_post ),
221 'externalServicesConnectUrls' => self::get_external_services_connect_urls(),
222 'calypsoEnv' => ( new Host() )->get_calypso_env(),
223 'products' => Jetpack::get_products_for_purchase(),
224 'recommendationsStep' => Jetpack_Core_Json_Api_Endpoints::get_recommendations_step()['step'],
225 'isSafari' => $is_safari || User_Agent_Info::is_opera_desktop(), // @todo Rename isSafari everywhere.
226 'doNotUseConnectionIframe' => Constants::is_true( 'JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME' ),
227 'licensing' => array(
228 'error' => Licensing::instance()->last_error(),
229 'showLicensingUi' => Licensing::instance()->is_licensing_input_enabled(),
230 'userCounts' => Licensing_Endpoints::get_user_license_counts(),
231 'activationNoticeDismiss' => Licensing::instance()->get_license_activation_notice_dismiss(),
232 ),
233 'hasSeenWCConnectionModal' => Jetpack_Options::get_option( 'has_seen_wc_connection_modal', false ),
234 'newRecommendations' => Jetpack_Recommendations::get_new_conditional_recommendations(),
235 // Check if WooCommerce plugin is active (based on https://docs.woocommerce.com/document/create-a-plugin/).
236 'isWooCommerceActive' => in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', Jetpack::get_active_plugins() ), true ),
237 'useMyJetpackLicensingUI' => My_Jetpack_Initializer::is_licensing_ui_enabled(),
238 'isOdysseyStatsEnabled' => Stats_Options::get_option( 'enable_odyssey_stats' ),
239 'shouldInitializeBlaze' => Blaze::should_initialize(),
240 'isBlazeDashboardEnabled' => Blaze::is_dashboard_enabled(),
241 /** This filter is documented in plugins/jetpack/modules/subscriptions/subscribe-module/class-jetpack-subscribe-module.php */
242 'isSubscriptionModalEnabled' => apply_filters( 'jetpack_subscriptions_modal_enabled', false ),
243 'socialInitialState' => self::get_publicize_initial_state(),
244 'gutenbergInitialState' => self::get_gutenberg_initial_state(),
245 );
246 }
247
248 /**
249 * Get information about the Gutenberg plugin and its Interactivity API support.
250 *
251 * @see https://make.wordpress.org/core/tag/interactivity-api/
252 *
253 * @return array
254 */
255 private static function get_gutenberg_initial_state() {
256 // If Gutenberg is not installed,
257 // check if we run a version of WP that would include support.
258 if ( ! Constants::is_true( 'IS_GUTENBERG_PLUGIN' ) ) {
259 global $wp_version;
260 return array(
261 'isAvailable' => false,
262 'hasInteractivityApi' => version_compare( $wp_version, '6.4', '>=' ),
263 );
264 }
265
266 // If we're running a dev version, assume it's the latest.
267 if ( Constants::is_true( 'GUTENBERG_DEVELOPMENT_MODE' ) ) {
268 return array(
269 'isAvailable' => true,
270 'hasInteractivityApi' => true,
271 );
272 }
273
274 $gutenberg_version = Constants::get_constant( 'GUTENBERG_VERSION' );
275 if ( ! $gutenberg_version ) {
276 return array(
277 'isAvailable' => false,
278 'hasInteractivityApi' => false,
279 );
280 }
281
282 return array(
283 'isAvailable' => true,
284 'hasInteractivityApi' => version_compare( $gutenberg_version, '16.6.0', '>=' ),
285 );
286 }
287
288 /**
289 * Gets the initial state for the Publicize module.
290 *
291 * @return array|null
292 */
293 public static function get_publicize_initial_state() {
294 $sig_settings = new Automattic\Jetpack\Publicize\Social_Image_Generator\Settings();
295 $auto_conversion_settings = new Automattic\Jetpack\Publicize\Auto_Conversion\Settings();
296
297 if ( empty( $sig_settings ) && empty( $auto_conversion_settings ) ) {
298 return null;
299 }
300
301 return array(
302 'socialImageGeneratorSettings' => array(
303 'available' => $sig_settings->is_available(),
304 'enabled' => $sig_settings->is_enabled(),
305 'defaultTemplate' => $sig_settings->get_default_template(),
306 ),
307 'autoConversionSettings' => array(
308 'available' => $auto_conversion_settings->is_available( 'image' ),
309 'image' => $auto_conversion_settings->is_enabled( 'image' ),
310 ),
311 );
312 }
313
314 /**
315 * Gets array of any Jetpack notices that have been dismissed.
316 *
317 * @return mixed|void
318 */
319 public static function get_dismissed_jetpack_notices() {
320 $jetpack_dismissed_notices = get_option( 'jetpack_dismissed_notices', array() );
321 /**
322 * Array of notices that have been dismissed.
323 *
324 * @param array $jetpack_dismissed_notices If empty, will not show any Jetpack notices.
325 */
326 $dismissed_notices = apply_filters( 'jetpack_dismissed_notices', $jetpack_dismissed_notices );
327 return $dismissed_notices;
328 }
329
330 /**
331 * Returns an array of modules and settings both as first class members of the object.
332 *
333 * @return array flattened settings with modules.
334 */
335 public static function get_flattened_settings() {
336 $core_api_endpoint = new Jetpack_Core_API_Data();
337 $settings = $core_api_endpoint->get_all_options();
338 return $settings->data;
339 }
340
341 /**
342 * Returns the release post content and image data as an associative array.
343 * This data is used to create the update modal.
344 */
345 public static function get_update_modal_data() {
346 $post_data = self::get_release_post_data();
347
348 if ( ! isset( $post_data['posts'][0] ) ) {
349 return;
350 }
351
352 $post = $post_data['posts'][0];
353
354 if ( empty( $post['content'] ) ) {
355 return;
356 }
357
358 // This allows us to embed videopress videos into the release post.
359 add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10, 2 );
360 $content = wp_kses_post( $post['content'] );
361 remove_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10, 2 );
362
363 $post_title = isset( $post['title'] ) ? $post['title'] : null;
364 $title = wp_kses( $post_title, array() );
365
366 $post_thumbnail = isset( $post['post_thumbnail'] ) ? $post['post_thumbnail'] : null;
367 if ( ! empty( $post_thumbnail ) ) {
368 $photon_image = new Image_CDN_Image(
369 array(
370 'file' => Image_CDN_Core::cdn_url( $post_thumbnail['URL'] ),
371 'width' => $post_thumbnail['width'],
372 'height' => $post_thumbnail['height'],
373 ),
374 $post_thumbnail['mime_type']
375 );
376 $photon_image->resize(
377 array(
378 'width' => 600,
379 'height' => null,
380 'crop' => false,
381 )
382 );
383 $post_thumbnail_url = $photon_image->get_raw_filename();
384 } else {
385 $post_thumbnail_url = null;
386 }
387
388 $post_array = array(
389 'release_post_content' => $content,
390 'release_post_featured_image' => $post_thumbnail_url,
391 'release_post_title' => $title,
392 );
393
394 return $post_array;
395 }
396
397 /**
398 * Temporarily allow post content to contain iframes, e.g. for videopress.
399 *
400 * @param string $tags The tags.
401 * @param string $context The context.
402 */
403 public static function allow_post_embed_iframe( $tags, $context ) {
404 if ( 'post' === $context ) {
405 $tags['iframe'] = array(
406 'src' => true,
407 'height' => true,
408 'width' => true,
409 'frameborder' => true,
410 'allowfullscreen' => true,
411 );
412 }
413
414 return $tags;
415 }
416
417 /**
418 * Obtains the release post from the Jetpack release post blog. A release post will be displayed in the
419 * update modal when a post has a tag equal to the Jetpack version number.
420 *
421 * The response parameters for the post array can be found here:
422 * https://developer.wordpress.com/docs/api/1.1/get/sites/%24site/posts/%24post_ID/#apidoc-response
423 *
424 * @return array|null Returns an associative array containing the release post data at index ['posts'][0].
425 * Returns null if the release post data is not available.
426 */
427 public static function get_release_post_data() {
428 if ( Constants::is_defined( 'TESTING_IN_JETPACK' ) && Constants::get_constant( 'TESTING_IN_JETPACK' ) ) {
429 return null;
430 }
431
432 $release_post_src = add_query_arg(
433 array(
434 'order_by' => 'date',
435 'tag' => JETPACK__VERSION,
436 'number' => '1',
437 ),
438 'https://public-api.wordpress.com/rest/v1/sites/' . JETPACK__RELEASE_POST_BLOG_SLUG . '/posts'
439 );
440
441 $response = wp_remote_get( $release_post_src );
442
443 if ( ! is_array( $response ) ) {
444 return null;
445 }
446
447 return json_decode( wp_remote_retrieve_body( $response ), true );
448 }
449
450 /**
451 * Get external services connect URLs.
452 */
453 public static function get_external_services_connect_urls() {
454 $connect_urls = array();
455 require_once JETPACK__PLUGIN_DIR . '_inc/lib/class.jetpack-keyring-service-helper.php';
456 // phpcs:disable
457 foreach ( Jetpack_Keyring_Service_Helper::SERVICES as $service_name => $service_info ) {
458 // phpcs:enable
459 $connect_urls[ $service_name ] = Jetpack_Keyring_Service_Helper::connect_url( $service_name, $service_info['for'] );
460 }
461 return $connect_urls;
462 }
463
464 /**
465 * Gets a purchase token that is used for Jetpack logged out visitor checkout.
466 * The purchase token should be appended to all CTA url's that lead to checkout.
467 *
468 * @since 9.8.0
469 * @return string|boolean
470 */
471 public static function get_purchase_token() {
472 if ( ! Jetpack::current_user_can_purchase() ) {
473 return false;
474 }
475
476 $purchase_token = Jetpack_Options::get_option( 'purchase_token', false );
477
478 if ( $purchase_token ) {
479 return $purchase_token;
480 }
481 // If the purchase token is not saved in the options table yet, then add it.
482 Jetpack_Options::update_option( 'purchase_token', self::generate_purchase_token(), true );
483 return Jetpack_Options::get_option( 'purchase_token', false );
484 }
485
486 /**
487 * Generates a purchase token that is used for Jetpack logged out visitor checkout.
488 *
489 * @since 9.8.0
490 * @return string
491 */
492 public static function generate_purchase_token() {
493 return wp_generate_password( 12, false );
494 }
495 }
496
497 // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move these functions to some other file.
498
499 /**
500 * Gather data about the current user.
501 *
502 * @since 4.1.0
503 *
504 * @return array
505 */
506 function jetpack_current_user_data() {
507 $jetpack_connection = new Connection_Manager( 'jetpack' );
508
509 $current_user = wp_get_current_user();
510 $is_user_connected = $jetpack_connection->is_user_connected( $current_user->ID );
511 $is_master_user = $is_user_connected && (int) $current_user->ID && (int) Jetpack_Options::get_option( 'master_user' ) === (int) $current_user->ID;
512 $dotcom_data = $jetpack_connection->get_connected_user_data();
513
514 // Add connected user gravatar to the returned dotcom_data.
515 // Probably we shouldn't do this when $dotcom_data is false, but we have been since 2016 so
516 // clients probably expect that by now.
517 if ( false === $dotcom_data ) {
518 $dotcom_data = array();
519 }
520 $dotcom_data['avatar'] = ( ! empty( $dotcom_data['email'] ) ?
521 get_avatar_url(
522 $dotcom_data['email'],
523 array(
524 'size' => 64,
525 'default' => 'mysteryman',
526 )
527 )
528 : false );
529
530 $current_user_data = array(
531 'isConnected' => $is_user_connected,
532 'isMaster' => $is_master_user,
533 'username' => $current_user->user_login,
534 'id' => $current_user->ID,
535 'wpcomUser' => $dotcom_data,
536 'gravatar' => get_avatar_url( $current_user->ID, 64, 'mm', '', array( 'force_display' => true ) ),
537 'permissions' => array(
538 'admin_page' => current_user_can( 'jetpack_admin_page' ),
539 'connect' => current_user_can( 'jetpack_connect' ),
540 'connect_user' => current_user_can( 'jetpack_connect_user' ),
541 'disconnect' => current_user_can( 'jetpack_disconnect' ),
542 'manage_modules' => current_user_can( 'jetpack_manage_modules' ),
543 'network_admin' => current_user_can( 'jetpack_network_admin_page' ),
544 'network_sites_page' => current_user_can( 'jetpack_network_sites_page' ),
545 'edit_posts' => current_user_can( 'edit_posts' ),
546 'publish_posts' => current_user_can( 'publish_posts' ),
547 'manage_options' => current_user_can( 'manage_options' ),
548 'view_stats' => current_user_can( 'view_stats' ),
549 'manage_plugins' => current_user_can( 'install_plugins' )
550 && current_user_can( 'activate_plugins' )
551 && current_user_can( 'update_plugins' )
552 && current_user_can( 'delete_plugins' ),
553 ),
554 );
555
556 return $current_user_data;
557 }
558