PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.3
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.3
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / jetpack_vendor / automattic / jetpack-search / src / initializers / class-initializer.php

class-initializer.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.3, at jetpack_vendor/automattic/jetpack-search/src/initializers/class-initializer.php

342 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Initializer base class.
4 *
5 * @package @automattic/jetpack-search
6 */
7
8 namespace Automattic\Jetpack\Search;
9
10 use Automattic\Jetpack\Connection\Manager as Connection_Manager;
11 use Automattic\Jetpack\Status\Host;
12 use WP_Error;
13 /**
14 * Base class for the initializer pattern.
15 */
16 class Initializer {
17
18 /**
19 * Whether a block-driven experience owns the search results this request
20 * — Embedded, or the experimental blocks Overlay. Set to `true` in
21 * `init_search_blocks()` only when the `jetpack_search_blocks_enabled`
22 * gate is on AND the saved experience is one of those (the Overlay arm
23 * additionally requires `jetpack_search_overlay_block_template_enabled`).
24 * In those experiences both Classic and Instant Search are suppressed, so
25 * `init_search()` returns falsy by design; `init()` reads this flag to
26 * treat that as a no-op rather than a real failure. Anchoring on the
27 * actually-wired-up state (not a filter read) prevents the abort carve-out
28 * from being bypassed on a site that doesn't have Search Blocks registered.
29 *
30 * @var bool
31 */
32 private static $block_search_active = false;
33
34 /**
35 * Initialize the search package.
36 *
37 * The method is called from the `Config` class.
38 */
39 public static function init() {
40 // Ahead of the abort filter below, so the flag stays listable by
41 // `wp companion feature-flag` even where Search initialization bails.
42 Dashboard::register_feature_flags();
43
44 // Load compatibility files - at this point all plugins are already loaded.
45 static::include_compatibility_files();
46
47 // Set up package version hook.
48 add_filter( 'jetpack_package_versions', __NAMESPACE__ . '\Package::send_version_to_tracker' );
49
50 /**
51 * The filter allows abortion of the Jetpack Search package initialization.
52 *
53 * @since 0.11.2
54 *
55 * @param boolean $init_search_package Default value is true.
56 */
57 if ( ! apply_filters( 'jetpack_search_init_search_package', true ) ) {
58 /**
59 * Fires when the Jetpack Search fails and would fallback to MySQL.
60 *
61 * @since Jetpack 7.9.0
62 * @param string $reason Reason for Search fallback.
63 * @param mixed $data Data associated with the request, such as attempted search parameters.
64 */
65 do_action( 'jetpack_search_abort', 'jetpack_search_init_search_package_filter', null );
66 return;
67 }
68
69 static::init_before_connection();
70
71 // Check whether Jetpack Search should be initialized in the first place .
72 if ( ! static::is_connected() || ! static::is_search_supported() ) {
73 /** This filter is documented in search/src/initalizers/class-initalizer.php */
74 do_action( 'jetpack_search_abort', 'inactive', null );
75 return;
76 }
77
78 // Register the Search 3.0 Interactivity API blocks. Connection +
79 // plan are already guaranteed by the abort above; this call only
80 // layers the Phase 1 feature flag on top, mirroring how
81 // `init_search()` layers `is_instant_search_enabled` on top of
82 // the same upstream gate.
83 static::init_search_blocks();
84
85 $blog_id = Helper::get_wpcom_site_id();
86 if ( ! $blog_id ) {
87 /** This filter is documented in search/src/initalizers/class-initalizer.php */
88 do_action( 'jetpack_search_abort', 'no_blog_id', null );
89 return;
90 }
91
92 if ( ! ( new Module_Control() )->is_active() ) {
93 /** This filter is documented in search/src/initalizers/class-initalizer.php */
94 do_action( 'jetpack_search_abort', 'module_inactive', null );
95 return;
96 }
97
98 // Initialize search package. The block-driven experiences (Embedded /
99 // blocks Overlay) intentionally skip both instant and classic init
100 // (Search_Blocks owns the UI), so a falsy return there is by design —
101 // not an abort. Anything else falsy is a real failure. Anchor on the
102 // actually-wired-up flag (set in `init_search_blocks()` only when the
103 // blocks gate passed) rather than a filter read, so flipping a filter
104 // without the blocks gate can never bypass the abort.
105 $initialized = static::init_search( $blog_id )
106 || self::$block_search_active;
107
108 if ( ! $initialized ) {
109 /** This filter is documented in search/src/initalizers/class-initalizer.php */
110 do_action( 'jetpack_search_abort', 'jetpack_search_init_search', null );
111 return;
112 }
113
114 /**
115 * Fires when the Jetpack Search package has been initialized.
116 *
117 * @since 0.11.2
118 */
119 do_action( 'jetpack_search_loaded' );
120 }
121
122 /**
123 * Extra tweaks to make Jetpack Search play well with others.
124 */
125 public static function include_compatibility_files() {
126 // WordPress.com Simple defines its own unrelated `Jetpack` class, so the class name
127 // alone does not mean the Jetpack plugin, and this shim would fatal there.
128 if ( class_exists( 'Jetpack' ) && ! ( new Host() )->is_wpcom_simple() ) {
129 require_once Package::get_installed_path() . 'compatibility/jetpack.php';
130 }
131 require_once Package::get_installed_path() . 'compatibility/search-0.15.2.php';
132 require_once Package::get_installed_path() . 'compatibility/search-0.17.0.php';
133 require_once Package::get_installed_path() . 'compatibility/unsupported-browsers.php';
134 }
135
136 /**
137 * Init functionality required for connection.
138 */
139 protected static function init_before_connection() {
140 // Set up Search API endpoints.
141 add_action( 'rest_api_init', array( REST_Controller::class, 'register' ) );
142 // The dashboard has to be initialized before connection.
143 ( new Dashboard() )->init_hooks();
144 ( new AI_Answers() )->init();
145 }
146
147 /**
148 * Register the Search 3.0 Interactivity API blocks on this request,
149 * gated by the Phase 1 feature flag.
150 *
151 * Called from `init()` after the upstream connection + Search-plan
152 * abort, so on entry the site is guaranteed to be connected and on a
153 * plan that supports Search (paid plans or the free
154 * `jetpack_search_free` product). The remaining gate is the
155 * feature-flag opt-in.
156 *
157 * Sits before the blog_id and module-active checks because admins
158 * should be able to configure Search blocks in the editor regardless
159 * of which runtime experience is enabled — matching how Instant
160 * Search layers its own opt-in on top of the same connection + plan
161 * gate further down in `init_search()`.
162 */
163 protected static function init_search_blocks() {
164 /**
165 * Filter whether the Jetpack Search 3.0 Interactivity API blocks are enabled.
166 *
167 * Necessary but not sufficient on its own — registration also
168 * requires the site to be connected and on a plan that supports
169 * Search (paid plans or the free `jetpack_search_free` product).
170 *
171 * @param bool $enabled Default true.
172 */
173 if ( ! apply_filters( 'jetpack_search_blocks_enabled', true ) ) {
174 return;
175 }
176
177 Search_Blocks::init();
178
179 // When the Search blocks own the front-end results (Embedded / blocks
180 // Overlay), Classic Search would otherwise run a server-side
181 // Elasticsearch query plus a WP_Query to hydrate the posts on every
182 // search request — work the blocks immediately discard. Suppress it so
183 // it never runs, the same way Instant Search replaces Classic;
184 // `Search_Blocks::filter__posts_pre_query` then short-circuits the
185 // remaining core database search. With both handlers gone `init_search()`
186 // returns false by design, so this flag tells `init()` not to treat that
187 // as an abort.
188 //
189 // Front-end only, matching the `posts_pre_query` registration guard:
190 // leaving Classic Search to initialize normally in wp-admin keeps the
191 // change scoped to the search page and avoids dropping admin-side hooks.
192 if ( ! is_admin() && Search_Blocks::owns_search_results() ) {
193 add_filter( 'jetpack_search_classic_search_enabled', '__return_false' );
194 self::$block_search_active = true;
195 }
196
197 // Experimental block-template overlay (available by default, opt-in
198 // via the Experience Selector; see
199 // `Search_Blocks::is_block_template_overlay_enabled()`): bypass the
200 // preact `SearchApp` so it doesn't race the block overlay for
201 // `?s=`, popstate, and theme search-trigger selectors. Suppressing
202 // at the init filter is cleaner than dequeuing post-enqueue. Gated on
203 // the overlay path specifically — Embedded never enables Instant Search,
204 // so there is nothing to suppress there.
205 if ( Search_Blocks::is_block_template_overlay_enabled() ) {
206 add_filter( 'jetpack_search_init_instant_search', '__return_false' );
207 }
208 }
209
210 /**
211 * Init the search package.
212 *
213 * @param int $blog_id WPCOM blog ID.
214 */
215 protected static function init_search( $blog_id ) {
216 // We could provide CLI to enable search/instant search, so init them regardless of whether the module is active or not.
217 static::init_cli();
218
219 $success = false;
220 $is_instant_search_enabled = ( new Module_Control() )->is_instant_search_enabled();
221 if ( $is_instant_search_enabled ) {
222 // Enable Instant search experience.
223 $success = static::init_instant_search( $blog_id );
224 }
225 /**
226 * Filter whether classic search should be enabled. By this stage, search module would be enabled already.
227 *
228 * @since 0.39.6
229 * @param boolean initial value whether classic search is enabled.
230 * @param boolean filtered result whether classic search is enabled.
231 */
232 if ( apply_filters( 'jetpack_search_classic_search_enabled', ! $is_instant_search_enabled ) ) {
233 // Enable the classic search experience.
234 $success = static::init_classic_search( $blog_id );
235 }
236
237 if ( $success ) {
238 // registers Jetpack Search widget.
239 add_action( 'widgets_init', array( static::class, 'jetpack_search_widget_init' ) );
240 }
241
242 return $success;
243 }
244
245 /**
246 * Init Instant Search and its dependencies.
247 *
248 * @param int $blog_id WPCOM blog ID.
249 */
250 protected static function init_instant_search( $blog_id ) {
251 /**
252 * The filter allows abortion of the Instant Search initialization.
253 *
254 * @since 0.11.2
255 *
256 * @param boolean $init_instant_search Default value is true.
257 */
258 if ( ! apply_filters( 'jetpack_search_init_instant_search', true ) ) {
259 return;
260 }
261
262 // Enable the instant search experience.
263 Instant_Search::initialize( $blog_id );
264 // Register instant search configurables as WordPress settings.
265 new Settings();
266 // Instantiate "Customberg", the live search configuration interface.
267 Customberg::instance();
268 // Enable configuring instant search within the Customizer iff it's not using a block theme.
269 if ( ! wp_is_block_theme() ) {
270 new Customizer();
271 }
272 return true;
273 }
274
275 /**
276 * Init Classic Search.
277 *
278 * @param int $blog_id WPCOM blog ID.
279 */
280 protected static function init_classic_search( $blog_id ) {
281 /**
282 * The filter allows abortion of the Classic Search initialization.
283 *
284 * @since 0.11.2
285 *
286 * @param boolean $init_instant_search Default value is true.
287 */
288 if ( ! apply_filters( 'jetpack_search_init_classic_search', true ) ) {
289 return;
290 }
291 Inline_Search::get_instance_maybe_fallback_to_classic( $blog_id );
292
293 return true;
294 }
295
296 /**
297 * Register jetpack-search CLI if `\CLI` exists.
298 *
299 * @return void
300 */
301 protected static function init_cli() {
302 if ( defined( 'WP_CLI' ) && \WP_CLI ) {
303 \WP_CLI::add_command( 'jetpack-search', __NAMESPACE__ . '\CLI' );
304 }
305 }
306
307 /**
308 * Register the widget if Jetpack Search is available and enabled.
309 */
310 public static function jetpack_search_widget_init() {
311 register_widget( 'Automattic\Jetpack\Search\Search_Widget' );
312 }
313
314 /**
315 * Check if site has been connected.
316 */
317 protected static function is_connected() {
318 return ( new Connection_Manager( Package::SLUG ) )->is_connected();
319 }
320
321 /**
322 * Check if search is supported by current plan.
323 */
324 protected static function is_search_supported() {
325 return ( new Plan() )->supports_search();
326 }
327
328 /**
329 * Perform necessary initialization steps for classic and instant search in the constructor.
330 *
331 * @deprecated
332 */
333 public static function initialize() {
334 return new WP_Error(
335 'invalid-method',
336 /* translators: %s: Method name. */
337 sprintf( __( "Method '%s' not implemented. Must be overridden in subclass.", 'jetpack-search-pkg' ), __METHOD__ ),
338 array( 'status' => 405 )
339 );
340 }
341 }
342