WPMUDEV_APIKEY ? WPMUDEV_APIKEY : get_site_option( 'wpmudev_apikey', false ); return apply_filters( $this->get_filter( 'api_key' ), $api_key ); } /** * Get Dashboard site ID * * @return int|bool */ public function get_dashboard_site_id() { if ( $this->has_dashboard() ) { return \WPMUDEV_Dashboard::$api->get_site_id(); } return false; } /** * Check if the user can install dashboard * * @return bool */ public function can_install() { $can_install = is_multisite() ? current_user_can( 'manage_network_options' ) : current_user_can( 'manage_options' ); return (bool) apply_filters( $this->get_filter( 'can_install' ), $can_install ); } /** * Checks whether the account has current paid plan with us * * @return bool */ public function is_member() { if ( $this->has_dashboard() && $this->membership_includes_smartcrawl() && defined( 'SMARTCRAWL_BUILD_TYPE' ) && 'full' === SMARTCRAWL_BUILD_TYPE ) { return true; } return false; } /** * Check if current membership has access to SC. * * @since 3.2.1 * * @return bool */ private function membership_includes_smartcrawl() { // Check if SmartCrawl is available for current membership. if ( class_exists( '\WPMUDEV_Dashboard' ) && isset( \WPMUDEV_Dashboard::$upgrader ) && method_exists( \WPMUDEV_Dashboard::$upgrader, 'user_can_install' ) ) { return \WPMUDEV_Dashboard::$upgrader->user_can_install( 167, true ); } return false; } /** * Clears the value from cache * * @param string $key Key for the value to clear. * * @return bool */ public function clear_cached( $key ) { $key = $this->get_cache_key( $key ); if ( empty( $key ) ) { return false; } return delete_transient( $key ); } /** * Get the key used for caching * * @param string $key Key suffix. * * @return mixed Full cache key as string, or (bool)false on failure */ public function get_cache_key( $key ) { if ( empty( $key ) ) { return false; } return $this->get_filter( $key ); } /** * Actually perform a request on behalf of the implementing service * * @param string $verb Action string. * * @return mixed Service response hash on success, (bool)false on failure */ public function request( $verb ) { $response = $this->remote_call( $verb ); return apply_filters( $this->get_filter( "request-{$verb}" ), apply_filters( $this->get_filter( 'request' ), $response, $verb ) ); } /** * Actually send out remote request * * @param string $verb Service endpoint to call. * * @return mixed Service response hash on success, (bool)false on failure */ protected function remote_call( $verb ) { if ( empty( $verb ) || ! in_array( $verb, $this->get_known_verbs(), true ) ) { return false; } $cacheable = $this->is_cacheable_verb( $verb ); if ( $cacheable ) { $cached = $this->get_cached( $verb ); if ( false !== $cached ) { Logger::debug( "Fetching [{$verb}] result from cache." ); return $cached; } } // Check to see if we have a valid error cache still. $error = $this->get_cached_error( $verb ); if ( ! empty( $error ) ) { Logger::debug( "Error cache still in effect for [{$verb}]" ); $errors = is_array( $error ) ? $error : array( $error ); foreach ( $errors as $err ) { $this->set_error_message( $err ); } return false; } $remote_url = $this->get_request_url( $verb ); if ( empty( $remote_url ) ) { Logger::warning( "Unable to construct endpoint URL for [{$verb}]." ); return false; } $request_arguments = $this->get_request_arguments( $verb ); if ( empty( $request_arguments ) ) { Logger::warning( "Unable to obtain request arguments for [{$verb}]." ); return false; } Logger::debug( "Sending a remote request to [{$remote_url}] ({$verb})" ); $response = wp_remote_request( $remote_url, $request_arguments ); Logger::debug( "Received a response from [{$remote_url}] ({$verb})" . var_export( $response, true ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export if ( is_wp_error( $response ) ) { Logger::error( "We were not able to communicate with [{$remote_url}] ({$verb})." ); if ( is_callable( array( $response, 'get_error_messages' ) ) ) { $msgs = $response->get_error_messages(); foreach ( $msgs as $msg ) { $this->set_error_message( $msg ); } $this->set_cached_error( $verb, $msgs ); } return false; } $response_code = (int) wp_remote_retrieve_response_code( $response ); if ( 200 !== $response_code ) { Logger::error( "We had an error communicating with [{$remote_url}]:[{$response_code}] ({$verb})." ); $this->handle_error_response( $response, $verb ); return false; } $body = wp_remote_retrieve_body( $response ); $result = $this->postprocess_response( $body ); if ( $cacheable ) { Logger::debug( "Setting cache for [{$verb}]" ); $this->set_cached( $verb, $result ); } return $result; } /** * Returns a flat list of known verbs as strings * * @return array */ abstract public function get_known_verbs(); /** * Determine if the action verb is able to be locally cached * * @param string $verb Action string. * * @return bool */ abstract public function is_cacheable_verb( $verb ); /** * Get cached value corresponding to internal key * * @param string $key Key to check. * * @return mixed Cached value, or (bool)false on failure */ public function get_cached( $key ) { $key = $this->get_cache_key( $key ); if ( empty( $key ) ) { return false; } return get_transient( $key ); } /** * Special case error cache getter * * @param string $verb Verb to check cached errors for. * * @return mixed Cached error or (bool) false */ public function get_cached_error( $verb ) { if ( empty( $verb ) ) { return false; } return $this->get_cached( "{$verb}-error" ); } /** * Adds error message to the errors queue * * @param string $msg Error message. */ protected function set_error_message( $msg ) { Logger::error( $msg ); $this->errors[] = $msg; } /** * Get the full URL to perform the service request * * @param string $verb Action string. * * @return mixed Full URL as string or (bool)false on failure */ abstract public function get_request_url( $verb ); /** * Spawn the arguments for WP HTTP API request call * * @param string $verb Action string. * * @return mixed Array of WP HTTP API arguments on success, or (bool)false on failure */ abstract public function get_request_arguments( $verb ); /** * Special case error cache setter * * @param string $verb Verb to set error cache for. * @param mixed $error Error to set. * * @return bool */ public function set_cached_error( $verb, $error ) { if ( empty( $verb ) ) { return false; } return $this->set_cached( "{$verb}-error", $error, self::ERR_CACHE_EXPIRY ); } /** * Sets cached value to the corresponding key * * @param string $key Key for the value to set. * @param mixed $value Value to set. * @param int $expiry Optional expiry time, in secs (one of the class expiry constants). * * @return bool */ public function set_cached( $key, $value, $expiry = false ) { $key = $this->get_cache_key( $key ); if ( empty( $key ) ) { return false; } return set_transient( $key, $value, $this->get_cache_expiry( $expiry ) ); } /** * Get cache expiry, in seconds * * @param int $expiry Expiry time to approximate. * * @return int Cache expiry time, in seconds */ public function get_cache_expiry( $expiry = false ) { $expiry = ! empty( $expiry ) && is_numeric( $expiry ) ? (int) $expiry : self::INTERMEDIATE_CACHE_EXPIRY; return (int) apply_filters( $this->get_filter( 'cache_expiry' ), $expiry ); } /** * Handles error response (non-200) from service * * @param object $response WP HTTP API response. * @param string $verb Request verb. */ abstract public function handle_error_response( $response, $verb ); /** * Post-process the response body * * Passthrough as default implementation * * @param string $body Response body. * * @return mixed */ protected function postprocess_response( $body ) { return json_decode( $body, true ); } /** * Gets all error message strings * * @return array */ public function get_errors() { return (array) $this->errors; } /** * Checks if we have any errors this far * * @return bool */ public function has_errors() { return ! empty( $this->errors ); } /** * Silently Sets all errors * * @param array $errs Errors to set. * * @return void|bool */ protected function set_all_errors( $errs ) { if ( ! is_array( $errs ) ) { return false; } $this->errors = $errs; } /** * Gets the timeout value for service requests. * * @return int The timeout value in seconds. */ protected function get_timeout() { return defined( 'SMARTCRAWL_SERVICE_REQUEST_TIMEOUT' ) ? \SMARTCRAWL_SERVICE_REQUEST_TIMEOUT : 5; } }