connection_manager = $connection_manager; } /** * Initializes this class's WP hooks. * * @return void */ public function init_hooks() { add_filter( 'allowed_redirect_hosts', [ $this, 'allowed_redirect_hosts' ] ); } /** * Sends a remote request through Jetpack. * * @param array $args - The arguments to passed to Jetpack. * @param string $body - The body passed on to the HTTP request. * @param bool $is_site_specific - If true, the site ID will be included in the request url. Defaults to true. * @param bool $use_user_token - If true, the request will be signed with the Jetpack connection owner user token rather than blog token. Defaults to false. * * @return array HTTP response on success. * @throws API_Exception - If not connected or request failed. */ public function remote_request( $args, $body = null, $is_site_specific = true, $use_user_token = false ) { // Make sure we're not sending requests if Jetpack is not connected. if ( ! $this->is_connected() ) { Logger::error( 'HTTP_REQUEST_ERROR Site is not connected to WordPress.com' ); throw new API_Exception( __( 'Site is not connected to WordPress.com', 'woocommerce-payments' ), 'wcpay_wpcom_not_connected', 409 // HTTP Conflict status code. ); } $args['blog_id'] = $this->get_blog_id(); if ( $use_user_token ) { $args['user_id'] = $this->connection_manager->get_connection_owner_id(); } if ( $is_site_specific ) { // We expect `url` to include a `%s` placeholder which will allow us inject the blog id. $url = explode( '?', $args['url'], 2 ); $url[0] = sprintf( $url[0], $args['blog_id'] ); $args['url'] = implode( '?', $url ); } return self::make_request( $args, $body ); } /** * Queries the WordPress.com REST API with a user token. * * @param string $path REST API path. * @param string $version REST API version. Default is `2`. * @param array $args Arguments to {@see WP_Http}. Default is `array()`. * @param string|array $body Body passed to {@see WP_Http}. Default is `null`. * @param string $base_api_path REST API root. Default is `wpcom`. * * @return array|\WP_Error $response Response data, else WP_Error on failure. */ public function wpcom_json_api_request_as_user( $path, $version = '2', $args = [], $body = null, $base_api_path = 'wpcom' ) { return Automattic\Jetpack\Connection\Client::wpcom_json_api_request_as_user( $path, $version, $args, $body, $base_api_path ); } /** * Makes a request through Jetpack. * * @param array $args - The arguments passed to Jetpack. * @param string $body - The body passed to the HTTP request. * * @return array HTTP response on success. * @throws Connection_Exception - If request returns WP_Error. */ private static function make_request( $args, $body ) { $response = Automattic\Jetpack\Connection\Client::remote_request( $args, $body ); if ( is_wp_error( $response ) || ! is_array( $response ) ) { Logger::error( 'HTTP_REQUEST_ERROR ' . var_export( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export $message = sprintf( // translators: %1: original error message. __( 'Http request failed. Reason: %1$s', 'woocommerce-payments' ), $response->get_error_message() ); throw new Connection_Exception( $message, 'wcpay_http_request_failed', 500 ); } return $response; } /** * Checks if Jetpack is connected. * * Checks if connection is authenticated in the same way as Jetpack_Client or Jetpack Connection Client does. * * @return bool true if Jetpack connection has access token. */ public function is_connected() { return $this->connection_manager->is_connected() && $this->connection_manager->has_connected_owner(); } /** * Checks if the current user is connected to WordPress.com. * * @return bool true if the current user is connected. */ public function is_user_connected() { return $this->connection_manager->is_user_connected(); } /** * Get the wpcom user data of the current connected user. * * @return bool|array An array with the WPCOM user data on success, false otherwise. */ public function get_connected_user_data() { return $this->connection_manager->get_connected_user_data(); } /** * Checks if the site has an admin who is also a connection owner. * * @return bool True if Jetpack connection has an owner. */ public function has_connection_owner() { return ! empty( $this->connection_manager->get_connection_owner_id() ); } /** * Gets the current WP.com blog ID. * * @return integer Current WPCOM blog ID. */ public function get_blog_id() { return Jetpack_Options::get_option( 'id' ); } /** * Starts the Jetpack connection process. Note that running this function will immediately redirect * to the Jetpack flow, so any PHP code after it will never be executed. * * @param string $redirect - URL to redirect to after the connection process is over. * * @throws API_Exception - Exception thrown on failure. */ public function start_connection( $redirect ) { // Register the site to wp.com. if ( ! $this->connection_manager->is_connected() ) { $result = $this->connection_manager->try_registration(); if ( is_wp_error( $result ) ) { throw new API_Exception( $result->get_error_message(), 'wcpay_jetpack_register_site_failed', 500 ); } } // Redirect the user to the Jetpack user connection flow. add_filter( 'jetpack_use_iframe_authorization_flow', '__return_false' ); // Same logic as in WC-Admin. $calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, [ 'development', 'wpcalypso', 'horizon', 'stage' ], true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production'; wp_safe_redirect( add_query_arg( [ 'from' => 'woocommerce-core-profiler', 'plugin_name' => 'woocommerce-payments', 'calypso_env' => $calypso_env, ], $this->connection_manager->get_authorization_url( null, $redirect ) ) ); exit; } /** * Filter function to add WP.com to the list of allowed redirect hosts * * @param array $hosts - array of allowed hosts. * * @return array allowed hosts */ public function allowed_redirect_hosts( $hosts ) { $hosts[] = 'jetpack.wordpress.com'; return $hosts; } }