deprecation.php (9329B)
1 <?php 2 namespace Elementor\Modules\DevTools; 3 4 if ( ! defined( 'ABSPATH' ) ) { 5 exit; // Exit if accessed directly. 6 } 7 8 class Deprecation { 9 const SOFT_VERSIONS_COUNT = 4; 10 const HARD_VERSIONS_COUNT = 8; 11 12 private $current_version = null; 13 private $soft_deprecated_notices = []; 14 15 public function __construct( $current_version ) { 16 $this->current_version = $current_version; 17 } 18 19 public function get_settings() { 20 return [ 21 'soft_notices' => $this->soft_deprecated_notices, 22 ]; 23 } 24 25 /** 26 * Get total of major. 27 * 28 * 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, 29 * versions with major2 more then 9 will be added to total. 30 * 31 * @since 3.1.0 32 * 33 * @param array $parsed_version 34 * 35 * @return int 36 */ 37 public function get_total_major( $parsed_version ) { 38 $major1 = $parsed_version['major1']; 39 $major2 = $parsed_version['major2']; 40 $major2 = $major2 > 9 ? 9 : $major2; 41 $minor = 0; 42 43 $total = intval( "{$major1}{$major2}{$minor}" ); 44 45 if ( $total > 99 ) { 46 $total = $total / 10; 47 } else { 48 $total = intval( $total / 10 ); 49 } 50 51 if ( $parsed_version['major2'] > 9 ) { 52 $total += $parsed_version['major2'] - 9; 53 } 54 55 return $total; 56 } 57 58 /** 59 * Get next version. 60 * 61 * @since 3.1.0 62 * 63 * @param string $version 64 * @param int $count 65 * 66 * @return string|false 67 */ 68 public function get_next_version( $version, $count = 1 ) { 69 $version = $this->parse_version( $version ); 70 71 if ( ! $version ) { 72 return false; 73 } 74 75 $version['total'] = $this->get_total_major( $version ) + $count; 76 77 $total = $version['total']; 78 79 if ( $total > 9 ) { 80 $version['major1'] = intval( $total / 10 ); 81 $version['major2'] = $total % 10; 82 } else { 83 $version['major1'] = 0; 84 $version['major2'] = $total; 85 } 86 87 $version['minor'] = 0; 88 89 return $this->implode_version( $version ); 90 } 91 92 /** 93 * Implode parsed version to string version. 94 * 95 * @since 3.1.0 96 * 97 * @param array $parsed_version 98 * 99 * @return string 100 */ 101 public function implode_version( $parsed_version ) { 102 $major1 = $parsed_version['major1']; 103 $major2 = $parsed_version['major2']; 104 $minor = $parsed_version['minor']; 105 106 return "{$major1}.{$major2}.{$minor}"; 107 } 108 109 /** 110 * Parse to an informative array. 111 * 112 * @since 3.1.0 113 * 114 * @param string $version 115 * 116 * @return array|false 117 */ 118 public function parse_version( $version ) { 119 $version_explode = explode( '.', $version ); 120 $version_explode_count = count( $version_explode ); 121 122 if ( $version_explode_count < 3 || $version_explode_count > 4 ) { 123 trigger_error( 'Invalid Semantic Version string provided' ); 124 125 return false; 126 } 127 128 list( $major1, $major2, $minor ) = $version_explode; 129 130 $result = [ 131 'major1' => intval( $major1 ), 132 'major2' => intval( $major2 ), 133 'minor' => intval( $minor ), 134 ]; 135 136 if ( $version_explode_count > 3 ) { 137 $result['build'] = $version_explode[3]; 138 } 139 140 return $result; 141 } 142 143 /** 144 * Compare two versions, result is equal to diff of major versions. 145 * 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 146 * Since $this->deprecation->get_total_major cannot determine how much really versions between 2.9.0 and 3.3.0. 147 * 148 * @since 3.1.0 149 * 150 * @param {string} $version1 151 * @param {string} $version2 152 * 153 * @return int|false 154 */ 155 public function compare_version( $version1, $version2 ) { 156 $version1 = self::parse_version( $version1 ); 157 $version2 = self::parse_version( $version2 ); 158 159 if ( $version1 && $version2 ) { 160 $versions = [ &$version1, &$version2 ]; 161 162 foreach ( $versions as &$version ) { 163 $version['total'] = self::get_total_major( $version ); 164 } 165 166 return $version1['total'] - $version2['total']; 167 } 168 169 return false; 170 } 171 172 /** 173 * Check Deprecation 174 * 175 * Checks whether the given entity is valid. If valid, this method checks whether the deprecation 176 * should be soft (browser console notice) or hard (use WordPress' native deprecation methods). 177 * 178 * @since 3.1.0 179 * 180 * @param string $entity - The Deprecated entity (the function/hook itself) 181 * @param string $version 182 * @param string $replacement Optional 183 * @param string $base_version Optional. Default is `null` 184 * 185 * @return bool|void 186 * @throws \Exception 187 */ 188 private function check_deprecation( $entity, $version, $replacement, $base_version = null ) { 189 if ( null === $base_version ) { 190 $base_version = $this->current_version; 191 } 192 193 $diff = $this->compare_version( $base_version, $version ); 194 195 if ( false === $diff ) { 196 throw new \Exception( 'Invalid deprecation diff' ); 197 } 198 199 $print_deprecated = false; 200 201 if ( defined( 'WP_DEBUG' ) && WP_DEBUG && $diff <= self::SOFT_VERSIONS_COUNT ) { 202 // Soft deprecated. 203 if ( ! isset( $this->soft_deprecated_notices[ $entity ] ) ) { 204 $this->soft_deprecated_notices[ $entity ] = [ 205 $version, 206 $replacement, 207 ]; 208 } 209 210 if ( defined( 'ELEMENTOR_DEBUG' ) && ELEMENTOR_DEBUG ) { 211 $print_deprecated = true; 212 } 213 } else { 214 // Hard deprecated. 215 $print_deprecated = true; 216 } 217 218 return $print_deprecated; 219 } 220 221 /** 222 * Deprecated Function 223 * 224 * Handles the deprecation process for functions. 225 * 226 * @since 3.1.0 227 * 228 * @param string $function 229 * @param string $version 230 * @param string $replacement Optional. Default is '' 231 * @param string $base_version Optional. Default is `null` 232 * @throws \Exception 233 */ 234 public function deprecated_function( $function, $version, $replacement = '', $base_version = null ) { 235 $print_deprecated = $this->check_deprecation( $function, $version, $replacement, $base_version ); 236 237 if ( $print_deprecated ) { 238 // PHPCS - We need to echo special characters because they can exist in function calls. 239 _deprecated_function( $function, esc_html( $version ), $replacement ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 240 } 241 } 242 243 /** 244 * Deprecated Hook 245 * 246 * Handles the deprecation process for hooks. 247 * 248 * @since 3.1.0 249 * 250 * @param string $hook 251 * @param string $version 252 * @param string $replacement Optional. Default is '' 253 * @param string $base_version Optional. Default is `null` 254 * @throws \Exception 255 */ 256 public function deprecated_hook( $hook, $version, $replacement = '', $base_version = null ) { 257 $print_deprecated = $this->check_deprecation( $hook, $version, $replacement, $base_version ); 258 259 if ( $print_deprecated ) { 260 _deprecated_hook( esc_html( $hook ), esc_html( $version ), esc_html( $replacement ) ); 261 } 262 } 263 264 /** 265 * Deprecated Argument 266 * 267 * Handles the deprecation process for function arguments. 268 * 269 * @since 3.1.0 270 * 271 * @param string $argument 272 * @param string $version 273 * @param string $replacement 274 * @param string $message 275 * @throws \Exception 276 */ 277 public function deprecated_argument( $argument, $version, $replacement = '', $message = '' ) { 278 $print_deprecated = $this->check_deprecation( $argument, $version, $replacement ); 279 280 if ( $print_deprecated ) { 281 $message = empty( $message ) ? '' : ' ' . $message; 282 // These arguments are escaped because they are printed later, and are not escaped when printed. 283 $error_message_args = [ esc_html( $argument ), esc_html( $version ) ]; 284 285 if ( $replacement ) { 286 /* translators: 1: Function argument, 2: Elementor version number, 3: Replacement argument name. */ 287 $translation_string = esc_html__( 'The %1$s argument is deprecated since version %2$s! Use %3$s instead.', 'elementor' ); 288 $error_message_args[] = $replacement; 289 } else { 290 /* translators: 1: Function argument, 2: Elementor version number. */ 291 $translation_string = esc_html__( 'The %1$s argument is deprecated since version %2$s!', 'elementor' ); 292 } 293 294 trigger_error( 295 vsprintf( 296 // PHPCS - $translation_string is already escaped above. 297 $translation_string, // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 298 // PHPCS - $error_message_args is an array. 299 $error_message_args // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 300 ) . esc_html( $message ), 301 E_USER_DEPRECATED 302 ); 303 } 304 } 305 306 /** 307 * Do Deprecated Action 308 * 309 * A method used to run deprecated actions through Elementor's deprecation process. 310 * 311 * @since 3.1.0 312 * 313 * @param string $hook 314 * @param array $args 315 * @param string $version 316 * @param string $replacement 317 * @param null|string $base_version 318 * 319 * @throws \Exception 320 */ 321 public function do_deprecated_action( $hook, $args, $version, $replacement = '', $base_version = null ) { 322 if ( ! has_action( $hook ) ) { 323 return; 324 } 325 326 $this->deprecated_hook( $hook, $version, $replacement, $base_version ); 327 328 do_action_ref_array( $hook, $args ); 329 } 330 331 /** 332 * Apply Deprecated Filter 333 * 334 * A method used to run deprecated filters through Elementor's deprecation process. 335 * 336 * @since 3.2.0 337 * 338 * @param string $hook 339 * @param array $args 340 * @param string $version 341 * @param string $replacement 342 * @param null|string $base_version 343 * 344 * @return mixed 345 * @throws \Exception 346 */ 347 public function apply_deprecated_filter( $hook, $args, $version, $replacement = '', $base_version = null ) { 348 if ( ! has_action( $hook ) ) { 349 return; 350 } 351 352 $this->deprecated_hook( $hook, $version, $replacement, $base_version ); 353 354 return apply_filters_ref_array( $hook, $args ); 355 } 356 }