<?php /** * The Search Plan class. * Registers the REST routes for Search. * * @package automattic/jetpack-search */ namespace Automattic\Jetpack\Search; use Automattic\Jetpack\Connection\Client; use Jetpack_Options; use WP_Error; /** * Registers the REST routes for Search. */ class Plan { const JETPACK_SEARCH_PLAN_INFO_OPTION_KEY = 'jetpack_search_plan_info'; const JETPACK_SEARCH_EVER_SUPPORTED_SEARCH = 'jetpack_search_ever_supported_search'; // The pricing update starting from August 2022. const JETPACK_SEARCH_NEW_PRICING_VERSION = '202208'; const JETPACK_SEARCH_FREE_PRODUCT_SLUG = 'jetpack_search_free'; /** * Whether we have hooked the actions. * * @var boolean */ protected static $update_plan_hook_initialized = false; /** * Init hooks for updating plan info */ public function init_hooks() { // Update plan info from WPCOM on Jetpack heartbeat. // TODO: implement heartbeart for search. if ( ! static::$update_plan_hook_initialized ) { add_action( 'jetpack_heartbeat', array( $this, 'get_plan_info_from_wpcom' ) ); static::$update_plan_hook_initialized = true; } } /** * Refresh plan info stored in options */ public function get_plan_info_from_wpcom() { $blog_id = Jetpack_Options::get_option( 'id' ); $response = Client::wpcom_json_api_request_as_blog( '/sites/' . $blog_id . '/jetpack-search/plan', '2', array(), null, 'wpcom' ); // store plan in options. $this->update_search_plan_info( $response ); return $response; } /** * Get plan info. * * @param {bool} $force_refresh - Default to false. Set true to load from WPCOM. */ public function get_plan_info( $force_refresh = false ) { if ( $force_refresh ) { $this->get_plan_info_from_wpcom(); } $plan_info = get_option( self::JETPACK_SEARCH_PLAN_INFO_OPTION_KEY ); if ( false === $plan_info && ! $force_refresh ) { $plan_info = $this->get_plan_info( true ); } return $plan_info; } /** * Please use `supports_instant_search` instead. * * @deprecated */ public function has_jetpack_search_product() { return (bool) get_option( 'has_jetpack_search_product' ); } /** * Returns true if plan supports Instant Search. */ public function supports_instant_search() { $plan_info = $this->get_plan_info(); return ( isset( $plan_info['supports_instant_search'] ) && $plan_info['supports_instant_search'] ) || $this->has_jetpack_search_product(); } /** * Returns true if the plan support either Instant Search or Classic Search. */ public function supports_search() { $plan_info = $this->get_plan_info(); return ( isset( $plan_info['supports_search'] ) && $plan_info['supports_search'] ) || $this->has_jetpack_search_product(); } /** * Returns true if the plan only supports Classic Search. */ public function supports_only_classic_search() { $plan_info = $this->get_plan_info(); return isset( $plan_info['supports_only_classic_search'] ) && $plan_info['supports_only_classic_search']; } /** * Whether the plan(s) ever supported search. */ public function ever_supported_search() { return (bool) get_option( self::JETPACK_SEARCH_EVER_SUPPORTED_SEARCH ) || $this->supports_search(); } /** * Returns true if the site is on free plan. */ public function is_free_plan() { $plan_info = $this->get_plan_info(); return Helper::is_forced_free_plan() || ( isset( $plan_info['effective_subscription']['product_slug'] ) && $plan_info['effective_subscription']['product_slug'] === self::JETPACK_SEARCH_FREE_PRODUCT_SLUG ); } /** * Update `has_jetpack_search_product` regarding the plan information * * @param array|WP_Error $response - Resopnse from WPCOM. * @return bool - true on success, false on failure. */ public function update_search_plan_info( $response ) { if ( is_wp_error( $response ) ) { return false; } $body = json_decode( wp_remote_retrieve_body( $response ), true ); $status_code = wp_remote_retrieve_response_code( $response ); if ( 200 !== $status_code ) { return false; } return $this->set_plan_options( $body ); } /** * Set plan info to options table * * @param array $plan_info - the decoded plan info array. */ public function set_plan_options( $plan_info ) { if ( ! isset( $plan_info['supports_instant_search'] ) ) { return false; } // set option whether has Jetpack Search plan for capability reason. if ( get_option( 'has_jetpack_search_product' ) !== (bool) $plan_info['supports_instant_search'] ) { update_option( 'has_jetpack_search_product', (bool) $plan_info['supports_instant_search'] ); } // We use this option to determine the visibility of search submenu. // If the site ever had search subscription, then we record it and show the menu after. if ( $plan_info['supports_instant_search'] ) { update_option( self::JETPACK_SEARCH_EVER_SUPPORTED_SEARCH, true, false ); } update_option( self::JETPACK_SEARCH_PLAN_INFO_OPTION_KEY, $plan_info ); return true; } }