PluginProbe
Elementor Website Builder – more than just a page builder / 3.16.1
Elementor Website Builder – more than just a page builder v3.16.1
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / dev-tools / deprecation.php

deprecation.php in Elementor Website Builder – more than just a page builder 3.16.1, at modules/dev-tools/deprecation.php

540 lines 15.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\DevTools;
3
4 use Elementor\Modules\DevTools\Backtrace_Helper;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly.
8 }
9
10 class Deprecation {
11 const SOFT_VERSIONS_COUNT = 4;
12 const HARD_VERSIONS_COUNT = 8;
13
14 private $current_version = null;
15 private $soft_deprecated_notices = [];
16
17 public function __construct( $current_version ) {
18 $this->current_version = $current_version;
19 }
20
21 public function get_settings() {
22 return [
23 'soft_notices' => $this->soft_deprecated_notices,
24 'soft_version_count' => self::SOFT_VERSIONS_COUNT,
25 'hard_version_count' => self::HARD_VERSIONS_COUNT,
26 'current_version' => ELEMENTOR_VERSION,
27 ];
28 }
29
30 /**
31 * Get total of major.
32 *
33 * Since `get_total_major` cannot determine how much really versions between 2.9.0 and 3.3.0 if there is 2.10.0 version for example,
34 * versions with major2 more then 9 will be added to total.
35 *
36 * @since 3.1.0
37 *
38 * @param array $parsed_version
39 *
40 * @return int
41 */
42 public function get_total_major( $parsed_version ) {
43 $major1 = $parsed_version['major1'];
44 $major2 = $parsed_version['major2'];
45 $major2 = $major2 > 9 ? 9 : $major2;
46 $minor = 0;
47
48 $total = intval( "{$major1}{$major2}{$minor}" );
49
50 if ( $total > 99 ) {
51 $total = $total / 10;
52 } else {
53 $total = intval( $total / 10 );
54 }
55
56 if ( $parsed_version['major2'] > 9 ) {
57 $total += $parsed_version['major2'] - 9;
58 }
59
60 return $total;
61 }
62
63 /**
64 * Get next version.
65 *
66 * @since 3.1.0
67 *
68 * @param string $version
69 * @param int $count
70 *
71 * @return string|false
72 */
73 public function get_next_version( $version, $count = 1 ) {
74 $version = $this->parse_version( $version );
75
76 if ( ! $version ) {
77 return false;
78 }
79
80 $version['total'] = $this->get_total_major( $version ) + $count;
81
82 $total = $version['total'];
83
84 if ( $total > 9 ) {
85 $version['major1'] = intval( $total / 10 );
86 $version['major2'] = $total % 10;
87 } else {
88 $version['major1'] = 0;
89 $version['major2'] = $total;
90 }
91
92 $version['minor'] = 0;
93
94 return $this->implode_version( $version );
95 }
96
97 /**
98 * Implode parsed version to string version.
99 *
100 * @since 3.1.0
101 *
102 * @param array $parsed_version
103 *
104 * @return string
105 */
106 public function implode_version( $parsed_version ) {
107 $major1 = $parsed_version['major1'];
108 $major2 = $parsed_version['major2'];
109 $minor = $parsed_version['minor'];
110
111 return "{$major1}.{$major2}.{$minor}";
112 }
113
114 /**
115 * Parse to an informative array.
116 *
117 * @since 3.1.0
118 *
119 * @param string $version
120 *
121 * @return array|false
122 */
123 public function parse_version( $version ) {
124 $version_explode = explode( '.', $version );
125 $version_explode_count = count( $version_explode );
126
127 if ( $version_explode_count < 3 || $version_explode_count > 4 ) {
128 // phpcs:disable WordPress.PHP.DevelopmentFunctions
129 trigger_error( 'Invalid Semantic Version string provided: ' . esc_html( var_export( $version, 1 ) ) );
130 // phpcs:enable
131
132 return false;
133 }
134
135 list( $major1, $major2, $minor ) = $version_explode;
136
137 $result = [
138 'major1' => intval( $major1 ),
139 'major2' => intval( $major2 ),
140 'minor' => intval( $minor ),
141 ];
142
143 if ( $version_explode_count > 3 ) {
144 $result['build'] = $version_explode[3];
145 }
146 return $result;
147 }
148
149 /**
150 * Compare two versions, result is equal to diff of major versions.
151 * Notice: If you want to compare between 2.9.0 and 3.3.0, and there is also a 2.10.0 version, you cannot get the right comparison
152 * Since $this->deprecation->get_total_major cannot determine how much really versions between 2.9.0 and 3.3.0.
153 *
154 * @since 3.1.0
155 *
156 * @param {string} $version1
157 * @param {string} $version2
158 *
159 * @return int|false
160 */
161 public function compare_version( $version1, $version2 ) {
162 $version1 = self::parse_version( $version1 );
163 $version2 = self::parse_version( $version2 );
164
165 if ( $version1 && $version2 ) {
166 $versions = [ &$version1, &$version2 ];
167
168 foreach ( $versions as &$version ) {
169 $version['total'] = self::get_total_major( $version );
170 }
171
172 return $version1['total'] - $version2['total'];
173 }
174 return false;
175 }
176
177 /**
178 * Check Deprecation
179 *
180 * Checks whether the given entity is valid. If valid, this method checks whether the deprecation
181 * should be soft (browser console notice) or hard (use WordPress' native deprecation methods).
182 *
183 * @since 3.15.0
184 *
185 * @param string $entity - The Deprecated entity (the function/hook itself)
186 * @param string $version
187 * @param string $replacement Optional
188 * @param string $stack_depth Optional. Default is 3. Change if calling functions depth changes.
189 *
190 * @return array
191 */
192 private function get_deprecation_info( $entity, $version, $replacement, $stack_depth = 3 ) {
193
194 $calling_source = Backtrace_Helper::find_who_called_me( $stack_depth );
195
196 $deprecation_info = [
197 'entity' => $entity,
198 'version' => $version,
199 'replacement' => $replacement,
200 'calling_function' => $calling_source['function'] ?? '',
201 'calling_file' => $calling_source['file'] ?? '',
202 'calling_line' => $calling_source['line'] ?? '',
203 'calling_plugin' => $calling_source['name'] ?? '',
204 'calling_type' => $calling_source['type'] ?? '',
205 ];
206 return $deprecation_info;
207 }
208
209 private function log_deprecation( $deprecation_object ) {
210 if ( empty( $deprecation_object['entity'] ) || ! $this->should_console_log_deprecated() ) {
211 return;
212 }
213
214 if ( ! isset( $this->soft_deprecated_notices[ $deprecation_object['entity'] ] ) ) {
215 $source_message = $this->create_location_message( $deprecation_object['calling_function'], $deprecation_object['calling_file'], $deprecation_object['calling_line'] );
216 $this->soft_deprecated_notices[ $deprecation_object['entity'] ] = [
217 $deprecation_object['version'],
218 $deprecation_object['replacement'],
219 $source_message,
220 ];
221 }
222
223 }
224
225 /**
226 * Checks whether deprecation message should be printed.
227 * If the user is logged in and has admin privileges, the message will be printed.
228 * If the user is not logged in, the message will be printed only if the user has WP_DEBUG enabled.
229 * If the user is logged in but does not have admin privileges, the message will be printed only if the user has ELEMENTOR_DEBUG enabled.
230 *
231 *
232 * @param mixed $version
233 * @param mixed $base_version
234 * @return bool
235 */
236 private function should_print_deprecated( $version, $base_version ) {
237 $is_elementor_debug = defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG;
238 $is_wp_debug = defined( 'WP_DEBUG' ) && WP_DEBUG;
239 $user_is_admin = current_user_can( 'manage_options' );
240 $user_is_logged_in = is_user_logged_in();
241
242 if ( $is_wp_debug ) {
243 if ( $is_elementor_debug ) {
244 return true;
245 }
246 if ( $user_is_admin ) {
247 return true;
248 }
249 if ( $user_is_logged_in && ! $this->is_first_deprecation_stage( $version, $base_version ) ) {
250 return true;
251 }
252 }
253 return false;
254 }
255
256 private function is_first_deprecation_stage( $version, $base_version ) {
257 if ( null === $base_version ) {
258 $base_version = $this->current_version;
259 }
260 $diff = $this->compare_version( $base_version, $version );
261 if ( false === $diff ) {
262 throw new \Exception( 'Invalid deprecation diff.' );
263 }
264 $first_deprecation_stage = $diff <= self::SOFT_VERSIONS_COUNT;
265 return $first_deprecation_stage;
266 }
267
268 private function should_console_log_deprecated() {
269 return defined( 'WP_DEBUG' ) && WP_DEBUG;
270 }
271
272 private function should_collect_deprication_info( $version, $base_version ) {
273 return $this->should_print_deprecated( $version, $base_version ) || $this->should_console_log_deprecated();
274 }
275
276 private function notify_deprecated_function( $deprecation_object ) {
277 /**
278 * Fires when a deprecated function is called.
279 *
280 * @since 2.5.0
281 *
282 * @param string $function_name The function that was called.
283 * @param string $replacement The function that should have been called.
284 * @param string $version The version of WordPress that deprecated the function.
285 */
286 do_action( 'deprecated_function_run', $deprecation_object['entity'], $deprecation_object['replacement'], $deprecation_object['version'] );
287
288 $source = $this->create_location_message( $deprecation_object['calling_function'], $deprecation_object['calling_file'], $deprecation_object['calling_line'] );
289
290 /**
291 * Filters whether to trigger an error for deprecated functions.
292 *
293 * @since 2.5.0
294 *
295 * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
296 */
297 if ( apply_filters( 'deprecated_function_trigger_error', true ) ) {
298 $message_string = '';
299 if ( ! empty( $deprecation_object['replacement'] ) ) {
300 $message_string = sprintf( __( 'Function %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead. Caller %4$s: %5$s. Called from: %6$s.', 'elementor' ),
301 $deprecation_object['entity'],
302 $deprecation_object['version'],
303 $deprecation_object['replacement'],
304 $deprecation_object['calling_type'],
305 $deprecation_object['calling_plugin'],
306 $source
307 );
308 } else {
309 $message_string = sprintf(__( 'Function %1$s is <strong>deprecated</strong> since version %2$s with no alternative available. Caller %3$s: %4$s. Called from: %5$s.', 'elementor' ),
310 $deprecation_object['entity'],
311 $deprecation_object['version'],
312 $deprecation_object['calling_type'],
313 $deprecation_object['calling_plugin'],
314 $source
315 );
316 }
317 $this->trigger_wp_error( $message_string );
318 }
319 }
320
321 private function notify_deprecated_argument( $deprecation_object, $message = '' ) {
322 do_action( 'deprecated_argument_run', $deprecation_object['entity'], $message, $deprecation_object['version'] );
323
324 $message = empty( $message ) ? '' : ' ' . $message;
325 $caller_location_message = $this->create_location_message( $deprecation_object['calling_function'], $deprecation_object['calling_file'], $deprecation_object['calling_line'] );
326
327 if ( ! empty( $deprecation_object['replacement'] ) ) {
328 /* translators: 1: Function argument, 2: Elementor version number, 3: Replacement argument name. */
329 $translation_string = sprintf(__( 'The %1$s argument is <strong>deprecated</strong> since version %2$s! Use %3$s instead. Caller %4$s: %5$s. Called from: %6$s.', 'elementor' ),
330 $deprecation_object['entity'],
331 $deprecation_object['version'],
332 $deprecation_object['replacement'],
333 $deprecation_object['calling_type'],
334 $deprecation_object['calling_plugin'],
335 $caller_location_message
336 ) . $message;
337
338 } else {
339 /* translators: 1: Function argument, 2: Elementor version number. */
340 $translation_string = sprintf(__( 'The %1$s argument is <strong>deprecated</strong> since version %2$s! Caller %3$s: %4$s. Called from: %5$s.', 'elementor' ),
341 $deprecation_object['entity'],
342 $deprecation_object['version'],
343 $deprecation_object['calling_type'],
344 $deprecation_object['calling_plugin'],
345 $caller_location_message
346 ) . $message;
347
348 }
349 $this->trigger_wp_error( $translation_string );
350
351 }
352
353 private function create_location_message( $function, $file, $line ) {
354 return sprintf( '%s on file %s:%d.', $function, $file, $line );
355 }
356
357 private function trigger_wp_error( $message ) {
358 // phpcs:disable WordPress.PHP.DevelopmentFunctions
359 trigger_error( wp_kses_post( $message ), E_USER_DEPRECATED );
360 // phpcs:enable
361 }
362
363
364 /**
365 * Deprecated Function
366 *
367 * Handles the deprecation process for functions
368 *
369 * @since 3.1.0
370 *
371 * @param string $function
372 * @param string $version
373 * @param string $replacement Optional. Default is ''
374 * @param string $base_version Optional. Default is `null`
375 * @throws \Exception
376 */
377 public function deprecated_function( $function, $version, $replacement = '', $base_version = null ) {
378
379 if ( null === $base_version ) {
380 $base_version = $this->current_version;
381 }
382 if ( ! $this->should_collect_deprication_info( $version, $base_version ) ) {
383 return;
384 }
385 $deprecation_info = $this->get_deprecation_info( $function, $version, $replacement );
386
387 if ( ! empty( $deprecation_info ) ) {
388 $this->log_deprecation( $deprecation_info );
389
390 if ( $this->should_print_deprecated( $version, $base_version ) ) {
391 $this->notify_deprecated_function( $deprecation_info );
392 }
393 }
394 }
395
396
397 /**
398 * Deprecated Hook
399 *
400 * Handles the deprecation process for hooks.
401 *
402 * @since 3.1.0
403 *
404 * @param string $hook
405 * @param string $version
406 * @param string $replacement Optional. Default is ''
407 * @param string $base_version Optional. Default is `null`
408 * @throws \Exception
409 */
410 public function deprecated_hook( $hook, $version, $replacement = '', $base_version = null ) {
411 if ( null === $base_version ) {
412 $base_version = $this->current_version;
413 }
414
415 if ( ! $this->should_collect_deprication_info( $version, $base_version ) ) {
416 return;
417 }
418
419 $deprecation_info = $this->get_deprecation_info( $hook, $version, $replacement );
420 if ( ! empty( $deprecation_info ) ) {
421 $this->log_deprecation( $deprecation_info );
422 if ( $this->should_print_deprecated( $version, $base_version ) ) {
423 $this->notify_deprecated_hook( $deprecation_info );
424 }
425 }
426 }
427
428
429 private function notify_deprecated_hook( $deprecation_object ) {
430 $message = $this->create_location_message( $deprecation_object['calling_function'], $deprecation_object['calling_file'], $deprecation_object['calling_line'] );
431 _deprecated_hook( esc_html( $deprecation_object['entity'] ), esc_html( $deprecation_object['version'] ), esc_html( $deprecation_object['replacement'] ), esc_html( $message ) );
432 }
433
434 /**
435 * Deprecated Argument
436 *
437 * Handles the deprecation process for function arguments.
438 *
439 * @since 3.1.0
440 *
441 * @param string $argument
442 * @param string $version
443 * @param string $replacement
444 * @param string $message
445 * @throws \Exception
446 */
447 public function deprecated_argument( $argument, $version, $replacement = '', $message = '' ) {
448 $base_version = $this->current_version;
449
450 if ( ! $this->should_collect_deprication_info( $version, $base_version ) ) {
451 return;
452 }
453
454 $deprecation_info = $this->get_deprecation_info( $argument, $version, $replacement );
455
456 if ( ! empty( $deprecation_info ) ) {
457 $this->log_deprecation( $deprecation_info );
458
459 if ( $this->should_print_deprecated( $version, $base_version ) ) {
460 $this->notify_deprecated_argument( $deprecation_info, $message );
461 }
462 }
463 }
464
465 /**
466 * Do Deprecated Action
467 *
468 * A method used to run deprecated actions through Elementor's deprecation process.
469 *
470 * @since 3.1.0
471 *
472 * @param string $hook
473 * @param array $args
474 * @param string $version
475 * @param string $replacement
476 * @param null|string $base_version
477 *
478 * @throws \Exception
479 */
480 public function do_deprecated_action( $hook, $args, $version, $replacement = '', $base_version = null ) {
481 if ( ! has_action( $hook ) ) {
482 return;
483 }
484 if ( null === $base_version ) {
485 $base_version = $this->current_version;
486 }
487
488 if ( ! $this->should_collect_deprication_info( $version, $base_version ) ) {
489 return;
490 }
491
492 $deprecation_info = $this->get_deprecation_info( $hook, $version, $replacement );
493 if ( ! empty( $deprecation_info ) ) {
494 $this->log_deprecation( $deprecation_info );
495 if ( $this->should_print_deprecated( $version, $base_version ) ) {
496 $this->notify_deprecated_hook( $deprecation_info );
497 }
498 }
499
500 do_action_ref_array( $hook, $args );
501 }
502
503 /**
504 * Apply Deprecated Filter
505 *
506 * A method used to run deprecated filters through Elementor's deprecation process.
507 *
508 * @since 3.2.0
509 *
510 * @param string $hook
511 * @param array $args
512 * @param string $version
513 * @param string $replacement
514 * @param null|string $base_version
515 *
516 * @return mixed
517 * @throws \Exception
518 */
519 public function apply_deprecated_filter( $hook, $args, $version, $replacement = '', $base_version = null ) {
520 if ( ! has_action( $hook ) ) {
521 // `$args` should be an array, but in order to keep BC, we need to support non-array values.
522 if ( is_array( $args ) ) {
523 return $args[0] ?? null;
524 }
525
526 return $args;
527 }
528
529 // BC - See the comment above.
530 if ( ! is_array( $args ) ) {
531 $args = [ $args ];
532 }
533
534 // Avoid associative arrays.
535 $args = array_values( $args );
536 $this->deprecated_hook( $hook, $version, $replacement, $base_version );
537 return apply_filters_ref_array( $hook, $args );
538 }
539 }
540