Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
58.89% |
159 / 270 |
|
33.33% |
4 / 12 |
CRAP | |
0.00% |
0 / 1 |
| jetpack_current_user_data | |
0.00% |
0 / 44 |
|
0.00% |
0 / 1 |
72 | |||
| Jetpack_Redux_State_Helper | |
70.35% |
159 / 226 |
|
36.36% |
4 / 11 |
78.63 | |
0.00% |
0 / 1 |
| get_minimal_state | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
| get_initial_state | |
97.90% |
140 / 143 |
|
0.00% |
0 / 1 |
17 | |||
| get_dismissed_jetpack_notices | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| get_flattened_settings | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
| get_update_modal_data | |
8.33% |
3 / 36 |
|
0.00% |
0 / 1 |
33.73 | |||
| allow_post_embed_iframe | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
6 | |||
| get_release_post_data | |
14.29% |
2 / 14 |
|
0.00% |
0 / 1 |
14.08 | |||
| get_external_services_connect_urls | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
| get_purchase_token | |
28.57% |
2 / 7 |
|
0.00% |
0 / 1 |
6.28 | |||
| generate_purchase_token | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| get_site_image | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| 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\My_Jetpack\Jetpack_Manage; |
| 25 | use Automattic\Jetpack\Partner; |
| 26 | use Automattic\Jetpack\Partner_Coupon as Jetpack_Partner_Coupon; |
| 27 | use Automattic\Jetpack\Publicize\Keyring_Helper; |
| 28 | use Automattic\Jetpack\Stats\Options as Stats_Options; |
| 29 | use Automattic\Jetpack\Status; |
| 30 | use Automattic\Jetpack\Status\Host; |
| 31 | |
| 32 | /** |
| 33 | * Responsible for populating the initial Redux state. |
| 34 | */ |
| 35 | class Jetpack_Redux_State_Helper { |
| 36 | /** |
| 37 | * Generate minimal state for React to fetch its own data asynchronously after load |
| 38 | * This can improve user experience, reducing time spent on server requests before serving the page |
| 39 | * e.g. used by React Disconnect Dialog on plugins page where the full initial state is not needed |
| 40 | */ |
| 41 | public static function get_minimal_state() { |
| 42 | return array( |
| 43 | 'WP_API_root' => esc_url_raw( rest_url() ), |
| 44 | 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ), |
| 45 | ); |
| 46 | } |
| 47 | |
| 48 | /** |
| 49 | * Generate the initial state array to be used by the Redux store. |
| 50 | */ |
| 51 | public static function get_initial_state() { |
| 52 | global $is_safari; |
| 53 | |
| 54 | // Load API endpoint base classes and endpoints for getting the module list fed into the JS Admin Page. |
| 55 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php'; |
| 56 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php'; |
| 57 | require_once JETPACK__PLUGIN_DIR . '_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php'; |
| 58 | |
| 59 | $module_list_endpoint = new Jetpack_Core_API_Module_List_Endpoint(); |
| 60 | $modules = $module_list_endpoint->get_modules(); |
| 61 | |
| 62 | // Preparing translated fields for JSON encoding by transforming all HTML entities to |
| 63 | // respective characters. |
| 64 | foreach ( $modules as $slug => $data ) { |
| 65 | $modules[ $slug ]['name'] = html_entity_decode( $data['name'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ); |
| 66 | $modules[ $slug ]['description'] = html_entity_decode( $data['description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ); |
| 67 | $modules[ $slug ]['short_description'] = html_entity_decode( $data['short_description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ); |
| 68 | $modules[ $slug ]['long_description'] = html_entity_decode( $data['long_description'], ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ); |
| 69 | } |
| 70 | |
| 71 | // "mock" a block module in order to get it searchable in the settings. |
| 72 | $modules['blocks']['module'] = 'blocks'; |
| 73 | $modules['blocks']['additional_search_queries'] = esc_html_x( 'blocks, block, gutenberg', 'Search terms', 'jetpack' ); |
| 74 | |
| 75 | // "mock" an Earn module in order to get it searchable in the settings. |
| 76 | $modules['earn']['module'] = 'earn'; |
| 77 | $modules['earn']['additional_search_queries'] = esc_html_x( 'earn, paypal, stripe, payments, pay', 'Search terms', 'jetpack' ); |
| 78 | |
| 79 | // Collecting roles that can view site stats. |
| 80 | $stats_roles = array(); |
| 81 | $enabled_roles = Stats_Options::get_option( 'roles' ); |
| 82 | |
| 83 | if ( ! function_exists( 'get_editable_roles' ) ) { |
| 84 | require_once ABSPATH . 'wp-admin/includes/user.php'; |
| 85 | } |
| 86 | foreach ( get_editable_roles() as $slug => $role ) { |
| 87 | $stats_roles[ $slug ] = array( |
| 88 | 'name' => translate_user_role( $role['name'] ), |
| 89 | 'canView' => is_array( $enabled_roles ) ? in_array( $slug, $enabled_roles, true ) : false, |
| 90 | ); |
| 91 | } |
| 92 | |
| 93 | // Get information about current theme. |
| 94 | $current_theme = wp_get_theme(); |
| 95 | |
| 96 | // Get all themes that Infinite Scroll provides support for natively. |
| 97 | $inf_scr_support_themes = array(); |
| 98 | foreach ( Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules/infinite-scroll/themes' ) as $path ) { |
| 99 | if ( is_readable( $path ) ) { |
| 100 | $inf_scr_support_themes[] = basename( $path, '.php' ); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | // Get last post, to build the link to Customizer in the Related Posts module. |
| 105 | $last_post = get_posts( array( 'posts_per_page' => 1 ) ); |
| 106 | $last_post = isset( $last_post[0] ) && $last_post[0] instanceof WP_Post |
| 107 | ? get_permalink( $last_post[0]->ID ) |
| 108 | : get_home_url(); |
| 109 | |
| 110 | $current_user_data = jetpack_current_user_data(); |
| 111 | |
| 112 | /** |
| 113 | * Adds information to the `connectionStatus` API field that is unique to the Jetpack React dashboard. |
| 114 | */ |
| 115 | $connection_status = array( |
| 116 | 'isInIdentityCrisis' => Identity_Crisis::validate_sync_error_idc_option(), |
| 117 | 'sandboxDomain' => JETPACK__SANDBOX_DOMAIN, |
| 118 | |
| 119 | /** |
| 120 | * Filter to add connection errors |
| 121 | * Format: array( array( 'code' => '...', 'message' => '...', 'action' => '...' ), ... ) |
| 122 | * |
| 123 | * @since 8.7.0 |
| 124 | * |
| 125 | * @param array $errors Connection errors. |
| 126 | */ |
| 127 | 'errors' => apply_filters( 'react_connection_errors_initial_state', array() ), |
| 128 | ); |
| 129 | |
| 130 | $connection_status = array_merge( REST_Connector::connection_status( false ), $connection_status ); |
| 131 | |
| 132 | $speed_score_history = new Speed_Score_History( wp_parse_url( get_site_url(), PHP_URL_HOST ) ); |
| 133 | |
| 134 | $block_availability = Jetpack_Gutenberg::get_cached_availability(); |
| 135 | |
| 136 | return array( |
| 137 | 'WP_API_root' => esc_url_raw( rest_url() ), |
| 138 | 'WP_API_nonce' => wp_create_nonce( 'wp_rest' ), |
| 139 | 'registrationNonce' => '', // Not used, keeping it for compatibility reasons, see https://github.com/Automattic/jetpack/pull/42076 |
| 140 | 'purchaseToken' => self::get_purchase_token(), |
| 141 | 'partnerCoupon' => Jetpack_Partner_Coupon::get_coupon(), |
| 142 | 'pluginBaseUrl' => plugins_url( '', JETPACK__PLUGIN_FILE ), |
| 143 | 'connectionStatus' => $connection_status, |
| 144 | 'connectedPlugins' => Connection_Plugin_Storage::get_all(), |
| 145 | 'connectUrl' => false == $current_user_data['isConnected'] // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual |
| 146 | ? Jetpack::init()->build_connect_url( true, false, false ) |
| 147 | : '', |
| 148 | 'dismissedNotices' => self::get_dismissed_jetpack_notices(), |
| 149 | 'isDevVersion' => Jetpack::is_development_version(), |
| 150 | 'currentVersion' => JETPACK__VERSION, |
| 151 | 'is_gutenberg_available' => true, |
| 152 | 'getModules' => $modules, |
| 153 | 'rawUrl' => ( new Status() )->get_site_suffix(), |
| 154 | 'adminUrl' => esc_url( admin_url() ), |
| 155 | 'siteTitle' => htmlspecialchars_decode( get_option( 'blogname' ), ENT_QUOTES ), |
| 156 | 'stats' => array( |
| 157 | // data is populated asynchronously on page load. |
| 158 | 'data' => array( |
| 159 | 'general' => false, |
| 160 | 'day' => false, |
| 161 | 'week' => false, |
| 162 | 'month' => false, |
| 163 | ), |
| 164 | 'roles' => $stats_roles, |
| 165 | ), |
| 166 | 'aff' => Partner::init()->get_partner_code( Partner::AFFILIATE_CODE ), |
| 167 | 'partnerSubsidiaryId' => Partner::init()->get_partner_code( Partner::SUBSIDIARY_CODE ), |
| 168 | 'settings' => self::get_flattened_settings(), |
| 169 | 'userData' => array( |
| 170 | 'currentUser' => $current_user_data, |
| 171 | ), |
| 172 | 'siteData' => array( |
| 173 | 'blog_id' => Jetpack_Options::get_option( 'id', 0 ), |
| 174 | 'icon' => has_site_icon() |
| 175 | ? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) ) |
| 176 | : '', |
| 177 | 'representativeImage' => self::get_site_image(), |
| 178 | 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ), // phpcs:ignore Universal.Operators.StrictComparisons.LooseEqual |
| 179 | /** |
| 180 | * Whether promotions are visible or not. |
| 181 | * |
| 182 | * @since 4.8.0 |
| 183 | * |
| 184 | * @param bool $are_promotions_active Status of promotions visibility. True by default. |
| 185 | */ |
| 186 | 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ), |
| 187 | 'plan' => Jetpack_Plan::get(), |
| 188 | 'showBackups' => Jetpack::show_backups_ui(), |
| 189 | 'showRecommendations' => Jetpack_Recommendations::is_enabled(), |
| 190 | /** This filter is documented in my-jetpack/src/class-initializer.php */ |
| 191 | 'showMyJetpack' => My_Jetpack_Initializer::should_initialize(), |
| 192 | 'isMultisite' => is_multisite(), |
| 193 | 'dateFormat' => get_option( 'date_format' ), |
| 194 | 'latestBoostSpeedScores' => $speed_score_history->latest(), |
| 195 | 'isSharingBlockAvailable' => isset( $block_availability['sharing-buttons'] ) |
| 196 | && $block_availability['sharing-buttons']['available'], |
| 197 | ), |
| 198 | 'themeData' => array( |
| 199 | 'name' => $current_theme->get( 'Name' ), |
| 200 | 'stylesheet' => $current_theme->get_stylesheet(), |
| 201 | 'hasUpdate' => (bool) get_theme_update_available( $current_theme ), |
| 202 | 'isBlockTheme' => (bool) $current_theme->is_block_theme(), |
| 203 | 'support' => array( |
| 204 | 'infinite-scroll' => current_theme_supports( 'infinite-scroll' ) || in_array( $current_theme->get_stylesheet(), $inf_scr_support_themes, true ), |
| 205 | 'widgets' => current_theme_supports( 'widgets' ), |
| 206 | 'webfonts' => wp_theme_has_theme_json() |
| 207 | && ( function_exists( 'wp_register_webfont_provider' ) || function_exists( 'wp_register_webfonts' ) ), |
| 208 | ), |
| 209 | ), |
| 210 | 'jetpackStateNotices' => array( |
| 211 | 'messageCode' => Jetpack::state( 'message' ), |
| 212 | 'errorCode' => Jetpack::state( 'error' ), |
| 213 | 'errorDescription' => Jetpack::state( 'error_description' ), |
| 214 | 'messageContent' => Jetpack::state( 'display_update_modal' ) ? self::get_update_modal_data() : null, |
| 215 | ), |
| 216 | 'tracksUserData' => Jetpack_Tracks_Client::get_connected_user_tracks_identity(), |
| 217 | 'currentIp' => IP_Utils::get_ip(), |
| 218 | 'lastPostUrl' => esc_url( $last_post ), |
| 219 | 'externalServicesConnectUrls' => self::get_external_services_connect_urls(), |
| 220 | 'calypsoEnv' => ( new Host() )->get_calypso_env(), |
| 221 | 'products' => Jetpack::get_products_for_purchase(), |
| 222 | 'recommendationsStep' => Jetpack_Core_Json_Api_Endpoints::get_recommendations_step()['step'], |
| 223 | 'isSafari' => $is_safari || User_Agent_Info::is_opera_desktop(), // @todo Rename isSafari everywhere. |
| 224 | 'doNotUseConnectionIframe' => Constants::is_true( 'JETPACK_SHOULD_NOT_USE_CONNECTION_IFRAME' ), |
| 225 | 'licensing' => array( |
| 226 | 'error' => Licensing::instance()->last_error(), |
| 227 | 'showLicensingUi' => Licensing::instance()->is_licensing_input_enabled(), |
| 228 | 'userCounts' => Licensing_Endpoints::get_user_license_counts(), |
| 229 | 'activationNoticeDismiss' => Licensing::instance()->get_license_activation_notice_dismiss(), |
| 230 | ), |
| 231 | 'jetpackManage' => array( |
| 232 | 'isEnabled' => Jetpack_Manage::could_use_jp_manage(), |
| 233 | 'isAgencyAccount' => Jetpack_Manage::is_agency_account(), |
| 234 | ), |
| 235 | 'hasSeenWCConnectionModal' => Jetpack_Options::get_option( 'has_seen_wc_connection_modal', false ), |
| 236 | 'newRecommendations' => Jetpack_Recommendations::get_new_conditional_recommendations(), |
| 237 | // Check if WooCommerce plugin is active (based on https://docs.woocommerce.com/document/create-a-plugin/). |
| 238 | 'isWooCommerceActive' => in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', Jetpack::get_active_plugins() ), true ), |
| 239 | 'useMyJetpackLicensingUI' => My_Jetpack_Initializer::is_licensing_ui_enabled(), |
| 240 | 'isOdysseyStatsEnabled' => Stats_Options::get_option( 'enable_odyssey_stats' ), |
| 241 | 'shouldInitializeBlaze' => Blaze::should_initialize(), |
| 242 | 'isBlazeDashboardEnabled' => Blaze::is_dashboard_enabled(), |
| 243 | 'isSubscriptionSiteEnabled' => apply_filters( 'jetpack_subscription_site_enabled', false ), |
| 244 | 'newsletterDateExample' => gmdate( get_option( 'date_format' ), time() ), |
| 245 | 'subscriptionSiteEditSupported' => $current_theme->is_block_theme(), |
| 246 | /* This filter is already documented in jetpack/modules/subscriptions.php */ |
| 247 | 'isWpAdminSubscriberManagementEnabled' => apply_filters( 'jetpack_wp_admin_subscriber_management_enabled', false ), |
| 248 | ); |
| 249 | } |
| 250 | |
| 251 | /** |
| 252 | * Gets array of any Jetpack notices that have been dismissed. |
| 253 | * |
| 254 | * @return mixed|void |
| 255 | */ |
| 256 | public static function get_dismissed_jetpack_notices() { |
| 257 | $jetpack_dismissed_notices = get_option( 'jetpack_dismissed_notices', array() ); |
| 258 | /** |
| 259 | * Array of notices that have been dismissed. |
| 260 | * |
| 261 | * @param array $jetpack_dismissed_notices If empty, will not show any Jetpack notices. |
| 262 | */ |
| 263 | $dismissed_notices = apply_filters( 'jetpack_dismissed_notices', $jetpack_dismissed_notices ); |
| 264 | return $dismissed_notices; |
| 265 | } |
| 266 | |
| 267 | /** |
| 268 | * Returns an array of modules and settings both as first class members of the object. |
| 269 | * |
| 270 | * @return array flattened settings with modules. |
| 271 | */ |
| 272 | public static function get_flattened_settings() { |
| 273 | $core_api_endpoint = new Jetpack_Core_API_Data(); |
| 274 | $settings = $core_api_endpoint->get_all_options(); |
| 275 | return $settings->data; |
| 276 | } |
| 277 | |
| 278 | /** |
| 279 | * Returns the release post content and image data as an associative array. |
| 280 | * This data is used to create the update modal. |
| 281 | */ |
| 282 | public static function get_update_modal_data() { |
| 283 | $post_data = self::get_release_post_data(); |
| 284 | |
| 285 | if ( ! isset( $post_data['posts'][0] ) ) { |
| 286 | return; |
| 287 | } |
| 288 | |
| 289 | $post = $post_data['posts'][0]; |
| 290 | |
| 291 | if ( empty( $post['content'] ) ) { |
| 292 | return; |
| 293 | } |
| 294 | |
| 295 | // This allows us to embed videopress videos into the release post. |
| 296 | add_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10, 2 ); |
| 297 | $content = wp_kses_post( $post['content'] ); |
| 298 | remove_filter( 'wp_kses_allowed_html', array( __CLASS__, 'allow_post_embed_iframe' ), 10 ); |
| 299 | |
| 300 | $post_title = isset( $post['title'] ) ? $post['title'] : null; |
| 301 | $title = wp_kses( $post_title, array() ); |
| 302 | |
| 303 | $post_thumbnail = isset( $post['post_thumbnail'] ) ? $post['post_thumbnail'] : null; |
| 304 | if ( ! empty( $post_thumbnail ) ) { |
| 305 | $photon_image = new Image_CDN_Image( |
| 306 | array( |
| 307 | 'file' => Image_CDN_Core::cdn_url( $post_thumbnail['URL'] ), |
| 308 | 'width' => $post_thumbnail['width'], |
| 309 | 'height' => $post_thumbnail['height'], |
| 310 | ), |
| 311 | $post_thumbnail['mime_type'] |
| 312 | ); |
| 313 | $photon_image->resize( |
| 314 | array( |
| 315 | 'width' => 600, |
| 316 | 'height' => null, |
| 317 | 'crop' => false, |
| 318 | ) |
| 319 | ); |
| 320 | $post_thumbnail_url = $photon_image->get_raw_filename(); |
| 321 | } else { |
| 322 | $post_thumbnail_url = null; |
| 323 | } |
| 324 | |
| 325 | $post_array = array( |
| 326 | 'release_post_content' => $content, |
| 327 | 'release_post_featured_image' => $post_thumbnail_url, |
| 328 | 'release_post_title' => $title, |
| 329 | ); |
| 330 | |
| 331 | return $post_array; |
| 332 | } |
| 333 | |
| 334 | /** |
| 335 | * Temporarily allow post content to contain iframes, e.g. for videopress. |
| 336 | * |
| 337 | * @param string $tags The tags. |
| 338 | * @param string $context The context. |
| 339 | */ |
| 340 | public static function allow_post_embed_iframe( $tags, $context ) { |
| 341 | if ( 'post' === $context ) { |
| 342 | $tags['iframe'] = array( |
| 343 | 'src' => true, |
| 344 | 'height' => true, |
| 345 | 'width' => true, |
| 346 | 'frameborder' => true, |
| 347 | 'allowfullscreen' => true, |
| 348 | ); |
| 349 | } |
| 350 | |
| 351 | return $tags; |
| 352 | } |
| 353 | |
| 354 | /** |
| 355 | * Obtains the release post from the Jetpack release post blog. A release post will be displayed in the |
| 356 | * update modal when a post has a tag equal to the Jetpack version number. |
| 357 | * |
| 358 | * The response parameters for the post array can be found here: |
| 359 | * https://developer.wordpress.com/docs/api/1.1/get/sites/%24site/posts/%24post_ID/#apidoc-response |
| 360 | * |
| 361 | * @return array|null Returns an associative array containing the release post data at index ['posts'][0]. |
| 362 | * Returns null if the release post data is not available. |
| 363 | */ |
| 364 | public static function get_release_post_data() { |
| 365 | if ( Constants::is_defined( 'TESTING_IN_JETPACK' ) && Constants::get_constant( 'TESTING_IN_JETPACK' ) ) { |
| 366 | return null; |
| 367 | } |
| 368 | |
| 369 | $release_post_src = add_query_arg( |
| 370 | array( |
| 371 | 'order_by' => 'date', |
| 372 | 'tag' => JETPACK__VERSION, |
| 373 | 'number' => '1', |
| 374 | ), |
| 375 | 'https://public-api.wordpress.com/rest/v1/sites/' . JETPACK__RELEASE_POST_BLOG_SLUG . '/posts' |
| 376 | ); |
| 377 | |
| 378 | $response = wp_remote_get( $release_post_src ); |
| 379 | |
| 380 | if ( ! is_array( $response ) ) { |
| 381 | return null; |
| 382 | } |
| 383 | |
| 384 | return json_decode( wp_remote_retrieve_body( $response ), true ); |
| 385 | } |
| 386 | |
| 387 | /** |
| 388 | * Get external services connect URLs. |
| 389 | */ |
| 390 | public static function get_external_services_connect_urls() { |
| 391 | $connect_urls = array(); |
| 392 | // phpcs:disable |
| 393 | foreach ( Keyring_Helper::SERVICES as $service_name => $service_info ) { |
| 394 | // phpcs:enable |
| 395 | $connect_urls[ $service_name ] = Keyring_Helper::connect_url( $service_name, $service_info['for'] ); |
| 396 | } |
| 397 | return $connect_urls; |
| 398 | } |
| 399 | |
| 400 | /** |
| 401 | * Gets a purchase token that is used for Jetpack logged out visitor checkout. |
| 402 | * The purchase token should be appended to all CTA url's that lead to checkout. |
| 403 | * |
| 404 | * @since 9.8.0 |
| 405 | * @return string|boolean |
| 406 | */ |
| 407 | public static function get_purchase_token() { |
| 408 | if ( ! Jetpack::current_user_can_purchase() ) { |
| 409 | return false; |
| 410 | } |
| 411 | |
| 412 | $purchase_token = Jetpack_Options::get_option( 'purchase_token', false ); |
| 413 | |
| 414 | if ( $purchase_token ) { |
| 415 | return $purchase_token; |
| 416 | } |
| 417 | // If the purchase token is not saved in the options table yet, then add it. |
| 418 | Jetpack_Options::update_option( 'purchase_token', self::generate_purchase_token(), true ); |
| 419 | return Jetpack_Options::get_option( 'purchase_token', false ); |
| 420 | } |
| 421 | |
| 422 | /** |
| 423 | * Generates a purchase token that is used for Jetpack logged out visitor checkout. |
| 424 | * |
| 425 | * @since 9.8.0 |
| 426 | * @return string |
| 427 | */ |
| 428 | public static function generate_purchase_token() { |
| 429 | return wp_generate_password( 12, false ); |
| 430 | } |
| 431 | |
| 432 | /** |
| 433 | * Get a representative image for the site. |
| 434 | * |
| 435 | * @since 15.0 |
| 436 | * |
| 437 | * @return string |
| 438 | */ |
| 439 | public static function get_site_image(): string { |
| 440 | // Get the dynamic image generated for the Open Graph Meta tags. |
| 441 | require_once JETPACK__PLUGIN_DIR . 'functions.opengraph.php'; |
| 442 | return jetpack_og_get_fallback_social_image( 200, 200 )['src']; |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move these functions to some other file. |
| 447 | |
| 448 | /** |
| 449 | * Gather data about the current user. |
| 450 | * |
| 451 | * @since 4.1.0 |
| 452 | * |
| 453 | * @return array |
| 454 | */ |
| 455 | function jetpack_current_user_data() { |
| 456 | $jetpack_connection = new Connection_Manager( 'jetpack' ); |
| 457 | |
| 458 | $current_user = wp_get_current_user(); |
| 459 | $is_user_connected = $jetpack_connection->is_user_connected( $current_user->ID ); |
| 460 | $is_master_user = $is_user_connected && (int) $current_user->ID && (int) Jetpack_Options::get_option( 'master_user' ) === (int) $current_user->ID; |
| 461 | $dotcom_data = $jetpack_connection->get_connected_user_data(); |
| 462 | |
| 463 | // Add connected user gravatar to the returned dotcom_data. |
| 464 | // Probably we shouldn't do this when $dotcom_data is false, but we have been since 2016 so |
| 465 | // clients probably expect that by now. |
| 466 | if ( false === $dotcom_data ) { |
| 467 | $dotcom_data = array(); |
| 468 | } |
| 469 | $dotcom_data['avatar'] = ( ! empty( $dotcom_data['email'] ) ? |
| 470 | get_avatar_url( |
| 471 | $dotcom_data['email'], |
| 472 | array( |
| 473 | 'size' => 64, |
| 474 | 'default' => 'mysteryman', |
| 475 | ) |
| 476 | ) |
| 477 | : false ); |
| 478 | |
| 479 | $current_user_data = array( |
| 480 | 'isConnected' => $is_user_connected, |
| 481 | 'isMaster' => $is_master_user, |
| 482 | 'username' => $current_user->user_login, |
| 483 | 'displayName' => $current_user->display_name, |
| 484 | 'email' => $current_user->user_email, |
| 485 | 'id' => $current_user->ID, |
| 486 | 'wpcomUser' => $dotcom_data, |
| 487 | 'gravatar' => get_avatar_url( $current_user->ID ), |
| 488 | 'permissions' => array( |
| 489 | 'admin_page' => current_user_can( 'jetpack_admin_page' ), |
| 490 | 'connect' => current_user_can( 'jetpack_connect' ), |
| 491 | 'connect_user' => current_user_can( 'jetpack_connect_user' ), |
| 492 | 'disconnect' => current_user_can( 'jetpack_disconnect' ), |
| 493 | 'manage_modules' => current_user_can( 'jetpack_manage_modules' ), |
| 494 | 'network_admin' => current_user_can( 'jetpack_network_admin_page' ), |
| 495 | 'network_sites_page' => current_user_can( 'jetpack_network_sites_page' ), |
| 496 | 'edit_posts' => current_user_can( 'edit_posts' ), |
| 497 | 'publish_posts' => current_user_can( 'publish_posts' ), |
| 498 | 'manage_options' => current_user_can( 'manage_options' ), |
| 499 | 'view_stats' => current_user_can( 'view_stats' ), |
| 500 | 'manage_plugins' => current_user_can( 'install_plugins' ) |
| 501 | && current_user_can( 'activate_plugins' ) |
| 502 | && current_user_can( 'update_plugins' ) |
| 503 | && current_user_can( 'delete_plugins' ), |
| 504 | ), |
| 505 | ); |
| 506 | |
| 507 | return $current_user_data; |
| 508 | } |