PluginProbe
ElasticPress / 4.2.0
ElasticPress v4.2.0
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 / Features.php

Features.php in ElasticPress 4.2.0, at includes/classes/Features.php

326 lines 8.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles registering and storing feature instances
4 *
5 * @since 2.1
6 * @package elasticpress
7 */
8
9 namespace ElasticPress;
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit; // Exit if accessed directly.
13 }
14
15 /**
16 * Class for storing and managing features
17 */
18 class Features {
19
20 /**
21 * Stores all features that have been properly included (both active and inactive)
22 *
23 * @since 2.1
24 * @var array
25 */
26 public $registered_features = [];
27
28 /**
29 * Initiate class actions
30 *
31 * @since 2.1
32 */
33 public function setup() {
34 // hooks order matters, make sure feature activation goes before features setup
35 add_action( 'init', array( $this, 'handle_feature_activation' ), 0 );
36 add_action( 'init', array( $this, 'setup_features' ), 0 );
37 }
38
39 /**
40 * Activate a feature
41 *
42 * @param string $slug Feature slug
43 * @since 2.2
44 */
45 public function activate_feature( $slug ) {
46 $this->update_feature( $slug, array( 'active' => true ) );
47 }
48
49 /**
50 * Dectivate a feature
51 *
52 * @param string $slug Feature slug
53 * @param bool $force Whether to force deactivation
54 * @since 2.2
55 */
56 public function deactivate_feature( $slug, $force = true ) {
57 $this->update_feature( $slug, array( 'active' => false ), $force );
58 }
59
60 /**
61 * Registers a feature for use in ElasticPress
62 *
63 * @param Feature $feature An instance of the Feature class
64 * @since 3.0
65 * @return boolean
66 */
67 public function register_feature( Feature $feature ) {
68 $feature_args['slug'] = $feature->slug;
69
70 $this->registered_features[ $feature->slug ] = $feature;
71
72 return true;
73 }
74
75 /**
76 * Easy access function to get a Feature object from a slug
77 *
78 * @param string $slug Feature slug
79 * @since 2.1
80 * @return Feature
81 */
82 public function get_registered_feature( $slug ) {
83 if ( empty( $this->registered_features[ $slug ] ) ) {
84 return false;
85 }
86
87 return $this->registered_features[ $slug ];
88 }
89
90 /**
91 * Activate or deactivate a feature
92 *
93 * @param string $slug Feature slug
94 * @param array $settings Array of settings
95 * @param bool $force Whether to force activate/deactivate
96 * @since 2.2
97 * @return array|bool
98 */
99 public function update_feature( $slug, $settings, $force = true ) {
100 $feature = $this->get_registered_feature( $slug );
101
102 if ( empty( $feature ) ) {
103 return false;
104 }
105
106 $original_state = $feature->is_active();
107
108 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
109 $feature_settings = get_site_option( 'ep_feature_settings', [] );
110 } else {
111 $feature_settings = get_option( 'ep_feature_settings', [] );
112 }
113
114 if ( empty( $feature_settings[ $slug ] ) ) {
115 // If doesn't exist, merge with feature defaults
116 $feature_settings[ $slug ] = wp_parse_args( $settings, $feature->default_settings );
117 } else {
118 // If exist just merge changed values into current
119 $feature_settings[ $slug ] = wp_parse_args( $settings, $feature_settings[ $slug ] );
120 }
121
122 // Make sure active is a proper bool
123 $feature_settings[ $slug ]['active'] = (bool) $feature_settings[ $slug ]['active'];
124
125 if ( $feature_settings[ $slug ]['active'] ) {
126 $feature_settings[ $slug ]['force_inactive'] = false;
127 }
128
129 // This means someone has explicitly deactivated the feature
130 if ( $force ) {
131 if ( ! (bool) $settings['active'] && $original_state ) {
132 $feature_settings[ $slug ]['force_inactive'] = true;
133 }
134 }
135
136 $sanitize_feature_settings = apply_filters( 'ep_sanitize_feature_settings', $feature_settings, $feature );
137
138 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
139 update_site_option( 'ep_feature_settings', $sanitize_feature_settings );
140 } else {
141 update_option( 'ep_feature_settings', $sanitize_feature_settings );
142 }
143
144 $data = array(
145 'active' => $sanitize_feature_settings[ $slug ]['active'],
146 'reindex' => false,
147 );
148
149 if ( $feature_settings[ $slug ]['active'] && ! $original_state ) {
150 if ( ! empty( $feature->requires_install_reindex ) ) {
151 $data['reindex'] = true;
152 }
153
154 $feature->post_activation();
155 }
156
157 /**
158 * Fires after activating, inactivating, or just updating a feature.
159 *
160 * @hook ep_after_update_feature
161 * @param {string} $feature Feature slug
162 * @param {array} $settings Feature settings
163 * @param {array} $data Feature activation data
164 *
165 * @since 3.5.5
166 */
167 do_action(
168 'ep_after_update_feature',
169 $slug,
170 $settings,
171 $data
172 );
173
174 return $data;
175 }
176
177 /**
178 * When plugins are adjusted, we need to determine how to activate/deactivate features
179 *
180 * @since 2.2
181 */
182 public function handle_feature_activation() {
183 /**
184 * Save our current requirement statuses for later
185 */
186
187 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
188 $old_requirement_statuses = get_site_option( 'ep_feature_requirement_statuses', false );
189 } else {
190 $old_requirement_statuses = get_option( 'ep_feature_requirement_statuses', false );
191 }
192
193 $new_requirement_statuses = [];
194
195 foreach ( $this->registered_features as $slug => $feature ) {
196 $status = $feature->requirements_status();
197 $new_requirement_statuses[ $slug ] = (int) $status->code;
198 }
199
200 $is_wp_cli = defined( 'WP_CLI' ) && \WP_CLI;
201
202 if ( $is_wp_cli || is_admin() ) {
203 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
204 update_site_option( 'ep_feature_requirement_statuses', $new_requirement_statuses );
205 } else {
206 update_option( 'ep_feature_requirement_statuses', $new_requirement_statuses );
207 }
208 }
209
210 /**
211 * If feature settings aren't created, let's create them and finish
212 */
213
214 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
215 $feature_settings = get_site_option( 'ep_feature_settings', false );
216 } else {
217 $feature_settings = get_option( 'ep_feature_settings', false );
218 }
219
220 if ( false === $feature_settings ) {
221 $registered_features = $this->registered_features;
222
223 foreach ( $registered_features as $slug => $feature ) {
224 if ( 0 === $feature->requirements_status()->code ) {
225 $this->activate_feature( $slug );
226 }
227 }
228
229 /**
230 * Nothing else to do since we are doing initial activation
231 */
232 return;
233 }
234
235 /**
236 * If a requirement status changes, we need to handle that by activating/deactivating/showing notification
237 */
238
239 if ( ( $is_wp_cli || is_admin() ) && ! empty( $old_requirement_statuses ) ) {
240 foreach ( $new_requirement_statuses as $slug => $code ) {
241 $feature = $this->get_registered_feature( $slug );
242
243 // If a feature is forced inactive, do nothing
244 $feature_settings = $feature->get_settings();
245 if ( is_array( $feature_settings ) && ! empty( $feature_settings['force_inactive'] ) ) {
246 continue;
247 }
248
249 // This is a new feature
250 if ( ! isset( $old_requirement_statuses[ $slug ] ) ) {
251 if ( 0 === $code ) {
252 $this->activate_feature( $slug );
253
254 if ( $feature->requires_install_reindex ) {
255 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
256 update_site_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
257 } else {
258 update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
259 }
260 }
261 }
262 } else {
263 // This feature has a 0 "ok" code when it did not before
264 if ( $old_requirement_statuses[ $slug ] !== $code && ( 0 === $code || 2 === $code ) ) {
265 $active = ( 0 === $code );
266
267 if ( ! $feature->is_active() && $active ) {
268 $this->activate_feature( $slug );
269
270 // Need to activate and maybe set a sync notice
271 if ( $feature->requires_install_reindex ) {
272 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
273 update_site_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
274 } else {
275 update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
276 }
277 }
278 } elseif ( $feature->is_active() && ! $active ) {
279 // Just deactivate, don't force
280 $this->deactivate_feature( $slug, false );
281 }
282 }
283 }
284 }
285 }
286 }
287
288 /**
289 * Set up all active features
290 *
291 * @since 2.1
292 */
293 public function setup_features() {
294 /**
295 * Fires before features are setup
296 *
297 * @hook ep_setup_features
298 * @since 2.1
299 */
300 do_action( 'ep_setup_features' );
301
302 foreach ( $this->registered_features as $feature_slug => $feature ) {
303 if ( $feature->is_active() ) {
304 $feature->setup();
305 }
306 }
307 }
308
309 /**
310 * Return singleton instance of class
311 *
312 * @return object
313 * @since 2.1
314 */
315 public static function factory() {
316 static $instance = false;
317
318 if ( ! $instance ) {
319 $instance = new self();
320 $instance->setup();
321 }
322
323 return $instance;
324 }
325 }
326