PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.1
WebberZone Top 10 — Popular Posts v4.5.1
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / util / class-helpers.php

class-helpers.php in WebberZone Top 10 — Popular Posts 4.5.1, at includes/util/class-helpers.php

701 lines 17.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Helpers class.
4 *
5 * @package WebberZone\Top_Ten\Util
6 */
7
8 namespace WebberZone\Top_Ten\Util;
9
10 use Jaybizzle\CrawlerDetect\CrawlerDetect;
11
12 if ( ! defined( 'WPINC' ) ) {
13 die;
14 }
15
16 /**
17 * Helpers class.
18 *
19 * @since 3.3.0
20 */
21 class Helpers {
22
23 /**
24 * Constructor class.
25 *
26 * @since 3.3.0
27 */
28 public function __construct() {
29 }
30
31 /**
32 * Retrieve the from date for the query
33 *
34 * @since 2.6.0
35 *
36 * @param string $time A date/time string.
37 * @param int $daily_range Daily range.
38 * @param int $hour_range Hour range.
39 * @return string From date
40 */
41 public static function get_from_date( $time = null, $daily_range = null, $hour_range = null ) {
42
43 $current_time = isset( $time ) ? strtotime( $time ) : strtotime( current_time( 'mysql' ) );
44 $daily_range = isset( $daily_range ) ? absint( $daily_range ) : (int) \tptn_get_option( 'daily_range' );
45 $hour_range = isset( $hour_range ) ? absint( $hour_range ) : (int) \tptn_get_option( 'hour_range' );
46
47 if ( \tptn_get_option( 'daily_midnight' ) ) {
48 $from_date = $current_time - ( max( 0, ( $daily_range - 1 ) ) * DAY_IN_SECONDS );
49 $from_date = gmdate( 'Y-m-d 0:0:0', $from_date );
50 } else {
51 $from_date = $current_time - ( $daily_range * DAY_IN_SECONDS + $hour_range * HOUR_IN_SECONDS );
52 $from_date = gmdate( 'Y-m-d H:0:0', $from_date );
53 }
54
55 /**
56 * Retrieve the from date for the query
57 *
58 * @since 2.6.0
59 *
60 * @param string $from_date From date.
61 * @param string $time A date/time string.
62 * @param int $daily_range Daily range.
63 * @param int $hour_range Hour range.
64 */
65 return apply_filters( 'tptn_get_from_date', $from_date, $time, $daily_range, $hour_range );
66 }
67
68 /**
69 * Get a human-readable label for a custom period range.
70 *
71 * @since 4.3.2
72 *
73 * @param int|null $daily_range Number of days. Defaults to the 'daily_range' option.
74 * @return string 'Daily' when the range is 1 day, else 'Custom (N days)'.
75 */
76 public static function get_daily_range_label( $daily_range = null ) {
77 $daily_range = isset( $daily_range ) ? absint( $daily_range ) : (int) \tptn_get_option( 'daily_range', 1 );
78
79 if ( 1 === $daily_range ) {
80 return __( 'Daily', 'top-10' );
81 }
82
83 return sprintf(
84 /* translators: %d: Number of days. */
85 __( 'Custom (%d days)', 'top-10' ),
86 $daily_range
87 );
88 }
89
90
91 /**
92 * Convert float number to format based on the locale if number_format_count is true.
93 *
94 * @since 2.6.0
95 * @since 4.4.0 Added the `$style` parameter.
96 *
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.
101 * @return string Converted number in string format.
102 */
103 public static function number_format_i18n( $number, $decimals = 0, $style = null ) {
104
105 $formatted = (float) $number;
106 $style = $style ? $style : \tptn_get_option( 'number_format_style', 'full' );
107
108 if ( 'abbreviated' === $style ) {
109 $formatted = self::abbreviate_number( $formatted );
110 } elseif ( \tptn_get_option( 'number_format_count' ) ) {
111 $formatted = number_format_i18n( (float) $formatted );
112 }
113
114 /**
115 * Filters the number formatted based on the locale.
116 *
117 * @since 2.6.0
118 *
119 * @param string $formatted Converted number in string format.
120 * @param float $number The number to convert based on locale.
121 * @param int $decimals Precision of the number of decimal places.
122 */
123 return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
124 }
125
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 /**
194 * Convert a string to CSV.
195 *
196 * @since 2.9.0
197 *
198 * @param array $input Input string.
199 * @param string $delimiter Delimiter.
200 * @param string $enclosure Enclosure.
201 * @param string $terminator Terminating string.
202 * @return string CSV string.
203 */
204 public static function str_putcsv( $input, $delimiter = ',', $enclosure = '"', $terminator = "\n" ) {
205 // First convert associative array to numeric indexed array.
206 $work_array = array();
207 foreach ( $input as $key => $value ) {
208 $work_array[] = $value;
209 }
210
211 $string = '';
212 $input_size = count( $work_array );
213
214 for ( $i = 0; $i < $input_size; $i++ ) {
215 // Nested array, process nest item.
216 if ( is_array( $work_array[ $i ] ) ) {
217 $string .= self::str_putcsv( $work_array[ $i ], $delimiter, $enclosure, $terminator );
218 } else {
219 switch ( gettype( $work_array[ $i ] ) ) {
220 case 'NULL':
221 $formatted = '';
222 break;
223 case 'boolean':
224 $formatted = ( true === $work_array[ $i ] ) ? 'true' : 'false';
225 break;
226 case 'integer':
227 $formatted = (string) (int) $work_array[ $i ];
228 break;
229 case 'double':
230 $formatted = number_format( (float) $work_array[ $i ], 2, '.', '' );
231 break;
232 case 'string':
233 $formatted = str_replace( $enclosure, $enclosure . $enclosure, (string) $work_array[ $i ] );
234 break;
235 default:
236 $formatted = '';
237 break;
238 }
239 $string .= $enclosure . $formatted . $enclosure;
240 $string .= ( $i < ( $input_size - 1 ) ) ? $delimiter : $terminator;
241 }
242 }
243
244 return $string;
245 }
246
247 /**
248 * Truncate a string to a certain length.
249 *
250 * @since 2.5.4
251 *
252 * @param string $input String to truncate.
253 * @param int $count Maximum number of characters to take.
254 * @param string $more What to append if $input needs to be trimmed.
255 * @param bool $break_words Optionally choose to break words.
256 * @return string Truncated string.
257 */
258 public static function trim_char( $input, $count = 60, $more = '&hellip;', $break_words = false ) {
259 $input = wp_strip_all_tags( $input, true );
260 if ( 0 === $count ) {
261 return '';
262 }
263 if ( mb_strlen( $input ) > $count && $count > 0 ) {
264 $count -= min( $count, mb_strlen( $more ) );
265 if ( ! $break_words ) {
266 $input = preg_replace( '/\s+?(\S+)?$/u', '', mb_substr( $input, 0, $count + 1 ) );
267 }
268 $input = mb_substr( $input, 0, $count ) . $more;
269 }
270 /**
271 * Filters truncated string.
272 *
273 * @since 2.4.0
274 *
275 * @param string $input String to truncate.
276 * @param int $count Maximum number of characters to take.
277 * @param string $more What to append if $input needs to be trimmed.
278 * @param bool $break_words Optionally choose to break words.
279 */
280 return apply_filters( 'tptn_trim_char', $input, $count, $more, $break_words );
281 }
282
283 /**
284 * Get the WP_Query arguments.
285 *
286 * @return array WP_Query arguments.
287 */
288 public static function get_wp_query_arguments() {
289 $arguments = array(
290 // Author Parameters.
291 'author' => '',
292 'author_name' => '',
293 'author__in' => array(),
294 'author__not_in' => array(),
295
296 // Category Parameters.
297 'cat' => '',
298 'category_name' => '',
299 'category__and' => array(),
300 'category__in' => array(),
301 'category__not_in' => array(),
302
303 // Tag Parameters.
304 'tag' => '',
305 'tag_id' => '',
306 'tag__and' => array(),
307 'tag__in' => array(),
308 'tag__not_in' => array(),
309 'tag_slug__and' => array(),
310 'tag_slug__in' => array(),
311
312 // Search Parameters.
313 'search_columns' => array(),
314 'exact' => false,
315 'sentence' => false,
316
317 // Post & Page Parameters.
318 'p' => '',
319 'name' => '',
320 'page_id' => '',
321 'pagename' => '',
322 'post__in' => array(),
323 'post__not_in' => array(),
324 'post_parent' => '',
325 'post_parent__in' => array(),
326 'post_parent__not_in' => array(),
327 'post_name__in' => array(),
328
329 // Password Parameters.
330 'has_password' => false,
331 'post_password' => null,
332
333 // Post Type Parameters.
334 'post_type' => '',
335
336 // Status Parameters.
337 'post_status' => '',
338
339 // Comment Parameters.
340 'comment_count' => '',
341
342 // Pagination Parameters.
343 'posts_per_page' => '',
344
345 // Order & Orderby Parameters.
346 'orderby' => '',
347 'order' => '',
348
349 // Date Parameters.
350 'year' => '',
351 'monthnum' => '',
352 'day' => '',
353 'hour' => '',
354 'minute' => '',
355 'second' => '',
356
357 // Custom Field (post meta) Parameters.
358 'meta_key' => '', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
359 'meta_value' => '', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
360 'meta_value_num' => '',
361 'meta_compare' => '',
362 );
363
364 return $arguments;
365 }
366
367 /**
368 * Parse WP_Query variables to parse comma separated list of IDs and convert them to arrays as needed by WP_Query.
369 *
370 * @param array $query_vars Defined query variables.
371 * @return array Complete query variables with undefined ones filled in empty.
372 */
373 public static function parse_wp_query_arguments( $query_vars ) {
374
375 $array_keys = array(
376 'category__in',
377 'category__not_in',
378 'category__and',
379 'post__in',
380 'post__not_in',
381 'post_name__in',
382 'tag__in',
383 'tag__not_in',
384 'tag__and',
385 'tag_slug__in',
386 'tag_slug__and',
387 'post_parent__in',
388 'post_parent__not_in',
389 'author__in',
390 'author__not_in',
391 );
392
393 foreach ( $array_keys as $key ) {
394 if ( isset( $query_vars[ $key ] ) ) {
395 $query_vars[ $key ] = wp_parse_list( $query_vars[ $key ] );
396 }
397 }
398
399 return $query_vars;
400 }
401
402 /**
403 * Check if the user agent matches known bots.
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 *
409 * @since 3.3.0
410 * @since 4.4.0 Switched to jaybizzle/crawler-detect for the primary detection.
411 * @link https://github.com/JayBizzle/Crawler-Detect
412 *
413 * @return bool True if the user agent matches a known bot pattern, false otherwise.
414 */
415 public static function is_bot() {
416 if ( ! isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
417 return false;
418 }
419
420 if ( class_exists( CrawlerDetect::class ) ) {
421 $crawler_detect = new CrawlerDetect();
422
423 if ( $crawler_detect->isCrawler() ) {
424 return true;
425 }
426 }
427
428 $user_agent = sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) );
429
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(
460 '11A465',
461 'AddThis.com',
462 'AdsBot-Google',
463 'Ahrefs',
464 'alexa site audit',
465 'AlipesNewsBot',
466 'Amazonbot',
467 'Amazon-Route53-Health-Check-Service',
468 'ApacheBench',
469 'AppDynamics',
470 'Applebot',
471 'ArchiveBot',
472 'Archive-It',
473 'AspiegelBot',
474 'Assetnote',
475 'axios',
476 'azure-logic-apps',
477 'Baiduspider',
478 'Barkrowler',
479 'bingbot',
480 'BLEXBot',
481 'BLP_bbot',
482 'BluechipBacklinks',
483 'Buck',
484 'Bytespider',
485 'CCBot',
486 'check_http',
487 'CloudFlare-Prefetch',
488 'cludo.com bot',
489 'colly',
490 'contentkingapp',
491 'Cookiebot',
492 'CopperEgg',
493 'crawler4j',
494 'Csnibot',
495 'Curebot',
496 'curl',
497 'CyotekWebCopy',
498 'Daum',
499 'Datadog Agent',
500 'DataForSeoBot',
501 'Detectify',
502 'DotBot',
503 'Dow Jones Searchbot',
504 'DuckDuckBot',
505 'facebookexternalhit',
506 'Faraday',
507 'FeedBurner',
508 'FeedFetcher-Google',
509 'feedonomics',
510 'Fess',
511 'Funnelback',
512 'Fuzz Faster U Fool',
513 'GAChecker',
514 'Ghost Inspector',
515 'Grapeshot',
516 'gobuster',
517 'gocolly',
518 'Googlebot',
519 'GoogleStackdriverMonitoring',
520 'Go-http-client',
521 'go-resty',
522 'GuzzleHttp',
523 'HeadlessChrome',
524 'heritrix',
525 'hokifyBot',
526 'Honolulu-bot',
527 'HTTrack',
528 'HubSpot Crawler',
529 'ICC-Crawler',
530 'Imperva',
531 'IonCrawl',
532 'jooble',
533 'KauaiBot',
534 'Kinza',
535 'LieBaoFast',
536 'linabot',
537 'Linespider',
538 'Linguee',
539 'LinkChecker',
540 'LinkedInBot',
541 'LinkUpBot',
542 'LinuxGetUrl',
543 'LMY47V',
544 'MacOutlook',
545 'Magnet.me',
546 'Magus Bot',
547 'Mail.RU_Bot',
548 'MauiBot',
549 'Mb2345Browser',
550 'MegaIndex',
551 'Microsoft Office',
552 'Microsoft Outlook',
553 'Microsoft Word',
554 'MicroMessenger',
555 'mindbreeze-crawler',
556 'mirrorweb.com',
557 'MJ12bot',
558 'monitoring-plugins',
559 'Monsidobot',
560 'MQQBrowser',
561 'msnbot',
562 'MSOffice',
563 'MTRobot',
564 'nagios-plugins',
565 'nettle',
566 'Neevabot',
567 'NewsCred',
568 'newspaper',
569 'Nuclei',
570 'NukeScan',
571 'OnCrawl',
572 'Orbbot',
573 'PageFreezer',
574 'panscient.com',
575 'PetalBot',
576 'Pingdom.com',
577 'Pinterestbot',
578 'PiplBot',
579 'python-requests',
580 'Qwantify',
581 'Re-re Studio',
582 'Riddler',
583 'RocketValidator',
584 'rogerbot',
585 'RustBot',
586 'Safeassign',
587 'Scrapy',
588 'Screaming Frog',
589 'SeobilityBot',
590 'Search365bot',
591 'SearchBlox',
592 'searchunify',
593 'Seekport',
594 'SemanticScholarBot',
595 'SemrushBot',
596 'SEOkicks',
597 'seoscanners',
598 'serpstatbot',
599 'SessionCam',
600 'SeznamBot',
601 'Site24x7',
602 'SiteAuditBot',
603 'siteimprove',
604 'SiteLockSpider',
605 'SiteSucker',
606 'SkypeRoom',
607 'Slackbot',
608 'Slurp',
609 'Sogou web spider',
610 'special_archiver',
611 'SpiderLing',
612 'StatusCake',
613 'Swiftbot',
614 'Synack',
615 'Turnitin',
616 'trendictionbot',
617 'trendkite-akashic-crawler',
618 'UCBrowser',
619 'Uptime',
620 'UptimeRobot',
621 'UT-Dorkbot',
622 'weborama-fetcher',
623 'WhiteHat Security',
624 'Wget',
625 'WTWBot',
626 'www.loc.gov',
627 'Xenu Link Sleuth',
628 'Vagabondo',
629 'VelenPublicWebCrawler',
630 'Yeti',
631 'Veracode Security Scan',
632 'YandexBot',
633 'YandexImages',
634 'YisouSpider',
635 'Zabbix',
636 'ZoominfoBot',
637 'ZoomSpider',
638 );
639 }
640
641 /**
642 * Get all terms of a post.
643 *
644 * @since 4.0.0
645 *
646 * @param int|\WP_Post $post Post ID or WP_Post object.
647 * @return array Array of taxonomies.
648 */
649 public static function get_all_terms( $post ) {
650 $taxonomies = array();
651
652 if ( ! empty( $post ) ) {
653 $post = get_post( $post );
654 }
655
656 if ( ! empty( $post ) ) {
657 $taxonomies = get_object_taxonomies( $post );
658 }
659
660 $all_terms = array();
661
662 // Loop through the taxonomies and get the terms for the post for each taxonomy.
663 foreach ( $taxonomies as $taxonomy ) {
664 $terms = get_the_terms( $post, $taxonomy );
665 if ( $terms && ! is_wp_error( $terms ) ) {
666 $all_terms = array_merge( $all_terms, $terms );
667 }
668 }
669
670 return $all_terms;
671 }
672
673 /**
674 * Sanitize args.
675 *
676 * @since 4.1.1
677 *
678 * @param array $args Array of arguments.
679 * @return array Sanitized array of arguments.
680 */
681 public static function sanitize_args( $args ): array {
682 foreach ( $args as $key => $value ) {
683 if ( is_string( $value ) ) {
684 switch ( $key ) {
685 case 'class':
686 case 'className':
687 case 'extra_class':
688 $classes = explode( ' ', $value );
689 $sanitized_classes = array_map( 'sanitize_html_class', $classes );
690 $args[ $key ] = implode( ' ', $sanitized_classes );
691 break;
692 default:
693 $args[ $key ] = wp_kses_post( $value );
694 break;
695 }
696 }
697 }
698 return $args;
699 }
700 }
701