PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
elasticpress / includes / classes / Upgrades.php

Upgrades.php in ElasticPress 5.3.5, at includes/classes/Upgrades.php

416 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handle upgrades.
4 *
5 * @since 3.x
6 * @package elasticpress
7 */
8
9 namespace ElasticPress;
10
11 use ElasticPress\Features;
12 use ElasticPress\Utils;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit; // Exit if accessed directly.
16 }
17
18 /**
19 * Class Upgrades
20 *
21 * @package ElasticPress
22 */
23 class Upgrades {
24
25 /**
26 * Store the version number before performing upgrades.
27 * Set in the `setup()` method.
28 *
29 * @var null|string
30 */
31 protected $old_version;
32
33 /**
34 * Initialize class
35 */
36 public function setup() {
37 $this->old_version = Utils\get_option( 'ep_version', false );
38
39 /**
40 * An array with the upgrades routines.
41 * Indexes are the ElasticPress version and values
42 * are an array with the method name and, if needed,
43 * the action name where it should be hooked.
44 */
45 $routines = [
46 '3.5.2' => [ 'upgrade_3_5_2', 'init' ],
47 '3.5.3' => [ 'upgrade_3_5_3', 'init' ],
48 '3.6.6' => [ 'upgrade_3_6_6', 'init' ],
49 '4.2.2' => [ 'upgrade_4_2_2', 'init' ],
50 '4.4.0' => [ 'upgrade_4_4_0', 'init' ],
51 '4.5.0' => [ 'upgrade_4_5_0', 'init' ],
52 '4.7.0' => [ 'upgrade_4_7_0', 'init' ],
53 '5.0.0' => [ 'upgrade_5_0_0', 'init' ],
54 ];
55
56 array_walk( $routines, [ $this, 'run_upgrade_routine' ] );
57
58 /**
59 * Check if a reindex is needed.
60 */
61 add_action( 'plugins_loaded', [ $this, 'check_reindex_needed' ], 5 );
62
63 /**
64 * Update the version number.
65 * Note: if a upgrade routine method is hooked to some action,
66 * this code will be executed *earlier* than the routine method.
67 */
68 Utils\update_option( 'ep_version', sanitize_text_field( EP_VERSION ) );
69
70 add_filter( 'ep_admin_notices', [ $this, 'resync_notice_4_0_0_instant_results' ] );
71 }
72
73 /**
74 * Run the upgrade routine, if needed.
75 *
76 * @param array $routine Array with the info about the method to call.
77 * If needed to be run in an action, it'll contain the action name.
78 * @param string $version The version number to be tested.
79 */
80 protected function run_upgrade_routine( $routine, $version ) {
81 if ( version_compare( $this->old_version, $version, '<' ) ) {
82 $function_name = $routine[0];
83 $action_tag = $routine[1];
84 $priority = ( ! empty( $routine[2] ) ) ? $routine[2] : 10;
85 if ( $action_tag ) {
86 add_action( $action_tag, [ $this, $function_name ], $priority );
87 } else {
88 $this->$function_name();
89 }
90 }
91 }
92
93 /**
94 * Upgrade routine of v3.5.2.
95 *
96 * If weighting options exist and the WooCommerce feature is enabled,
97 * this method will enable the SKU field.
98 */
99 public function upgrade_3_5_2() {
100 $weighting_options = get_option( 'elasticpress_weighting', [] );
101 if ( empty( $weighting_options ) ) {
102 return;
103 }
104
105 $woocommerce = Features::factory()->get_registered_feature( 'woocommerce' );
106 if ( ! $woocommerce->is_active() ) {
107 return;
108 }
109
110 if ( empty( $weighting_options['product'] ) ) {
111 return;
112 }
113
114 if ( ! empty( $weighting_options['product']['author_name'] ) ) {
115 unset( $weighting_options['product']['author_name'] );
116 }
117
118 $weighting_options['product']['meta._sku.value'] = array(
119 'enabled' => true,
120 'weight' => 1,
121 );
122
123 update_option( 'elasticpress_weighting', $weighting_options );
124 }
125
126 /**
127 * Upgrade routine of v3.5.3.
128 *
129 * Check if synonyms post has the correct post type, otherwise,
130 * change it to the correct one.
131 */
132 public function upgrade_3_5_3() {
133 delete_option( 'elasticpress_synonyms_post_id' );
134 delete_site_option( 'elasticpress_synonyms_post_id' );
135 }
136
137 /**
138 * Upgrade routine of v3.6.6.
139 *
140 * Delete all synonyms that have the post content identical to the example we set.
141 * In previous versions we had a bug that created several posts with it.
142 *
143 * @see https://github.com/10up/ElasticPress/issues/2516
144 */
145 public function upgrade_3_6_6() {
146 global $wpdb;
147
148 $synonyms = \ElasticPress\Features::factory()->get_registered_feature( 'search' )->synonyms;
149
150 if ( ! $synonyms ) {
151 return;
152 }
153
154 // phpcs:disable WordPress.DB.DirectDatabaseQuery
155 $synonyms_example_ids = $wpdb->get_col(
156 $wpdb->prepare(
157 "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_content = %s LIMIT 100",
158 $synonyms::POST_TYPE_NAME,
159 $synonyms->example_synonym_list()
160 )
161 );
162 // phpcs:enable WordPress.DB.DirectDatabaseQuery
163
164 if ( ! $synonyms_example_ids ) {
165 return;
166 }
167
168 foreach ( $synonyms_example_ids as $synonym_post_id ) {
169 wp_delete_post( $synonym_post_id, true );
170 }
171 }
172
173 /**
174 * Upgrade routine of v4.2.2.
175 *
176 * Delete the transient with ES info, so EP is forced to fetch it again,
177 * determining the correct software type (elasticsearch or opensearch, for example)
178 *
179 * @see https://github.com/10up/ElasticPress/issues/2882
180 */
181 public function upgrade_4_2_2() {
182 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
183 delete_site_transient( 'ep_es_info' );
184 } else {
185 delete_transient( 'ep_es_info' );
186 }
187 }
188
189 /**
190 * Upgrade routine of v4.4.0.
191 *
192 * Delete the ep_prefix option, as that is now obtained via ep_credentials
193 *
194 * @see https://github.com/10up/ElasticPress/issues/2739
195 */
196 public function upgrade_4_4_0() {
197 Utils\delete_option( 'ep_prefix' );
198 }
199
200 /**
201 * Upgrade routine of v4.5.0.
202 *
203 * Add the ElasticPress capability to admins
204 *
205 * @see https://github.com/10up/ElasticPress/pull/3313
206 */
207 public function upgrade_4_5_0() {
208 setup_roles();
209 }
210
211 /**
212 * Upgrade routine of v4.7.0.
213 *
214 * Remove old total_fields_limit transients
215 * Remove cached autosuggest requests
216 *
217 * @see https://github.com/10up/ElasticPress/pull/3552
218 */
219 public function upgrade_4_7_0() {
220 global $wpdb;
221
222 if ( is_multisite() ) {
223 $sites = \get_sites( [ 'number' => 0 ] );
224 foreach ( $sites as $site ) {
225 $blog_option = get_blog_option( $site->blog_id, 'ep_indexable' );
226 if ( $blog_option ) {
227 update_site_meta( $site->blog_id, 'ep_indexable', $blog_option );
228 }
229 }
230 }
231
232 $transients = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
233 "SELECT option_name
234 FROM {$wpdb->prefix}options
235 WHERE option_name LIKE '_transient_ep_total_fields_limit_%'"
236 );
237
238 foreach ( $transients as $transient ) {
239 $transient_name = str_replace( '_transient_', '', $transient );
240 delete_site_transient( $transient_name );
241 delete_transient( $transient_name );
242 }
243
244 if ( function_exists( 'wp_cache_supports' ) && wp_cache_supports( 'flush_group' ) ) {
245 wp_cache_flush_group( 'ep_autosuggest' );
246 }
247 delete_transient( 'ep_autosuggest_query_request_cache' );
248 }
249
250 /**
251 * Upgrade routine of v5.0.0.
252 */
253 public function upgrade_5_0_0() {
254 $features_in_settings = Features::factory()->get_feature_settings();
255 if ( ! empty( $features_in_settings ) ) {
256 foreach ( $features_in_settings as $feature_slug => $feature_settings ) {
257 $feature = Features::factory()->get_registered_feature( $feature_slug );
258 if ( ! $feature ) {
259 continue;
260 }
261
262 $settings_schema = $feature->get_settings_schema();
263 foreach ( $settings_schema as $setting_schema ) {
264 if ( ! isset( $feature_settings[ $setting_schema['key'] ] ) ) {
265 continue;
266 }
267
268 $value = $feature_settings[ $setting_schema['key'] ];
269
270 if ( ! in_array( $setting_schema['type'], [ 'checkbox', 'radio' ], true ) || ! is_bool( $value ) ) {
271 continue;
272 }
273
274 $features_in_settings[ $feature_slug ][ $setting_schema['key'] ] = $value ? '1' : '0';
275 }
276 }
277 Utils\update_option( 'ep_feature_settings', $features_in_settings );
278 }
279
280 /**
281 * Remove the 'ep_last_index' option and store it as an entry of 'ep_sync_history'
282 */
283 $last_sync = Utils\get_option( 'ep_last_index', [] );
284 if ( ! empty( $last_sync ) ) {
285 Utils\delete_option( 'ep_last_index' );
286 Utils\update_option( 'ep_sync_history', [ $last_sync ] );
287 }
288 }
289
290 /**
291 * Adjust the upgrade sync notice to warn users about Instant Results.
292 *
293 * As 4.0.0 introduces this new feature and it requires a resync, admin users
294 * might want to enable the feature before the resync (and then resync only once.)
295 *
296 * @since 4.0.0
297 * @param array $notices All admin notices
298 * @return array
299 */
300 public function resync_notice_4_0_0_instant_results( $notices ) {
301 if ( ! isset( $notices['upgrade_sync'] ) ) {
302 return $notices;
303 }
304
305 $instant_results = \ElasticPress\Features::factory()->get_registered_feature( 'instant-results' );
306 if ( $instant_results->is_active() ) {
307 return $notices;
308 }
309
310 $feature_status = $instant_results->requirements_status();
311 $appended_message = '';
312 if ( 1 >= $feature_status->get_code() ) {
313 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
314 $features_url = admin_url( 'network/admin.php?page=elasticpress' );
315 } else {
316 $features_url = admin_url( 'admin.php?page=elasticpress' );
317 }
318
319 $appended_message = wp_kses_post(
320 sprintf(
321 /* translators: 1: <a> tag (Support article); 2. </a>; 3: <a> tag (link to Features screen); 4. </a>; */
322 __( '%1$sInstant Results%2$s is now available in ElasticPress, but requires a re-sync before activation. If you would like to use Instant Results, click %3$shere%4$s to activate the feature and start your sync.', 'elasticpress' ),
323 '<a href="https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#instant-results">',
324 '</a>',
325 '<a href="' . $features_url . '">',
326 '</a>'
327 )
328 );
329 } else {
330 $appended_message = wp_kses_post(
331 sprintf(
332 /* translators: 1: <a> tag (Support article about Instant Results); 2. </a>; 3: <a> tag (Support article about self hosted Elasticsearch setups); 4. </a>; */
333 __( '%1$sInstant Results%2$s is now available in ElasticPress, but requires a re-sync before activation. If you would like to use Instant Results, since you are not using ElasticPress.io, you will also need to %3$sinstall and configure a PHP proxy%4$s.', 'elasticpress' ),
334 '<a href="https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#instant-results">',
335 '</a>',
336 '<a href="https://www.elasticpress.io/resources/articles/considerations-for-self-hosted-elasticsearch-setups/">',
337 '</a>'
338 )
339 );
340 }
341
342 $notices['upgrade_sync']['html'] .= '<br><br>' . $appended_message;
343
344 return $notices;
345 }
346
347 /**
348 * Check if a reindex is needed based on the version number.
349 */
350 public function check_reindex_needed() {
351 if ( ! is_admin() || defined( 'DOING_AJAX' ) ) {
352 return;
353 }
354
355 $last_sync = Utils\get_option( 'ep_last_sync', 'never' );
356
357 // No need to upgrade since we've never synced.
358 if ( empty( $last_sync ) || 'never' === $last_sync ) {
359 return;
360 }
361
362 /**
363 * Reindex if we cross a reindex version in the upgrade
364 */
365 $reindex_versions = apply_filters(
366 'ep_reindex_versions',
367 array(
368 '2.2',
369 '2.3.1',
370 '2.4',
371 '2.5.1',
372 '2.6',
373 '2.7',
374 '3.0',
375 '3.1',
376 '3.3',
377 '3.4',
378 '3.6.0',
379 '3.6.1',
380 '4.0.0-beta.1',
381 '4.0.0',
382 )
383 );
384
385 $need_upgrade_sync = false;
386
387 if ( false !== $this->old_version ) {
388 $last_reindex_version = $reindex_versions[ count( $reindex_versions ) - 1 ];
389
390 if ( -1 === version_compare( $this->old_version, $last_reindex_version ) && 0 <= version_compare( EP_VERSION, $last_reindex_version ) ) {
391 $need_upgrade_sync = true;
392 }
393 }
394
395 if ( $need_upgrade_sync ) {
396 Utils\update_option( 'ep_need_upgrade_sync', true );
397 }
398 }
399
400 /**
401 * Return singleton instance of class
402 *
403 * @return self
404 */
405 public static function factory() {
406 static $instance = false;
407
408 if ( ! $instance ) {
409 $instance = new self();
410 $instance->setup();
411 }
412
413 return $instance;
414 }
415 }
416