WPSEO_Utils

Group of utility methods for use by WPSEO All methods are static, this is just a sort of namespacing class wrapper.

Defined (1)

The class is defined in the following location(s).

/inc/class-wpseo-utils.php  
  1. class WPSEO_Utils { 
  2.  
  3. /** 
  4. * @var bool $has_filters Whether the PHP filter extension is enabled 
  5. * @static 
  6. * @since 1.8.0 
  7. */ 
  8. public static $has_filters; 
  9.  
  10. /** 
  11. * @var array notifications to be shown in the JavaScript console 
  12. * @static 
  13. * @since 3.3.2 
  14. */ 
  15. protected static $console_notifications = array(); 
  16.  
  17. /** 
  18. * Check whether the current user is allowed to access the configuration. 
  19. * @static 
  20. * @since 1.8.0 
  21. * @return boolean 
  22. */ 
  23. public static function grant_access() { 
  24. if ( ! is_multisite() ) { 
  25. return true; 
  26.  
  27. $options = get_site_option( 'wpseo_ms' ); 
  28.  
  29. if ( empty( $options['access'] ) || $options['access'] === 'admin' ) { 
  30. return current_user_can( 'manage_options' ); 
  31.  
  32. return is_super_admin(); 
  33.  
  34. /** 
  35. * Check whether file editing is allowed for the .htaccess and robots.txt files 
  36. * @internal current_user_can() checks internally whether a user is on wp-ms and adjusts accordingly. 
  37. * @static 
  38. * @since 1.8.0 
  39. * @return bool 
  40. */ 
  41. public static function allow_system_file_edit() { 
  42. $allowed = true; 
  43.  
  44. if ( current_user_can( 'edit_files' ) === false ) { 
  45. $allowed = false; 
  46.  
  47. /** 
  48. * Filter: 'wpseo_allow_system_file_edit' - Allow developers to change whether the editing of 
  49. * .htaccess and robots.txt is allowed 
  50. * @api bool $allowed Whether file editing is allowed 
  51. */ 
  52.  
  53. return apply_filters( 'wpseo_allow_system_file_edit', $allowed ); 
  54.  
  55. /** 
  56. * Check if the web server is running on Apache 
  57. * @static 
  58. * @since 1.8.0 
  59. * @return bool 
  60. */ 
  61. public static function is_apache() { 
  62. if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'apache' ) !== false ) { 
  63. return true; 
  64.  
  65. return false; 
  66.  
  67. /** 
  68. * Check if the web server is running on Nginx 
  69. * @static 
  70. * @since 1.8.0 
  71. * @return bool 
  72. */ 
  73. public static function is_nginx() { 
  74. if ( isset( $_SERVER['SERVER_SOFTWARE'] ) && stristr( $_SERVER['SERVER_SOFTWARE'], 'nginx' ) !== false ) { 
  75. return true; 
  76.  
  77. return false; 
  78.  
  79. /** 
  80. * Register a notification to be shown in the JavaScript console 
  81. * @since 3.3.2 
  82. * @param string $identifier Notification identifier. 
  83. * @param string $message Message to be shown. 
  84. * @param bool $one_time_only Only show once (if added multiple times). 
  85. */ 
  86. public static function javascript_console_notification( $identifier, $message, $one_time_only = false ) { 
  87. static $registered_hook; 
  88.  
  89. if ( is_null( $registered_hook ) ) { 
  90. add_action( 'admin_footer', array( __CLASS__, 'localize_console_notices' ), 999 ); 
  91. $registered_hook = true; 
  92.  
  93. $prefix = 'Yoast SEO: '; 
  94. if ( substr( $message, 0, strlen( $prefix ) ) !== $prefix ) { 
  95. $message = $prefix . $message; 
  96.  
  97. if ( $one_time_only ) { 
  98. self::$console_notifications[ $identifier ] = $message; 
  99. else { 
  100. self::$console_notifications[] = $message; 
  101.  
  102. /** 
  103. * Localize the console notifications to JavaScript 
  104. * @since 3.3.2 
  105. */ 
  106. public static function localize_console_notices() { 
  107. if ( empty( self::$console_notifications ) ) { 
  108. return; 
  109.  
  110. wp_localize_script( WPSEO_Admin_Asset_Manager::PREFIX . 'admin-global-script', 'wpseoConsoleNotifications', array_values( self::$console_notifications ) ); 
  111.  
  112. /** 
  113. * Check whether a url is relative 
  114. * @since 1.8.0 
  115. * @param string $url URL string to check. 
  116. * @return bool 
  117. */ 
  118. public static function is_url_relative( $url ) { 
  119. return ( strpos( $url, 'http' ) !== 0 && strpos( $url, '//' ) !== 0 ); 
  120.  
  121. /** 
  122. * List all the available user roles 
  123. * @since 1.8.0 
  124. * @static 
  125. * @return array $roles 
  126. */ 
  127. public static function get_roles() { 
  128. global $wp_roles; 
  129.  
  130. if ( ! isset( $wp_roles ) ) { 
  131. $wp_roles = new WP_Roles(); 
  132.  
  133. $roles = $wp_roles->get_names(); 
  134.  
  135. return $roles; 
  136.  
  137. /** 
  138. * Standardize whitespace in a string 
  139. * Replace line breaks, carriage returns, tabs with a space, then remove double spaces. 
  140. * @since 1.8.0 
  141. * @param string $string String input to standardize. 
  142. * @return string 
  143. */ 
  144. public static function standardize_whitespace( $string ) { 
  145. return trim( str_replace( ' ', ' ', str_replace( array( "\t", "\n", "\r", "\f" ), ' ', $string ) ) ); 
  146.  
  147. /** 
  148. * First strip out registered and enclosing shortcodes using native WordPress strip_shortcodes function. 
  149. * Then strip out the shortcodes with a filthy regex, because people don't properly register their shortcodes. 
  150. * @static 
  151. * @since 1.8.0 
  152. * @param string $text Input string that might contain shortcodes. 
  153. * @return string $text string without shortcodes 
  154. */ 
  155. public static function strip_shortcode( $text ) { 
  156. return preg_replace( '`\[[^\]]+\]`s', '', strip_shortcodes( $text ) ); 
  157.  
  158. /** 
  159. * Recursively trim whitespace round a string value or of string values within an array 
  160. * Only trims strings to avoid typecasting a variable (to string) 
  161. * @static 
  162. * @since 1.8.0 
  163. * @param mixed $value Value to trim or array of values to trim. 
  164. * @return mixed Trimmed value or array of trimmed values 
  165. */ 
  166. public static function trim_recursive( $value ) { 
  167. if ( is_string( $value ) ) { 
  168. $value = trim( $value ); 
  169. elseif ( is_array( $value ) ) { 
  170. $value = array_map( array( __CLASS__, 'trim_recursive' ), $value ); 
  171.  
  172. return $value; 
  173.  
  174. /** 
  175. * Translates a decimal analysis score into a textual one. 
  176. * @static 
  177. * @since 1.8.0 
  178. * @param int $val The decimal score to translate. 
  179. * @param bool $css_value Whether to return the i18n translated score or the CSS class value. 
  180. * @return string 
  181. */ 
  182. public static function translate_score( $val, $css_value = true ) { 
  183. $seo_rank = WPSEO_Rank::from_numeric_score( $val ); 
  184.  
  185. if ( $css_value ) { 
  186. return $seo_rank->get_css_class(); 
  187.  
  188. return $seo_rank->get_label(); 
  189.  
  190. /** 
  191. * Emulate the WP native sanitize_text_field function in a %%variable%% safe way 
  192. * @see https://core.trac.wordpress.org/browser/trunk/src/wp-includes/formatting.php for the original 
  193. * Sanitize a string from user input or from the db 
  194. * check for invalid UTF-8,  
  195. * Convert single < characters to entity,  
  196. * strip all tags,  
  197. * remove line breaks, tabs and extra white space,  
  198. * strip octets - BUT DO NOT REMOVE (part of) VARIABLES WHICH WILL BE REPLACED. 
  199. * @static 
  200. * @since 1.8.0 
  201. * @param string $value String value to sanitize. 
  202. * @return string 
  203. */ 
  204. public static function sanitize_text_field( $value ) { 
  205. $filtered = wp_check_invalid_utf8( $value ); 
  206.  
  207. if ( strpos( $filtered, '<' ) !== false ) { 
  208. $filtered = wp_pre_kses_less_than( $filtered ); 
  209. // This will strip extra whitespace for us. 
  210. $filtered = wp_strip_all_tags( $filtered, true ); 
  211. else { 
  212. $filtered = trim( preg_replace( '`[\r\n\t ]+`', ' ', $filtered ) ); 
  213.  
  214. $found = false; 
  215. while ( preg_match( '`[^%](%[a-f0-9]{2})`i', $filtered, $match ) ) { 
  216. $filtered = str_replace( $match[1], '', $filtered ); 
  217. $found = true; 
  218. unset( $match ); 
  219.  
  220. if ( $found ) { 
  221. // Strip out the whitespace that may now exist after removing the octets. 
  222. $filtered = trim( preg_replace( '` +`', ' ', $filtered ) ); 
  223.  
  224. /** 
  225. * Filter a sanitized text field string. 
  226. * @since WP 2.9.0 
  227. * @param string $filtered The sanitized string. 
  228. * @param string $str The string prior to being sanitized. 
  229. */ 
  230.  
  231. return apply_filters( 'sanitize_text_field', $filtered, $value ); 
  232.  
  233. /** 
  234. * Sanitize a url for saving to the database 
  235. * Not to be confused with the old native WP function 
  236. * @todo [JRF => whomever] check/improve url verification 
  237. * @since 1.8.0 
  238. * @param string $value String URL value to sanitize. 
  239. * @param array $allowed_protocols Optional set of allowed protocols. 
  240. * @return string 
  241. */ 
  242. public static function sanitize_url( $value, $allowed_protocols = array( 'http', 'https' ) ) { 
  243. return esc_url_raw( sanitize_text_field( rawurldecode( $value ) ), $allowed_protocols ); 
  244.  
  245. /** 
  246. * Validate a value as boolean 
  247. * @static 
  248. * @since 1.8.0 
  249. * @param mixed $value Value to validate. 
  250. * @return bool 
  251. */ 
  252. public static function validate_bool( $value ) { 
  253. if ( ! isset( self::$has_filters ) ) { 
  254. self::$has_filters = extension_loaded( 'filter' ); 
  255.  
  256. if ( self::$has_filters ) { 
  257. return filter_var( $value, FILTER_VALIDATE_BOOLEAN ); 
  258. else { 
  259. return self::emulate_filter_bool( $value ); 
  260.  
  261. /** 
  262. * Cast a value to bool 
  263. * @static 
  264. * @since 1.8.0 
  265. * @param mixed $value Value to cast. 
  266. * @return bool 
  267. */ 
  268. public static function emulate_filter_bool( $value ) { 
  269. $true = array( 
  270. '1',  
  271. 'true',  
  272. 'True',  
  273. 'TRUE',  
  274. 'y',  
  275. 'Y',  
  276. 'yes',  
  277. 'Yes',  
  278. 'YES',  
  279. 'on',  
  280. 'On',  
  281. 'ON',  
  282.  
  283. ); 
  284. $false = array( 
  285. '0',  
  286. 'false',  
  287. 'False',  
  288. 'FALSE',  
  289. 'n',  
  290. 'N',  
  291. 'no',  
  292. 'No',  
  293. 'NO',  
  294. 'off',  
  295. 'Off',  
  296. 'OFF',  
  297. ); 
  298.  
  299. if ( is_bool( $value ) ) { 
  300. return $value; 
  301. else if ( is_int( $value ) && ( $value === 0 || $value === 1 ) ) { 
  302. return (bool) $value; 
  303. else if ( ( is_float( $value ) && ! is_nan( $value ) ) && ( $value === (float) 0 || $value === (float) 1 ) ) { 
  304. return (bool) $value; 
  305. else if ( is_string( $value ) ) { 
  306. $value = trim( $value ); 
  307. if ( in_array( $value, $true, true ) ) { 
  308. return true; 
  309. else if ( in_array( $value, $false, true ) ) { 
  310. return false; 
  311. else { 
  312. return false; 
  313.  
  314. return false; 
  315.  
  316. /** 
  317. * Validate a value as integer 
  318. * @static 
  319. * @since 1.8.0 
  320. * @param mixed $value Value to validate. 
  321. * @return int|bool int or false in case of failure to convert to int 
  322. */ 
  323. public static function validate_int( $value ) { 
  324. if ( ! isset( self::$has_filters ) ) { 
  325. self::$has_filters = extension_loaded( 'filter' ); 
  326.  
  327. if ( self::$has_filters ) { 
  328. return filter_var( $value, FILTER_VALIDATE_INT ); 
  329. else { 
  330. return self::emulate_filter_int( $value ); 
  331.  
  332. /** 
  333. * Cast a value to integer 
  334. * @static 
  335. * @since 1.8.0 
  336. * @param mixed $value Value to cast. 
  337. * @return int|bool 
  338. */ 
  339. public static function emulate_filter_int( $value ) { 
  340. if ( is_int( $value ) ) { 
  341. return $value; 
  342. else if ( is_float( $value ) ) { 
  343. if ( (int) $value == $value && ! is_nan( $value ) ) { 
  344. return (int) $value; 
  345. else { 
  346. return false; 
  347. else if ( is_string( $value ) ) { 
  348. $value = trim( $value ); 
  349. if ( $value === '' ) { 
  350. return false; 
  351. else if ( ctype_digit( $value ) ) { 
  352. return (int) $value; 
  353. else if ( strpos( $value, '-' ) === 0 && ctype_digit( substr( $value, 1 ) ) ) { 
  354. return (int) $value; 
  355. else { 
  356. return false; 
  357.  
  358. return false; 
  359.  
  360. /** 
  361. * Clears the WP or W3TC cache depending on which is used 
  362. * @static 
  363. * @since 1.8.0 
  364. */ 
  365. public static function clear_cache() { 
  366. if ( function_exists( 'w3tc_pgcache_flush' ) ) { 
  367. w3tc_pgcache_flush(); 
  368. elseif ( function_exists( 'wp_cache_clear_cache' ) ) { 
  369. wp_cache_clear_cache(); 
  370.  
  371. /** 
  372. * Flush W3TC cache after succesfull update/add of taxonomy meta option 
  373. * @static 
  374. * @since 1.8.0 
  375. */ 
  376. public static function flush_w3tc_cache() { 
  377. if ( defined( 'W3TC_DIR' ) && function_exists( 'w3tc_objectcache_flush' ) ) { 
  378. w3tc_objectcache_flush(); 
  379.  
  380. /** 
  381. * Clear rewrite rules 
  382. * @static 
  383. * @since 1.8.0 
  384. */ 
  385. public static function clear_rewrites() { 
  386. delete_option( 'rewrite_rules' ); 
  387.  
  388. /** 
  389. * Do simple reliable math calculations without the risk of wrong results 
  390. * @see http://floating-point-gui.de/ 
  391. * @see the big red warning on http://php.net/language.types.float.php 
  392. * In the rare case that the bcmath extension would not be loaded, it will return the normal calculation results 
  393. * @static 
  394. * @since 1.5.0 
  395. * @since 1.8.0 Moved from stand-alone function to this class. 
  396. * @param mixed $number1 Scalar (string/int/float/bool). 
  397. * @param string $action Calculation action to execute. Valid input: 
  398. * '+' or 'add' or 'addition',  
  399. * '-' or 'sub' or 'subtract',  
  400. * '*' or 'mul' or 'multiply',  
  401. * '/' or 'div' or 'divide',  
  402. * '%' or 'mod' or 'modulus' 
  403. * '=' or 'comp' or 'compare'. 
  404. * @param mixed $number2 Scalar (string/int/float/bool). 
  405. * @param bool $round Whether or not to round the result. Defaults to false. 
  406. * Will be disregarded for a compare operation. 
  407. * @param int $decimals Decimals for rounding operation. Defaults to 0. 
  408. * @param int $precision Calculation precision. Defaults to 10. 
  409. * @return mixed Calculation Result or false if either or the numbers isn't scalar or 
  410. * an invalid operation was passed 
  411. * - for compare the result will always be an integer 
  412. * - for all other operations, the result will either be an integer (preferred) 
  413. * or a float 
  414. */ 
  415. public static function calc( $number1, $action, $number2, $round = false, $decimals = 0, $precision = 10 ) { 
  416. static $bc; 
  417.  
  418. if ( ! is_scalar( $number1 ) || ! is_scalar( $number2 ) ) { 
  419. return false; 
  420.  
  421. if ( ! isset( $bc ) ) { 
  422. $bc = extension_loaded( 'bcmath' ); 
  423.  
  424. if ( $bc ) { 
  425. $number1 = number_format( $number1, 10, '.', '' ); 
  426. $number2 = number_format( $number2, 10, '.', '' ); 
  427.  
  428. $result = null; 
  429. $compare = false; 
  430.  
  431. switch ( $action ) { 
  432. case '+': 
  433. case 'add': 
  434. case 'addition': 
  435. $result = ( $bc ) ? bcadd( $number1, $number2, $precision ) /** string */ : ( $number1 + $number2 ); 
  436. break; 
  437.  
  438. case '-': 
  439. case 'sub': 
  440. case 'subtract': 
  441. $result = ( $bc ) ? bcsub( $number1, $number2, $precision ) /** string */ : ( $number1 - $number2 ); 
  442. break; 
  443.  
  444. case '*': 
  445. case 'mul': 
  446. case 'multiply': 
  447. $result = ( $bc ) ? bcmul( $number1, $number2, $precision ) /** string */ : ( $number1 * $number2 ); 
  448. break; 
  449.  
  450. case '/': 
  451. case 'div': 
  452. case 'divide': 
  453. if ( $bc ) { 
  454. $result = bcdiv( $number1, $number2, $precision ); // String, or NULL if right_operand is 0. 
  455. elseif ( $number2 != 0 ) { 
  456. $result = ( $number1 / $number2 ); 
  457.  
  458. if ( ! isset( $result ) ) { 
  459. $result = 0; 
  460. break; 
  461.  
  462. case '%': 
  463. case 'mod': 
  464. case 'modulus': 
  465. if ( $bc ) { 
  466. $result = bcmod( $number1, $number2 ); // String, or NULL if modulus is 0. 
  467. elseif ( $number2 != 0 ) { 
  468. $result = ( $number1 % $number2 ); 
  469.  
  470. if ( ! isset( $result ) ) { 
  471. $result = 0; 
  472. break; 
  473.  
  474. case '=': 
  475. case 'comp': 
  476. case 'compare': 
  477. $compare = true; 
  478. if ( $bc ) { 
  479. $result = bccomp( $number1, $number2, $precision ); // Returns int 0, 1 or -1. 
  480. else { 
  481. $result = ( $number1 == $number2 ) ? 0 : ( ( $number1 > $number2 ) ? 1 : - 1 ); 
  482. break; 
  483.  
  484. if ( isset( $result ) ) { 
  485. if ( $compare === false ) { 
  486. if ( $round === true ) { 
  487. $result = round( floatval( $result ), $decimals ); 
  488. if ( $decimals === 0 ) { 
  489. $result = (int) $result; 
  490. else { 
  491. $result = ( intval( $result ) == $result ) ? intval( $result ) : floatval( $result ); 
  492.  
  493. return $result; 
  494.  
  495. return false; 
  496.  
  497. /** 
  498. * Trim whitespace and NBSP (Non-breaking space) from string 
  499. * @since 2.0.0 
  500. * @param string $string String input to trim. 
  501. * @return string 
  502. */ 
  503. public static function trim_nbsp_from_string( $string ) { 
  504. $find = array( ' ', chr( 0xC2 ) . chr( 0xA0 ) ); 
  505. $string = str_replace( $find, ' ', $string ); 
  506. $string = trim( $string ); 
  507.  
  508. return $string; 
  509.  
  510. /** 
  511. * Check if a string is a valid datetime 
  512. * @since 2.0.0 
  513. * @param string $datetime String input to check as valid input for DateTime class. 
  514. * @return bool 
  515. */ 
  516. public static function is_valid_datetime( $datetime ) { 
  517.  
  518. if ( substr( $datetime, 0, 1 ) === '-' ) { 
  519. return false; 
  520.  
  521. try { 
  522. return new DateTime( $datetime ) !== false; 
  523. } catch ( Exception $exc ) { 
  524. return false; 
  525.  
  526. /** 
  527. * Format the URL to be sure it is okay for using as a redirect url. 
  528. * This method will parse the URL and combine them in one string. 
  529. * @since 2.3.0 
  530. * @param string $url URL string. 
  531. * @return mixed 
  532. */ 
  533. public static function format_url( $url ) { 
  534. $parsed_url = wp_parse_url( $url ); 
  535.  
  536. $formatted_url = ''; 
  537. if ( ! empty( $parsed_url['path'] ) ) { 
  538. $formatted_url = $parsed_url['path']; 
  539.  
  540. // Prepend a slash if first char != slash. 
  541. if ( stripos( $formatted_url, '/' ) !== 0 ) { 
  542. $formatted_url = '/' . $formatted_url; 
  543.  
  544. // Append 'query' string if it exists. 
  545. if ( isset( $parsed_url['query'] ) && '' != $parsed_url['query'] ) { 
  546. $formatted_url .= '?' . $parsed_url['query']; 
  547.  
  548. return apply_filters( 'wpseo_format_admin_url', $formatted_url ); 
  549.  
  550.  
  551. /** 
  552. * Get plugin name from file 
  553. * @since 2.3.3 
  554. * @param string $plugin Plugin path relative to plugins directory. 
  555. * @return string|bool 
  556. */ 
  557. public static function get_plugin_name( $plugin ) { 
  558. $plugin_details = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin ); 
  559.  
  560. if ( $plugin_details['Name'] != '' ) { 
  561. return $plugin_details['Name']; 
  562.  
  563. return false; 
  564.  
  565. /** 
  566. * Retrieves the sitename. 
  567. * @since 3.0.0 
  568. * @return string 
  569. */ 
  570. public static function get_site_name() { 
  571. return trim( strip_tags( get_bloginfo( 'name' ) ) ); 
  572.  
  573. /** 
  574. * Retrieves the title separator. 
  575. * @since 3.0.0 
  576. * @return string 
  577. */ 
  578. public static function get_title_separator() { 
  579. $replacement = WPSEO_Options::get_default( 'wpseo_titles', 'separator' ); 
  580.  
  581. // Get the titles option and the separator options. 
  582. $titles_options = WPSEO_Options::get_option( 'wpseo_titles' ); 
  583. $seperator_options = WPSEO_Option_Titles::get_instance()->get_separator_options(); 
  584.  
  585. // This should always be set, but just to be sure. 
  586. if ( isset( $seperator_options[ $titles_options['separator'] ] ) ) { 
  587. // Set the new replacement. 
  588. $replacement = $seperator_options[ $titles_options['separator'] ]; 
  589.  
  590. /** 
  591. * Filter: 'wpseo_replacements_filter_sep' - Allow customization of the separator character(s) 
  592. * @api string $replacement The current separator 
  593. */ 
  594. return apply_filters( 'wpseo_replacements_filter_sep', $replacement ); 
  595.  
  596. /** 
  597. * Check if the current opened page is a Yoast SEO page. 
  598. * @since 3.0.0 
  599. * @return bool 
  600. */ 
  601. public static function is_yoast_seo_page() { 
  602. static $is_yoast_seo; 
  603.  
  604. if ( $is_yoast_seo === null ) { 
  605. $current_page = filter_input( INPUT_GET, 'page' ); 
  606. $is_yoast_seo = ( substr( $current_page, 0, 6 ) === 'wpseo_' ); 
  607.  
  608. return $is_yoast_seo; 
  609.  
  610. /** 
  611. * Check if the current opened page belongs to Yoast SEO Free. 
  612. * @since 3.3.0 
  613. * @param string $current_page the current page the user is on. 
  614. * @return bool 
  615. */ 
  616. public static function is_yoast_seo_free_page( $current_page ) { 
  617. $yoast_seo_free_pages = array( 
  618. 'wpseo_dashboard',  
  619. 'wpseo_titles',  
  620. 'wpseo_social',  
  621. 'wpseo_xml',  
  622. 'wpseo_advanced',  
  623. 'wpseo_tools',  
  624. 'wpseo_search_console',  
  625. 'wpseo_licenses',  
  626. ); 
  627.  
  628. return in_array( $current_page, $yoast_seo_free_pages ); 
  629.  
  630. /** 
  631. * Determine if Yoast SEO is in development mode? 
  632. * Inspired by JetPack (https://github.com/Automattic/jetpack/blob/master/class.jetpack.php#L1383-L1406). 
  633. * @since 3.0.0 
  634. * @return bool 
  635. */ 
  636. public static function is_development_mode() { 
  637. $development_mode = false; 
  638.  
  639. if ( defined( 'WPSEO_DEBUG' ) ) { 
  640. $development_mode = WPSEO_DEBUG; 
  641. elseif ( site_url() && false === strpos( site_url(), '.' ) ) { 
  642. $development_mode = true; 
  643.  
  644. /** 
  645. * Filter the Yoast SEO development mode. 
  646. * @since 3.0 
  647. * @param bool $development_mode Is Yoast SEOs development mode active. 
  648. */ 
  649.  
  650. return apply_filters( 'yoast_seo_development_mode', $development_mode ); 
  651.  
  652. /** 
  653. * Retrieve home URL with proper trailing slash. 
  654. * @since 3.3.0 
  655. * @param string $path Path relative to home URL. 
  656. * @param string|null $scheme Scheme to apply. 
  657. * @return string Home URL with optional path, appropriately slashed if not. 
  658. */ 
  659. public static function home_url( $path = '', $scheme = null ) { 
  660.  
  661. $home_url = home_url( $path, $scheme ); 
  662.  
  663. if ( ! empty( $path ) ) { 
  664. return $home_url; 
  665.  
  666. $home_path = parse_url( $home_url, PHP_URL_PATH ); 
  667.  
  668. if ( '/' === $home_path ) { // Home at site root, already slashed. 
  669. return $home_url; 
  670.  
  671. if ( is_null( $home_path ) ) { // Home at site root, always slash. 
  672. return trailingslashit( $home_url ); 
  673.  
  674. if ( is_string( $home_path ) ) { // Home in subdirectory, slash if permalink structure has slash. 
  675. return user_trailingslashit( $home_url ); 
  676.  
  677. return $home_url; 
  678.  
  679. /** 
  680. * Returns a base64 URL for the svg for use in the menu 
  681. * @since 3.3.0 
  682. * @param bool $base64 Whether or not to return base64'd output. 
  683. * @return string 
  684. */ 
  685. public static function get_icon_svg( $base64 = true ) { 
  686. $svg = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="100%" height="100%" style="fill:#82878c" viewBox="0 0 512 512"><g><g><g><g><path d="M203.6, 395c6.8-17.4, 6.8-36.6, 0-54l-79.4-204h70.9l47.7, 149.4l74.8-207.6H116.4c-41.8, 0-76, 34.2-76, 76V357c0, 41.8, 34.2, 76, 76, 76H173C189, 424.1, 197.6, 410.3, 203.6, 395z"/></g><g><path d="M471.6, 154.8c0-41.8-34.2-76-76-76h-3L285.7, 365c-9.6, 26.7-19.4, 49.3-30.3, 68h216.2V154.8z"/></g></g><path stroke-width="2.974" stroke-miterlimit="10" d="M338, 1.3l-93.3, 259.1l-42.1-131.9h-89.1l83.8, 215.2c6, 15.5, 6, 32.5, 0, 48c-7.4, 19-19, 37.3-53, 41.9l-7.2, 1v76h8.3c81.7, 0, 118.9-57.2, 149.6-142.9L431.6, 1.3H338z M279.4, 362c-32.9, 92-67.6, 128.7-125.7, 131.8v-45c37.5-7.5, 51.3-31, 59.1-51.1c7.5-19.3, 7.5-40.7, 0-60l-75-192.7h52.8l53.3, 166.8l105.9-294h58.1L279.4, 362z"/></g></g></svg>'; 
  687.  
  688. if ( $base64 ) { 
  689. return 'data:image/svg+xml;base64, ' . base64_encode( $svg ); 
  690.  
  691. return $svg; 
  692.  
  693. /** 
  694. * Returns the language part of a given locale, defaults to english when the $locale is empty 
  695. * @since 3.4 
  696. * @param string $locale The locale to get the language of. 
  697. * @returns string The language part of the locale. 
  698. */ 
  699. public static function get_language( $locale ) { 
  700. $language = 'en'; 
  701.  
  702. if ( ! empty( $locale ) && strlen( $locale ) >= 2 ) { 
  703. $language = substr( $locale, 0, 2 ); 
  704.  
  705. return $language; 
  706.  
  707. /** 
  708. * Returns the user locale for the language to be used in the admin. 
  709. * WordPress 4.7 introduced the ability for users to specify an Admin language 
  710. * different from the language used on the front end. This checks if the feature 
  711. * is available and returns the user's language, with a fallback to the site's language. 
  712. * Can be removed when support for WordPress 4.6 will be dropped, in favor 
  713. * of WordPress get_user_locale() that already fallbacks to the site*s locale. 
  714. * @since 4.1 
  715. * @returns string The locale. 
  716. */ 
  717. public static function get_user_locale() { 
  718. if ( function_exists( 'get_user_locale' ) ) { 
  719. return get_user_locale(); 
  720.  
  721. return get_locale(); 
  722.  
  723. /** 
  724. * Checks if the WP-REST-API is available. 
  725. * @since 3.6 
  726. * @since 3.7 Introduced the $minimum_version parameter. 
  727. * @param string $minimum_version The minimum version the API should be. 
  728. * @return bool Returns true if the API is available. 
  729. */ 
  730. public static function is_api_available( $minimum_version = '2.0' ) { 
  731. return ( defined( 'REST_API_VERSION' ) 
  732. && version_compare( REST_API_VERSION, $minimum_version, '>=' ) ); 
  733.  
  734. /********************** DEPRECATED METHODS **********************/ 
  735.  
  736. // @codeCoverageIgnoreStart 
  737. /** 
  738. * Wrapper for the PHP filter input function. 
  739. * This is used because stupidly enough, the `filter_input` function is not available on all hosts... 
  740. * @since 1.8.0 
  741. * @deprecated 3.0 
  742. * @deprecated Passes through to PHP call, no longer used in code. 
  743. * @param int $type Input type constant. 
  744. * @param string $variable_name Variable name to get. 
  745. * @param int $filter Filter to apply. 
  746. * @return mixed 
  747. */ 
  748. public static function filter_input( $type, $variable_name, $filter = FILTER_DEFAULT ) { 
  749. _deprecated_function( __METHOD__, 'WPSEO 3.0', 'PHP native filter_input()' ); 
  750.  
  751. return filter_input( $type, $variable_name, $filter ); 
  752.  
  753. /** 
  754. * Adds a hook that when given option is updated, the XML sitemap transient cache is cleared 
  755. * @since 2.2.0 
  756. * @deprecated 3.2 
  757. * @see WPSEO_Sitemaps_Cache::register_clear_on_option_update() 
  758. * @param string $option Option name. 
  759. * @param string $type Sitemap type. 
  760. */ 
  761. public static function register_cache_clear_option( $option, $type = '' ) { 
  762. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Sitemaps_Cache::register_clear_on_option_update()' ); 
  763. WPSEO_Sitemaps_Cache::register_clear_on_option_update( $option, $type ); 
  764.  
  765. /** 
  766. * Clears the transient cache when a given option is updated, if that option has been registered before 
  767. * @since 2.2.0 
  768. * @deprecated 3.2 
  769. * @see WPSEO_Sitemaps_Cache::clear_on_option_update() 
  770. * @param string $option The option that's being updated. 
  771. */ 
  772. public static function clear_transient_cache( $option ) { 
  773. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Sitemaps_Cache::clear_on_option_update()' ); 
  774. WPSEO_Sitemaps_Cache::clear_on_option_update( $option ); 
  775.  
  776. /** 
  777. * Clear entire XML sitemap cache 
  778. * @since 1.8.0 
  779. * @deprecated 3.2 
  780. * @see WPSEO_Sitemaps_Cache::clear() 
  781. * @param array $types Set of sitemap types to invalidate cache for. 
  782. */ 
  783. public static function clear_sitemap_cache( $types = array() ) { 
  784. _deprecated_function( __METHOD__, 'WPSEO 3.2', 'WPSEO_Sitemaps_Cache::clear()' ); 
  785. WPSEO_Sitemaps_Cache::clear( $types ); 
  786.  
  787. /** 
  788. * Wrapper for encoding the array as a json string. Includes a fallback if wp_json_encode doesn't exist. 
  789. * @since 3.0.0 
  790. * @deprecated 3.3 Core versions without wp_json_encode() no longer supported, fallback unnecessary. 
  791. * @param array $array_to_encode The array which will be encoded. 
  792. * @param int $options Optional. Array with options which will be passed in to the encoding methods. 
  793. * @param int $depth Optional. Maximum depth to walk through $data. Must be greater than 0. Default 512. 
  794. * @return false|string 
  795. */ 
  796. public static function json_encode( array $array_to_encode, $options = 0, $depth = 512 ) { 
  797. _deprecated_function( __METHOD__, 'WPSEO 3.3', 'wp_json_encode()' ); 
  798.  
  799. return wp_json_encode( $array_to_encode, $options, $depth ); 
  800. // @codeCoverageIgnoreEnd