| @@ -6,8 +6,10 @@ | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | namespace WebberZone\Top_Ten\Util; |
| 9 | 9 | |
| 10 | +use Jaybizzle\CrawlerDetect\CrawlerDetect; | |
| 11 | + | |
| 10 | 12 | if ( ! defined( 'WPINC' ) ) { |
| 11 | 13 | die; |
| 12 | 14 | } |
| 13 | 15 | |
| @@ -89,18 +91,24 @@ | ||
| 89 | 91 | /** |
| 90 | 92 | * Convert float number to format based on the locale if number_format_count is true. |
| 91 | 93 | * |
| 92 | 94 | * @since 2.6.0 |
| 95 | + * @since 4.4.0 Added the `$style` parameter. | |
| 93 | 96 | * |
| 94 | - * @param float $number The number to convert based on locale. | |
| 95 | - * @param int $decimals Optional. Precision of the number of decimal places. Default 0. | |
| 97 | + * @param float $number The number to convert based on locale. | |
| 98 | + * @param int $decimals Optional. Precision of the number of decimal places. Default 0. | |
| 99 | + * @param string|null $style Optional. 'full' or 'abbreviated'. Default null, which uses the | |
| 100 | + * `number_format_style` setting. | |
| 96 | 101 | * @return string Converted number in string format. |
| 97 | 102 | */ |
| 98 | - public static function number_format_i18n( $number, $decimals = 0 ) { | |
| 103 | + public static function number_format_i18n( $number, $decimals = 0, $style = null ) { | |
| 99 | 104 | |
| 100 | 105 | $formatted = (float) $number; |
| 106 | + $style = $style ? $style : \tptn_get_option( 'number_format_style', 'full' ); | |
| 101 | 107 | |
| 102 | - if ( \tptn_get_option( 'number_format_count' ) ) { | |
| 108 | + if ( 'abbreviated' === $style ) { | |
| 109 | + $formatted = self::abbreviate_number( $formatted ); | |
| 110 | + } elseif ( \tptn_get_option( 'number_format_count' ) ) { | |
| 103 | 111 | $formatted = number_format_i18n( (float) $formatted ); |
| 104 | 112 | } |
| 105 | 113 | |
| 106 | 114 | /** |
| @@ -115,8 +123,75 @@ | ||
| 115 | 123 | return apply_filters( 'number_format_i18n', $formatted, $number, $decimals ); |
| 116 | 124 | } |
| 117 | 125 | |
| 118 | 126 | /** |
| 127 | + * Abbreviate a number, e.g. 1200 becomes 1.2k and 3400000 becomes 3.4M. | |
| 128 | + * | |
| 129 | + * The decimal separator is locale-aware via number_format_i18n(). | |
| 130 | + * | |
| 131 | + * @since 4.4.0 | |
| 132 | + * | |
| 133 | + * @param float|int $number The number to abbreviate. | |
| 134 | + * @param int $decimals Optional. Maximum number of decimal places. Default 1. | |
| 135 | + * @return string Abbreviated number, e.g. 1.2k, 3.4M. Numbers below the lowest | |
| 136 | + * threshold are returned locale-formatted without a suffix. | |
| 137 | + */ | |
| 138 | + public static function abbreviate_number( $number, $decimals = 1 ) { | |
| 139 | + $number = (float) $number; | |
| 140 | + $decimals = absint( $decimals ); | |
| 141 | + | |
| 142 | + /** | |
| 143 | + * Filters the abbreviation thresholds and suffixes. | |
| 144 | + * | |
| 145 | + * @since 4.4.0 | |
| 146 | + * | |
| 147 | + * @param array $abbreviations Array of divisor => suffix pairs, checked in descending order of divisor. | |
| 148 | + * @param float $number The number being abbreviated. | |
| 149 | + */ | |
| 150 | + $abbreviations = apply_filters( | |
| 151 | + 'tptn_number_format_abbreviations', | |
| 152 | + array( | |
| 153 | + 1000000000 => 'B', | |
| 154 | + 1000000 => 'M', | |
| 155 | + 1000 => 'k', | |
| 156 | + ), | |
| 157 | + $number | |
| 158 | + ); | |
| 159 | + krsort( $abbreviations, SORT_NUMERIC ); | |
| 160 | + | |
| 161 | + /** | |
| 162 | + * Filters the number of decimal places used when abbreviating a number. | |
| 163 | + * | |
| 164 | + * @since 4.4.0 | |
| 165 | + * | |
| 166 | + * @param int $decimals Maximum number of decimal places. | |
| 167 | + * @param float $number The number being abbreviated. | |
| 168 | + */ | |
| 169 | + $decimals = absint( apply_filters( 'tptn_abbreviate_number_decimals', $decimals, $number ) ); | |
| 170 | + | |
| 171 | + $divisors = array_keys( $abbreviations ); | |
| 172 | + | |
| 173 | + foreach ( $divisors as $i => $divisor ) { | |
| 174 | + if ( abs( $number ) >= $divisor ) { | |
| 175 | + $value = round( $number / $divisor, $decimals ); | |
| 176 | + | |
| 177 | + // Rounding can push the value into the next tier, e.g. 999950 => 1000k. Bump it to 1M instead. | |
| 178 | + if ( $i > 0 && abs( $value ) * $divisor >= $divisors[ $i - 1 ] ) { | |
| 179 | + $divisor = $divisors[ $i - 1 ]; | |
| 180 | + $value = round( $number / $divisor, $decimals ); | |
| 181 | + } | |
| 182 | + | |
| 183 | + $suffix = $abbreviations[ $divisor ]; | |
| 184 | + $precision = ( floor( $value ) === $value ) ? 0 : $decimals; | |
| 185 | + | |
| 186 | + return number_format_i18n( $value, $precision ) . $suffix; | |
| 187 | + } | |
| 188 | + } | |
| 189 | + | |
| 190 | + return number_format_i18n( $number ); | |
| 191 | + } | |
| 192 | + | |
| 193 | + /** | |
| 119 | 194 | * Convert a string to CSV. |
| 120 | 195 | * |
| 121 | 196 | * @since 2.9.0 |
| 122 | 197 | * |
| @@ -326,10 +401,15 @@ | ||
| 326 | 401 | |
| 327 | 402 | /** |
| 328 | 403 | * Check if the user agent matches known bots. |
| 329 | 404 | * |
| 405 | + * Uses the jaybizzle/crawler-detect library for the primary check, and falls back to | |
| 406 | + * a filterable list of patterns for bots that library doesn't recognise (or if the | |
| 407 | + * library isn't available at all). | |
| 408 | + * | |
| 330 | 409 | * @since 3.3.0 |
| 331 | - * @link https://github.com/janusman/robot-user-agents | |
| 410 | + * @since 4.4.0 Switched to jaybizzle/crawler-detect for the primary detection. | |
| 411 | + * @link https://github.com/JayBizzle/Crawler-Detect | |
| 332 | 412 | * |
| 333 | 413 | * @return bool True if the user agent matches a known bot pattern, false otherwise. |
| 334 | 414 | */ |
| 335 | 415 | public static function is_bot() { |
| @@ -336,11 +416,48 @@ | ||
| 336 | 416 | if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) { |
| 337 | 417 | return false; |
| 338 | 418 | } |
| 339 | 419 | |
| 420 | + if ( class_exists( CrawlerDetect::class ) ) { | |
| 421 | + $crawler_detect = new CrawlerDetect(); | |
| 422 | + | |
| 423 | + if ( $crawler_detect->isCrawler() ) { | |
| 424 | + return true; | |
| 425 | + } | |
| 426 | + } | |
| 427 | + | |
| 340 | 428 | $user_agent = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ); |
| 341 | 429 | |
| 342 | - $bot_user_agents = array( | |
| 430 | + /** | |
| 431 | + * Filter the list of known bot user agent patterns to check against. | |
| 432 | + * | |
| 433 | + * Defaults to a bundled list, used as a fallback alongside (or instead of, if the | |
| 434 | + * jaybizzle/crawler-detect library failed to load) the library's own detection. | |
| 435 | + * | |
| 436 | + * @since 3.3.0 | |
| 437 | + * | |
| 438 | + * @param array $bot_user_agents List of bot user agent patterns. | |
| 439 | + */ | |
| 440 | + $bot_user_agents = apply_filters( 'tptn_bots', self::get_default_bot_user_agents() ); | |
| 441 | + | |
| 442 | + foreach ( $bot_user_agents as $bot_user_agent ) { | |
| 443 | + if ( preg_match( '/' . preg_quote( strtolower( $bot_user_agent ), '/' ) . '/i', strtolower( $user_agent ) ) ) { | |
| 444 | + return true; | |
| 445 | + } | |
| 446 | + } | |
| 447 | + | |
| 448 | + return false; | |
| 449 | + } | |
| 450 | + | |
| 451 | + /** | |
| 452 | + * Default list of bot user agent patterns, used as a fallback for is_bot(). | |
| 453 | + * | |
| 454 | + * @since 4.4.0 | |
| 455 | + * | |
| 456 | + * @return array List of bot user agent patterns. | |
| 457 | + */ | |
| 458 | + protected static function get_default_bot_user_agents() { | |
| 459 | + return array( | |
| 343 | 460 | '11A465', |
| 344 | 461 | 'AddThis.com', |
| 345 | 462 | 'AdsBot-Google', |
| 346 | 463 | 'Ahrefs', |
| @@ -518,25 +635,8 @@ | ||
| 518 | 635 | 'Zabbix', |
| 519 | 636 | 'ZoominfoBot', |
| 520 | 637 | 'ZoomSpider', |
| 521 | 638 | ); |
| 522 | - | |
| 523 | - /** | |
| 524 | - * Filter the list of known bots. | |
| 525 | - * | |
| 526 | - * @since 3.3.0 | |
| 527 | - * | |
| 528 | - * @param array $bot_user_agents List of known bots. | |
| 529 | - */ | |
| 530 | - $bot_user_agent = apply_filters( 'tptn_bots', $bot_user_agents ); | |
| 531 | - | |
| 532 | - foreach ( $bot_user_agents as $bot_user_agent ) { | |
| 533 | - if ( preg_match( '/' . preg_quote( strtolower( $bot_user_agent ), '/' ) . '/i', strtolower( $user_agent ) ) ) { | |
| 534 | - return true; | |
| 535 | - } | |
| 536 | - } | |
| 537 | - | |
| 538 | - return false; | |
| 539 | 639 | } |
| 540 | 640 | |
| 541 | 641 | /** |
| 542 | 642 | * Get all terms of a post. |