ng indicating whether inline search should use newer 1.3 API. * * @param bool $swap_classic_to_inline_search - true to use Inline Search, false to use Classic Search. */ public function update_swap_classic_to_inline_search( bool $swap_classic_to_inline_search ) { return update_option( self::SEARCH_MODULE_SWAP_CLASSIC_TO_INLINE_OPTION_KEY, $swap_classic_to_inline_search ); } /** * Get the active search experience. * * `'off'` is read from the global Jetpack module-active state (not stored in * this package's option). `'inline'`, `'embedded'`, `'overlay'`, and * `'overlay_blocks'` are each written as their literal value to * `jetpack_search_experience` whenever the experience changes, and read * straight back here. * * @return string One of 'embedded', 'overlay', 'overlay_blocks', 'inline', 'off'. */ public function get_experience() { if ( ! $this->is_active() ) { return self::EXPERIENCE_OFF; } $saved = get_option( self::SEARCH_MODULE_EXPERIENCE_OPTION_KEY, false ); if ( self::EXPERIENCE_EMBEDDED === $saved ) { return self::EXPERIENCE_EMBEDDED; } if ( self::EXPERIENCE_OVERLAY === $saved ) { return self::EXPERIENCE_OVERLAY; } if ( self::EXPERIENCE_OVERLAY_BLOCKS === $saved ) { return self::EXPERIENCE_OVERLAY_BLOCKS; } // Legacy fallback for sites that have never saved via the new UI: a true // `instant_search_enabled` boolean reads as overlay; otherwise inline. if ( $this->is_instant_search_enabled() ) { return self::EXPERIENCE_OVERLAY; } return self::EXPERIENCE_INLINE; } /** * Update the search experience. * * Storage is narrower than the wire format: `'off'` only deactivates the global * module (no write to the experience option) and disables * `instant_search_enabled` so the legacy boolean doesn't drift true after * a non-overlay re-enable. `'inline'` deletes the experience option (the * absence of an opt-in *is* inline). Only `'embedded'` and `'overlay'` * write affirmative values. * * Legacy `module_active` / `instant_search_enabled` are kept in lockstep so * unmigrated readers (Initializer, Options, sidebar registration) continue to * see the right state until they're migrated to consult get_experience(). * * @param string $experience One of 'embedded', 'overlay', 'inline', 'off'. * @return bool|WP_Error WP_Error on failure; true on success for the affirmative * branches; the bool from Modules::deactivate() for `'off'` * (false signals the module was already inactive — a benign * no-op the REST controller treats as success). */ public function update_experience( string $experience ) { $valid_values = array( self::EXPERIENCE_OVERLAY, self::EXPERIENCE_OVERLAY_BLOCKS, self::EXPERIENCE_EMBEDDED, self::EXPERIENCE_INLINE, self::EXPERIENCE_OFF, ); if ( ! in_array( $experience, $valid_values, true ) ) { return new WP_Error( 'invalid_experience', esc_html__( 'Invalid experience value.', 'jetpack-search-pkg' ), array( 'status' => 400 ) ); } // Defence-in-depth for the experimental blocks-powered overlay: the // dashboard already hides the option when the // `jetpack_search_overlay_block_template_enabled` filter is off, but // a scripted REST POST could otherwise pre-stage `overlay_blocks` on // a site where the operator has pinned the filter to false. Reject // the value at the boundary so the runtime gate isn't the only // safety net. if ( self::EXPERIENCE_OVERLAY_BLOCKS === $experience && ! (bool) apply_filters( 'jetpack_search_overlay_block_template_enabled', true ) ) { return new WP_Error( 'experience_not_available', esc_html__( 'The blocks-powered Overlay search experience is not enabled on this site.', 'jetpack-search-pkg' ), array( 'status' => 400 ) ); } switch ( $experience ) { case self::EXPERIENCE_OFF: $this->disable_instant_search(); return ( new Modules() )->deactivate( self::JETPACK_SEARCH_MODULE_SLUG ); case self::EXPERIENCE_INLINE: $result = $this->activate(); if ( is_wp_error( $result ) ) { return $result; } $this->disable_instant_search(); // Inline is the absence of an opt-in — delete the option rather than // writing 'inline'. Pre-existing sites that have never saved are // already in this state, so this also normalises after a switch. update_option( self::SEARCH_MODULE_EXPERIENCE_OPTION_KEY, '' ); return true; case self::EXPERIENCE_EMBEDDED: $result = $this->activate(); if ( is_wp_error( $result ) ) { return $result; } $this->disable_instant_search(); update_option( self::SEARCH_MODULE_EXPERIENCE_OPTION_KEY, self::EXPERIENCE_EMBEDDED ); return true; case self::EXPERIENCE_OVERLAY: $result = $this->activate(); if ( is_wp_error( $result ) ) { return $result; } $result = $this->enable_instant_search(); if ( is_wp_error( $result ) ) { return $result; } update_option( self::SEARCH_MODULE_EXPERIENCE_OPTION_KEY, self::EXPERIENCE_OVERLAY ); return true; case self::EXPERIENCE_OVERLAY_BLOCKS: // The blocks-powered overlay does not boot the legacy preact // `SearchApp`, so we keep `instant_search_enabled` off; the // runtime hookup lives in `Search_Blocks::is_block_template_overlay_enabled()` // which combines the user's experience choice with the // `jetpack_search_overlay_block_template_enabled` server filter. $result = $this->activate(); if ( is_wp_error( $result ) ) { return $result; } $this->disable_instant_search(); update_option( self::SEARCH_MODULE_EXPERIENCE_OPTION_KEY, self::EXPERIENCE_OVERLAY_BLOCKS ); return true; default: // Unreachable — the `in_array` guard at the top of this // method already restricts $experience to the cases above. // Returning a typed value (rather than falling through to an // implicit `null`) satisfies the static analyzers that flag // switch statements without a `default` branch, and keeps the // method's `bool|WP_Error` contract honest if a future caller // loosens the validation. return true; } } /** * Get a list of activated modules as an array of module slugs. * * @deprecated 0.12.3 * @return Array $active_modules */ public function get_active_modules() { _deprecated_function( __METHOD__, 'jetpack-search-0.12.3', 'Automattic\\Jetpack\\Modules\\get_active' ); return ( new Modules() )->get_active(); } /** * Adds search to the list of available modules * * @param array $modules The available modules. * @return array */ public function search_filter_available_modules( $modules ) { return array_merge( array( self::JETPACK_SEARCH_MODULE_SLUG ), $modules ); } }