PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / trunk
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More vtrunk
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / classes / Plugin / Prerequisites.php

Prerequisites.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More trunk, at classes/Plugin/Prerequisites.php

406 lines 10.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Prerequisite handler.
4 *
5 * @package ContentControl\Utils
6 */
7
8 namespace ContentControl\Plugin;
9
10 defined( 'ABSPATH' ) || exit;
11
12 /**
13 * Prerequisite handler.
14 *
15 * @version 1.0.0
16 */
17 class Prerequisites {
18
19 /**
20 * Cache accessible across instances.
21 *
22 * @var array<string,array<string,mixed>>
23 */
24 public static $cache = [];
25
26 /**
27 * Array of checks to perform.
28 *
29 * @var array{type:string,version:string}[]
30 */
31 protected $checks = [];
32
33 /**
34 * Array of detected failures.
35 *
36 * @var array{type:string,version:string}[]
37 */
38 protected $failures = [];
39
40 /**
41 * Instantiate prerequisite checker.
42 *
43 * @param array{type:string,version:string}[] $requirements Array of requirements.
44 */
45 public function __construct( $requirements = [] ) {
46 foreach ( $requirements as $arguments ) {
47 switch ( $arguments['type'] ) {
48 case 'php':
49 $this->checks[] = wp_parse_args(
50 $arguments,
51 [
52 'type' => 'php',
53 'version' => '5.6',
54 ]
55 );
56 break;
57 // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText
58 case 'wordpress':
59 case 'wp':
60 $this->checks[] = wp_parse_args(
61 $arguments,
62 [
63 'type' => 'wp',
64 'version' => '5.6',
65 ]
66 );
67 break;
68 case 'plugin':
69 $this->checks[] = wp_parse_args(
70 $arguments,
71 [
72 'type' => 'plugin',
73 'slug' => '',
74 'name' => '',
75 'version' => '',
76 'check_installed' => false,
77 'dep_label' => '',
78 ]
79 );
80 break;
81 default:
82 break;
83 }
84 }
85 }
86
87 /**
88 * Check requirements.
89 *
90 * @param boolean $return_on_fail Whether it should stop processing if one fails.
91 *
92 * @return bool
93 */
94 public function check( $return_on_fail = false ) {
95 $end_result = true;
96
97 foreach ( $this->checks as $check ) {
98 $result = $this->check_handler( $check );
99
100 if ( false === $result ) {
101 if ( true === $return_on_fail ) {
102 return false;
103 }
104
105 $end_result = false;
106 }
107 }
108
109 return $end_result;
110 }
111
112 /**
113 * Render notices when appropriate.
114 *
115 * @return void
116 */
117 public function setup_notices() {
118 add_action( 'admin_notices', [ $this, 'render_notices' ] );
119 }
120
121 /**
122 * Handle individual checks by mapping them to methods.
123 *
124 * @param array{type:string,version:string} $check Requirement check arguments.
125 *
126 * @return bool
127 */
128 public function check_handler( $check ) {
129 return method_exists( $this, 'check_' . $check['type'] ) ? $this->{'check_' . $check['type']}( $check ) : false;
130 }
131
132 /**
133 * Report failure notice to the queue.
134 *
135 * @param array{type:string,version:string} $check_args Array of check arguments.
136 *
137 * @return void
138 */
139 public function report_failure( $check_args ) {
140 $this->failures[] = $check_args;
141 }
142
143 /**
144 * Get a list of failures.
145 *
146 * @return array{type:string,version:string}[]
147 */
148 public function get_failures() {
149 return $this->failures;
150 }
151
152 /**
153 * Check PHP version against args.
154 *
155 * @param array{type:string,version:string} $check_args Array of args.
156 *
157 * @return bool
158 */
159 public function check_php( $check_args ) {
160 if ( false === version_compare( phpversion(), $check_args['version'], '>=' ) ) {
161 $this->report_failure( $check_args );
162 return false;
163 }
164
165 return true;
166 }
167
168
169 /**
170 * Check PHP version against args.
171 *
172 * @param array{type:string,version:string} $check_args Array of args.
173 *
174 * @return bool
175 */
176 public function check_wp( $check_args ) {
177 global $wp_version;
178
179 if ( false === version_compare( $wp_version, $check_args['version'], '>=' ) ) {
180 $this->report_failure( $check_args );
181 return false;
182 }
183
184 return true;
185 }
186
187 /**
188 * Check plugin requirements.
189 *
190 * @param array{type:string,version:string,name:string,slug:string,version:string,check_installed:bool,dep_label:string} $check_args Array of args.
191 *
192 * @return bool
193 */
194 public function check_plugin( $check_args ) {
195 $active = $this->plugin_is_active( $check_args['slug'] );
196
197 /**
198 * The following checks are performed in this order for performance reasons.
199 *
200 * We start with most cached option, to least in hopes of a hit early.
201 *
202 * 1. If active and not checking version.
203 * 2. If active and outdated.
204 * 3. If not active and installed.
205 * 4. If not installed
206 */
207 if ( true === $active ) {
208 // If required version is set & plugin is active, check that first.
209 if ( ! empty( $check_args['version'] ) ) {
210 $version = $this->get_plugin_data( $check_args['slug'], 'Version' );
211
212 // If its higher than the required version, we can bail now > true.
213 if ( version_compare( $version, $check_args['version'], '>=' ) ) {
214 return true;
215 } else {
216 // If not updated, report the failure and bail > false.
217 $this->report_failure(
218 array_merge(
219 $check_args,
220 [
221 // Report not_updated status.
222 'not_updated' => true,
223 ]
224 )
225 );
226 return false;
227 }
228 } else {
229 // If the plugin is active, with no required version, were done > true.
230 return true;
231 }
232 }
233
234 if ( $check_args['check_installed'] ) {
235 // Check if installed, if so the plugin is not activated.
236 if ( $check_args['name'] === $this->get_plugin_data( $check_args['slug'], 'Name' ) ) {
237 $this->report_failure(
238 array_merge(
239 $check_args,
240 [
241 // Report not_activated status.
242 'not_activated' => true,
243 ]
244 )
245 );
246 } else {
247 $this->report_failure(
248 array_merge(
249 $check_args,
250 [
251 // Report not_installed status.
252 'not_installed' => true,
253 ]
254 )
255 );
256 }
257 }
258
259 return false;
260 }
261
262 /**
263 * Internally cached get_plugin_data/get_file_data wrapper.
264 *
265 * @param string $slug Plugins `folder/file.php` slug.
266 * @param string $header Specific plugin header needed.
267 * @return mixed
268 */
269 private function get_plugin_data( $slug, $header = null ) {
270 if ( ! isset( static::$cache['get_plugin_data'][ $slug ] ) ) {
271 $headers = \get_file_data( WP_PLUGIN_DIR . '/' . $slug, [
272 'Name' => 'Plugin Name',
273 'Version' => 'Version',
274 ], 'plugin' );
275
276 static::$cache['get_plugin_data'][ $slug ] = $headers;
277 }
278
279 $plugin_data = static::$cache['get_plugin_data'][ $slug ];
280
281 if ( empty( $header ) ) {
282 return $plugin_data;
283 }
284
285 return isset( $plugin_data[ $header ] ) ? $plugin_data[ $header ] : null;
286 }
287
288 /**
289 * Check if plugin is active.
290 *
291 * @param string $slug Slug to check for.
292 *
293 * @return bool
294 */
295 protected function plugin_is_active( $slug ) {
296 $active_plugins = \get_option( 'active_plugins', [] );
297
298 return in_array( $slug, $active_plugins, true );
299 }
300
301
302 /**
303 * Get php error message.
304 *
305 * @param array{type:string,version:string} $failed_check_args Check arguments.
306 *
307 * @return string
308 */
309 public function get_php_message( $failed_check_args ) {
310 /* translators: 1. Requirement name (WordPress|PHP)., 2. Version Number. */
311 $message = __( 'This plugin requires <b>%1$s %2$s</b> or higher in order to run.', 'content-control' );
312 return sprintf(
313 $message,
314 // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Reuse the WordPress Core translation.
315 __( 'PHP', 'default' ),
316 $failed_check_args['version'] );
317 }
318
319 /**
320 * Get wp error message.
321 *
322 * @param array{type:string,version:string} $failed_check_args Check arguments.
323 *
324 * @return string
325 */
326 public function get_wp_message( $failed_check_args ) {
327 /* translators: 1. Requirement name (WordPress|PHP)., 2. Version Number. */
328 $message = __( 'This plugin requires <b>%1$s %2$s</b> or higher in order to run.', 'content-control' );
329 return sprintf(
330 $message,
331 // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch -- Reuse the WordPress Core translation.
332 __( 'WordPress', 'default' ),
333 $failed_check_args['version']
334 );
335 }
336
337 /**
338 * Get plugin error message.
339 *
340 * @param array{type:string,version:string,name:string,slug:string,version:string,check_installed:bool,dep_label:string,not_activated?:bool|null,not_updated?:bool|null} $failed_check_args Get helpful error message.
341 *
342 * @return string
343 */
344 public function get_plugin_message( $failed_check_args ) {
345 $slug = $failed_check_args['slug'];
346 // Without file path.
347 $short_slug = explode( '/', $slug );
348 $short_slug = $short_slug[0];
349 $name = $failed_check_args['name'];
350 $dep_label = $failed_check_args['dep_label'];
351
352 if ( isset( $failed_check_args['not_activated'] ) ) {
353 $url = esc_url( wp_nonce_url( admin_url( 'plugins.php?action=activate&plugin=' . $slug ), 'activate-plugin_' . $slug ) );
354 $link = '<a href="' . $url . '">' . __( 'activate it', 'content-control' ) . '</a>';
355
356 $text = sprintf(
357 /* translators: 1. Plugin Name, 2. Required Plugin Name, 4. `activate it` link. */
358 __( 'The plugin "%1$s" requires %2$s! Please %3$s to continue!', 'content-control' ),
359 $dep_label,
360 '<strong>' . $name . '</strong>',
361 $link
362 );
363 } elseif ( isset( $failed_check_args['not_updated'] ) ) {
364 $url = esc_url( wp_nonce_url( admin_url( 'update.php?action=upgrade-plugin&plugin=' . $slug ), 'upgrade-plugin_' . $slug ) );
365 $link = '<a href="' . $url . '">' . __( 'update it', 'content-control' ) . '</a>';
366
367 $text = sprintf(
368 /* translators: 1. Plugin Name, 2. Required Plugin Name, 3. Version number, 4. `update it` link. */
369 __( 'The plugin "%1$s" requires %2$s v%3$s or higher! Please %4$s to continue!', 'content-control' ),
370 $dep_label,
371 '<strong>' . $name . '</strong>',
372 '<strong>' . $failed_check_args['version'] . '</strong>',
373 $link
374 );
375 } else {
376 $url = esc_url( wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . $short_slug ), 'install-plugin_' . $short_slug ) );
377 $link = '<a href="' . $url . '">' . __( 'install it', 'content-control' ) . '</a>';
378
379 $text = sprintf(
380 /* translators: 1. Plugin Name, 2. Required Plugin Name, 3. `install it` link. */
381 __( 'The plugin "%1$s" requires %2$s! Please %3$s to continue!', 'content-control' ),
382 $dep_label,
383 '<strong>' . $name . '</strong>',
384 $link
385 );
386 }
387
388 return $text;
389 }
390
391 /**
392 * Render needed admin notices.
393 *
394 * @return void
395 */
396 public function render_notices() {
397 foreach ( $this->failures as $failure ) {
398 $class = 'notice notice-error';
399 $message = method_exists( $this, 'get_' . $failure['type'] . '_message' ) ? $this->{'get_' . $failure['type'] . '_message'}( $failure ) : false;
400
401 // Requirement messages contain only the post-safe links and emphasis generated above.
402 printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), wp_kses_post( $message ) );
403 }
404 }
405 }
406